diff --git a/config.c b/config.c new file mode 100644 index 0000000..eaeb2a3 --- /dev/null +++ b/config.c @@ -0,0 +1,184 @@ +#include "model3.h" +#include "expat.h" + +enum +{ + ELEMENT_NONE = 1, + ELEMENT_CONFIG, + ELEMENT_ROMPATH, + ELEMENT_GAMELIST, + ELEMENT_BACKUPPATH, + ELEMENT_WIDTH, + ELEMENT_HEIGHT, + ELEMENT_FULLSCREEN, + ELEMENT_FPSLIMIT, + ELEMENT_STRETCH, +}; + +static STRING_ID element_id[] = +{ + { "config", ELEMENT_CONFIG }, + { "rom_path", ELEMENT_ROMPATH }, + { "gamelist", ELEMENT_GAMELIST }, + { "backup_path", ELEMENT_BACKUPPATH }, + { "width", ELEMENT_WIDTH }, + { "height", ELEMENT_HEIGHT }, + { "fullscreen", ELEMENT_FULLSCREEN }, + { "fps_limit", ELEMENT_FPSLIMIT }, + { "stretch", ELEMENT_STRETCH }, + { "", 0 }, +}; + +static STRING_ID boolean_id[] = +{ + { "yes", TRUE }, + { "no", FALSE }, + { "", 0 }, +}; + +static UINT8 *config_file; +static int current_element; + + +static void XMLCALL element_start(void *data, const char *el, const char **attr) +{ + int element = get_string_id(el, element_id); + + if (element < 0) + { + message(0, "Unknown element %s while parsing XML file\n", el); + } + else + { + current_element = element; + } +} + +static void XMLCALL element_end(void *data, const char *el) +{ + int element = get_string_id(el, element_id); + + if (element < 0) + { + message(0, "Unknown element %s while parsing XML\n", el); + } + else + { + switch (element) + { + case ELEMENT_CONFIG: + case ELEMENT_ROMPATH: + case ELEMENT_GAMELIST: + case ELEMENT_BACKUPPATH: + case ELEMENT_WIDTH: + case ELEMENT_HEIGHT: + case ELEMENT_FULLSCREEN: + case ELEMENT_FPSLIMIT: + case ELEMENT_STRETCH: + { + current_element = ELEMENT_NONE; + break; + } + } + } +} + +static void XMLCALL character_data(void *data, const char *s, int len) +{ + char temp[2000]; + memcpy(temp, s, len); + temp[len] = 0; + + switch (current_element) + { + case ELEMENT_ROMPATH: + { + strcpy(m3_config.rom_path, temp); + break; + } + case ELEMENT_GAMELIST: + { + strcpy(m3_config.rom_list, temp); + break; + } + case ELEMENT_BACKUPPATH: + { + strcpy(m3_config.backup_path, temp); + break; + } + case ELEMENT_WIDTH: + { + int width; + sscanf(temp, "%d", &width); + m3_config.width = width; + break; + } + case ELEMENT_HEIGHT: + { + int height; + sscanf(temp, "%d", &height); + m3_config.height = height; + break; + } + case ELEMENT_FULLSCREEN: + { + BOOL fullscreen = get_string_id(temp, boolean_id); + m3_config.fullscreen = fullscreen; + break; + } + case ELEMENT_FPSLIMIT: + { + BOOL fpslimit = get_string_id(temp, boolean_id); + m3_config.fps_limit = fpslimit; + break; + } + case ELEMENT_STRETCH: + { + BOOL stretch = get_string_id(temp, boolean_id); + m3_config.stretch = stretch; + break; + } + } +} + +BOOL parse_config(const char *config_name) +{ + XML_Parser parser; + + int length; + FILE *file; + + file = open_file(FILE_READ|FILE_BINARY, "%s", config_name); + if (file == NULL) + { + message(0, "Couldn't open %s", config_name); + return FALSE; + } + + length = (int)get_open_file_size(file); + + config_file = (UINT8*)malloc(length); + + if (!read_from_file(file, config_file, length)) + { + message(0, "I/O error while reading %s", config_name); + return FALSE; + } + + close_file(file); + + // parse the XML file + parser = XML_ParserCreate(NULL); + + XML_SetElementHandler(parser, element_start, element_end); + XML_SetCharacterDataHandler(parser, character_data); + + if (XML_Parse(parser, config_file, length, 1) != XML_STATUS_OK) + { + message(0, "Error while parsing the XML file %s", config_name); + return FALSE; + } + + XML_ParserFree(parser); + return TRUE; +} \ No newline at end of file diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..ed422ca --- /dev/null +++ b/config.xml @@ -0,0 +1,22 @@ + + + + + + + + + +]> + + + c:\devmame\roms + games.xml + c:\code\supermodel2\backup + 1280 + 1024 + yes + no + yes + \ No newline at end of file diff --git a/core/bridge.c b/core/bridge.c new file mode 100644 index 0000000..663c2f0 --- /dev/null +++ b/core/bridge.c @@ -0,0 +1,492 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * bridge.c + * + * MPC105 and MPC106 PCI bridge/memory controller emulation. + * + * Warning: Portability hazard. Code assumes it is running on a little endian + * machine. + * + * NOTE: Data written to the bridge controller is byte-reversed by the PPC. + * This is to make it little endian. + */ + +#include "model3.h" + +/******************************************************************/ +/* Internal Bridge State */ +/******************************************************************/ + +/* + * Macros for Register Access + * + * Assuming a little endian system (portability hazard!) + */ + +#define DWORD(addr) *((UINT32 *) ®s[addr]) +#define WORD(addr) *((UINT16 *) ®s[addr]) +#define BYTE(addr) regs[addr] + +/* + * Bridge State + * + * This code is intended for use on little-endian systems. Data from the + * registers should be returned as if a big endian read was performed (thus + * returning the little endian word 0x1057 as 0x5710.) + * + * The DWORD() and WORD() macros only work on little endian systems and are + * intended to set up the bridge state. Reads and writes using the handlers + * are done in big endian fashion by manually breaking down the data into + * bytes. + * + * To make this code fully portable, it would probably be enough to remove + * the DWORD() and WORD() macros. + */ + +static UINT8 regs[0x100]; +static UINT8 config_data[4]; // data for last CONFIG_ADDR command +static UINT32 reg_ptr; // current register address + +/******************************************************************/ +/* Interface */ +/******************************************************************/ + +/* + * Callback for Bus Commands + * + * Note that there are no callbacks for reads/writes to CONFIG_DATA yet as + * the need for them has not yet appeared. + */ + +static UINT32 (*config_addr_callback)(UINT32); + +/* + * UINT8 bridge_read_8(UINT32 addr); + * + * Reads directly from a register. The lower 8 bits of the address are the + * register to read from. This is intended for the MPC105 which can map its + * internal registers to 0xF8FFF0xx. + * + * Parameters: + * addr = Address (only lower 8 bits matter.) + * + * Returns: + * Data read. + */ + +UINT8 bridge_read_8(UINT32 addr) +{ + LOG("model3.log", "RB REG%02X\n", addr & 0xff); + + return BYTE(addr & 0xff); +} + +/* + * UINT16 bridge_read_16(UINT32 addr); + * + * Reads directly from a register. The lower 8 bits of the address are the + * register to read from. This is intended for the MPC105 which can map its + * internal registers to 0xF8FFF0xx. + * + * Bit 0 is masked off to ensure 16-bit alignment (I'm not sure how a real + * PCIBMC would handle this.) + * + * Parameters: + * addr = Address (only lower 8 bits matter.) + * + * Returns: + * Data read. + */ + +UINT16 bridge_read_16(UINT32 addr) +{ + LOG("model3.log", "RH REG%02X\n", addr & 0xff); + addr &= 0xfe; + return (BYTE(addr + 0) << 8) | BYTE(addr + 1); +} + +/* + * UINT32 bridge_read_32(UINT32 addr); + * + * Reads directly from a register. The lower 8 bits of the address are the + * register to read from. This is intended for the MPC105 which can map its + * internal registers to 0xF8FFF0xx. + * + * The lower 2 bits are masked off to ensure 32-bit alignment. + * + * Parameters: + * addr = Address (only lower 8 bits matter.) + * + * Returns: + * Data read. + */ + +UINT32 bridge_read_32(UINT32 addr) +{ + LOG("model3.log", "RW REG%02X\n", addr & 0xff); + addr &= 0xfc; + return (BYTE(addr + 0) << 24) | (BYTE(addr + 1) << 16) | + (BYTE(addr + 2) << 8) | BYTE(addr + 3); +} + +/* + * void bridge_write_8(UINT32 addr, UINT8 data); + * + * Writes directly to a register. Only the lower 8 bits matter. This is + * intended for the MPC105. + * + * Arguments: + * addr = Address (only lower 8 bits matter.) + * data = Data to write. + */ + +void bridge_write_8(UINT32 addr, UINT8 data) +{ + LOG("model3.log", "REG%02X=%02X\n", addr & 0xff, data); + BYTE(addr & 0xff) = data; +} + +/* + * void bridge_write_16(UINT32 addr, UINT16 data); + * + * Writes directly to a register. Only the lower 8 bits matter. This is + * intended for the MPC105. + * + * Bit 0 is masked off to ensure 16-bit alignment. + * + * Arguments: + * addr = Address (only lower 8 bits matter.) + * data = Data to write. + */ + +void bridge_write_16(UINT32 addr, UINT16 data) +{ + LOG("model3.log", "REG%02X=%02X%02X\n", addr & 0xff, data & 0xff, (data >> 8) & 0xff); + addr &= 0xfe; + BYTE(addr + 0) = data >> 8; + BYTE(addr + 1) = (UINT8) data; +} + +/* + * void bridge_write_32(UINT32 addr, UINT32 data); + * + * Writes directly to a register. Only the lower 8 bits matter. This is + * intended for the MPC105. + * + * The lower 2 bits are masked off to ensure 32-bit alignment. + * + * Arguments: + * addr = Address (only lower 8 bits matter.) + * data = Data to write. + */ + +void bridge_write_32(UINT32 addr, UINT32 data) +{ + LOG("model3.log", "REG%02X=%02X%02X%02X%02X\n", addr & 0xff, data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff, (data >> 24) & 0xff); + addr &= 0xfc; + BYTE(addr + 0) = data >> 24; + BYTE(addr + 1) = data >> 16; + BYTE(addr + 2) = data >> 8; + BYTE(addr + 3) = data; +} + +/* + * UINT8 bridge_read_config_data_8(UINT32 addr); + * + * Reads from CONFIG_DATA offset 0 to 3. Only the lower 2 bits of the address + * are checked to determine which byte to read. I'm not sure whether this is + * correct behavior (perhaps all byte offsets return the same data.) + * + * Parameters: + * addr = Address to read from (only lower 2 bits matter.) + * + * Returns: + * Data read. + */ + +UINT8 bridge_read_config_data_8(UINT32 addr) +{ + return config_data[addr & 3]; +// return BYTE(reg_ptr + (addr & 3)); +} + +/* + * UINT16 bridge_read_config_data_16(UINT32 addr); + * + * Reads from CONFIG_DATA offset 0 or 2. Only bit 1 of the address is checked + * to determine which word to read. I'm not sure whether this is correct + * behavior for word reads (both words might return the same data, for + * example.) + * + * Parameters: + * addr = Address to read from (only bit 1 matters.) + * + * Returns: + * Data read. + */ + +UINT16 bridge_read_config_data_16(UINT32 addr) +{ + return (config_data[(addr & 2) + 0] << 8) | config_data[(addr & 2) + 1]; +// return (BYTE(reg_ptr + (addr & 2) + 0) << 8) | +// BYTE(reg_ptr + (addr & 2) + 1); +} + +/* + * UINT32 bridge_read_config_data_32(UINT32 addr); + * + * Reads from CONFIG_DATA. The address argument is ignored because it is + * assumed that this function is only called for valid CONFIG_DATA addresses. + * + * Parameters: + * addr = Ignored. + * + * Returns: + * Data read. + */ + +UINT32 bridge_read_config_data_32(UINT32 addr) +{ + LOG("model3.log", "%08X: READ CONFIG DATA\n", ppc_get_pc()); + return (config_data[0] << 24) | (config_data[1] << 16) | + (config_data[2] << 8) | config_data[3]; +// return (BYTE(reg_ptr + 0) << 24) | (BYTE(reg_ptr + 1) << 16) | +// (BYTE(reg_ptr + 2) << 8) | BYTE(reg_ptr + 3); +} + +/* + * void bridge_write_config_addr_32(UINT32 addr, UINT32 data); + * + * Writes to CONFIG_ADDR. The address argument is ignored because it is + * assumed that this function is only called for valid CONFIG_ADDR addresses. + * + * Parameters: + * addr = Ignored. + * data = Data to write. + */ + +void bridge_write_config_addr_32(UINT32 addr, UINT32 data) +{ + UINT32 callback_data; + + /* + * I'm not sure how the bridge controller distinguishes between indirect + * register accesses and accesses which must be passed to some device on + * the PCI bus. + * + * Currently, I test to see if the command is of the format 0x800000XX, + * and if so, I return put register data in the return buffer + * (config_data), otherwise I invoke the callback. + */ + + +// LOG("model3.log", "CONFIG_ADDR=%02X%02X%02X%02X @ %08X", data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff, (data >> 24) & 0xff, PowerPC_ReadIntegerRegister(POWERPC_IREG_PC)); +// reg_ptr = data >> 24; // remember, data comes in little endian form +// // see page 3-15 of MPC106UM/D REV.1 + + if ((data & 0x00ffffff) == 0x00000080) // indirect register access (little endian data, see page 3-15 of MPC106UM/D REV.1) + { + reg_ptr = data >> 24; + config_data[0] = BYTE(reg_ptr + 0); + config_data[1] = BYTE(reg_ptr + 1); + config_data[2] = BYTE(reg_ptr + 2); + config_data[3] = BYTE(reg_ptr + 3); + } + else // pass it to the callback + { + if (config_addr_callback != NULL) + { + callback_data = config_addr_callback(BSWAP32(data)); + callback_data = BSWAP32(callback_data); // so we can return as little endian + } + else + callback_data = 0xFFFFFFFF; + + config_data[0] = callback_data >> 24; + config_data[1] = callback_data >> 16; + config_data[2] = callback_data >> 8; + config_data[3] = callback_data; + } +} + +/* + * void bridge_write_config_data_8(UINT32 addr, UINT8 data); + * + * Writes to CONFIG_DATA. The lower 2 bits determine which byte offset to + * write to. + * + * Parameters: + * addr = Address to write to (only lower 2 bits matter.) + * data = Data to write. + */ + +void bridge_write_config_data_8(UINT32 addr, UINT8 data) +{ +// LOG("model3.log", "CONFIG_DATA=%02X @ %08X", data, PowerPC_ReadIntegerRegister(POWERPC_IREG_PC)); + BYTE(reg_ptr + (addr & 3)) = data; + config_data[addr & 3] = data; +} + +/* + * void bridge_write_config_data_16(UINT32 addr, UINT16 data); + * + * Writes to CONFIG_DATA. Only bit 1 of the address is checked to determine + * which word to write to. + * + * Parameters: + * addr = Address to write to (only bit 1 matters.) + * data = Data to write. + */ + +void bridge_write_config_data_16(UINT32 addr, UINT16 data) +{ + BYTE(reg_ptr + (addr & 2) + 0) = data >> 8; + BYTE(reg_ptr + (addr & 2) + 1) = (UINT8) data; + config_data[(addr & 2) + 0] = data >> 8; + config_data[(addr & 2) + 1] = (UINT8) data; +// LOG("model3.log", "CONFIG_DATA=%04X @ %08X", WORD(reg_ptr), PowerPC_ReadIntegerRegister(POWERPC_IREG_PC)); +} + +/* + * void bridge_write_config_data_32(UINT32 addr, UINT32 data); + * + * Writes to CONFIG_DATA. The address argument is ignored because it is + * assumed that this function is only called for valid CONFIG_DATA addresses. + * + * Parameters: + * addr = Ignored. + * data = Data to write. + */ + +void bridge_write_config_data_32(UINT32 addr, UINT32 data) +{ + BYTE(reg_ptr + 0) = data >> 24; + BYTE(reg_ptr + 1) = data >> 16; + BYTE(reg_ptr + 2) = data >> 8; + BYTE(reg_ptr + 3) = data; + config_data[0] = data >> 24; + config_data[1] = data >> 16; + config_data[2] = data >> 8; + config_data[3] = data; +// LOG("model3.log", "CONFIG_DATA=%08X @ %08X", DWORD(reg_ptr), PowerPC_ReadIntegerRegister(POWERPC_IREG_PC)); +} + +/* + * void bridge_save_state(FILE *fp); + * + * Saves the bridge controller state by writing it out to a file. + * + * Parameters: + * fp = File to write to. + */ + +void bridge_save_state(FILE *fp) +{ + fwrite(regs, sizeof(UINT8), 0x100, fp); + fwrite(config_data, sizeof(UINT8), 4, fp); + fwrite(®_ptr, sizeof(UINT32), 1, fp); +} + +/* + * void bridge_load_state(FILE *fp); + * + * Loads the bridge controller state by reading it in from a file. + * + * Parameters: + * fp = File to read from. + */ + +void bridge_load_state(FILE *fp) +{ + fread(regs, sizeof(UINT8), 0x100, fp); + fread(config_data, sizeof(UINT8), 4, fp); + fread(®_ptr, sizeof(UINT32), 1, fp); +} + +/* + * void bridge_reset(INT device); + * + * Initializes the bridge controller's internal state. + * + * Memory control configuration 1 is to be set to 0xFFn20000, where n is data + * sampled from signals sent by hardware to the MPC105 (see the MPC105 + * manual.) For Model 3, I'm guessing that n == 0. + * + * Parameters: + * device = Device ID of the bridge to emulate (1 = MPC105, 2 = MPC106.) + * If it is not one of these values, behavior is undefined. + */ + +void bridge_reset(INT device) +{ + if (device == 1) + LOG("model3.log", "Using MPC105\n"); + else if (device == 2) + LOG("model3.log", "Using MPC106\n"); + else + LOG("model3.log", "ERROR: Unknown bridge controller device ID (%d)\n", device); + + memset(regs, 0, sizeof(UINT8) * 0x100); + memset(config_data, 0, sizeof(UINT8) * 4); + reg_ptr = 0; + + /* + * Set up common fields + */ + + WORD(0x00) = 0x1057; // vendor ID (Motorola) + WORD(0x02) = device; // device ID + WORD(0x04) = 0x0006; // PCI command + WORD(0x06) = 0x0080; // PCI status + BYTE(0x08) = 0x00; // revision ID (?) + BYTE(0x0b) = 0x06; // class code + DWORD(0xa8) = 0xff000010; // processor interface configuration 1 + DWORD(0xac) = 0x000c060c; // processor interface configuration 2 + BYTE(0xba) = 0x04; // alternate OS-visible parameters 1 + BYTE(0xc0) = 0x01; // error enabling 1 + DWORD(0xf0) = 0xff020000; // memory control configuration 1 + DWORD(0xf4) = 0x00000003; // memory control configuration 2 + DWORD(0xfc) = 0x00100000; // memory control configuration 4 + + /* + * Additional settings for MPC106 + */ + + if (device == 2) // MPC106 + { + BYTE(0x0c) = 0x08; // cache line size + BYTE(0x73) = 0xcd; // output driver control + DWORD(0xe0) = 0x0fff0042; // emulation support configuration 1 + DWORD(0xe8) = 0x00000020; // emulation support configuration 2 + } +} + +/* + * void bridge_init(UINT32 (*config_addr_callback_ptr)(UINT32)); + * + * Initializes the bridge controller by setting up the CONFIG_ADDR callback. + * bridge_reset() must still be used to put the controller in a usable (reset) + * state. + */ + +void bridge_init(UINT32 (*config_addr_callback_ptr)(UINT32)) +{ + config_addr_callback = config_addr_callback_ptr; +} diff --git a/core/bridge.h b/core/bridge.h new file mode 100644 index 0000000..0158df5 --- /dev/null +++ b/core/bridge.h @@ -0,0 +1,50 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * bridge.h + * + * MPC105 and MPC106 PCI bridge/memory controller header. + */ + +#ifndef INCLUDED_BRIDGE_H +#define INCLUDED_BRIDGE_H + +extern UINT8 bridge_read_8(UINT32); +extern UINT16 bridge_read_16(UINT32); +extern UINT32 bridge_read_32(UINT32); +extern void bridge_write_8(UINT32, UINT8); +extern void bridge_write_16(UINT32, UINT16); +extern void bridge_write_32(UINT32, UINT32); + +extern UINT8 bridge_read_config_data_8(UINT32); +extern UINT16 bridge_read_config_data_16(UINT32); +extern UINT32 bridge_read_config_data_32(UINT32); +extern void bridge_write_config_addr_32(UINT32, UINT32); +extern void bridge_write_config_data_8(UINT32, UINT8); +extern void bridge_write_config_data_16(UINT32, UINT16); +extern void bridge_write_config_data_32(UINT32, UINT32); + +extern void bridge_save_state(FILE *); +extern void bridge_load_state(FILE *); + +extern void bridge_reset(INT); +extern void bridge_init(UINT32 (*)(UINT32)); + +#endif // INCLUDED_BRIDGE_H + diff --git a/core/controls.c b/core/controls.c new file mode 100644 index 0000000..332da33 --- /dev/null +++ b/core/controls.c @@ -0,0 +1,292 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//TODO: In controls_write(): Is EEPROM only written when bank_select = 1? +// This makes little sense because banking affects reg 4 only, right? +// Also, should EEPROM reads only be performed when bank_select=1? + +/* + * controls.c + * + * Control emulation. + */ + +/* + * Lost World Gun Notes: + * --------------------- + * + * MCU Command Reg = 0x24 (byte) + * MCU Arg Reg = 0x28 (byte) + * + * Procedure for issuing commands: + * 1. Arg written first, then command. + * 2. Waits on reg 0x34 (see Stefano's post to model3 group for details.) + * 3. Reads a byte from 0x2C, then a byte from 0x30. + * + * Command 0x00: Set address (in arg reg.) + * Command 0x87: Read gun data. + * + * Virtual On 2 Notes: + * ------------------- + * + * Control Area Offset 0x08: Lever 1, LRUD??TS (T = Turbo, S = Shot Trigger) + * 0x0C: Lever 2 + * 0x18: Dipswitch, bits 7-0 = DS1-8 + * + * Dipswitch bit 0x20 (DS3) should be cleared otherwise some test is performed + * by Virtual On 2 at boot-up. + */ + +#include "model3.h" + +/******************************************************************/ +/* Privates */ +/******************************************************************/ + +/* + * Register Set + */ + +static UINT8 controls_reg[0x40]; +static UINT8 controls_reg_bank[2]; +static BOOL controls_bank_select; + +/* + * Gun Data + * + * Gun data is read by communicating with the MCU. An address is passed and + * some data is read back. The total number of data bytes that the MCU stores + * and can address is unknown, but I assume 16 (Stefano: Is this correct?) + * + * Here is how gun data is stored: + * + * Offset 0: player 1 gun X position, lower 8 bits + * 1: player 1 gun X position, upper 3 bits + * 2: player 1 gun Y position, lower 8 bits + * 3: player 1 gun Y position, upper 3 bits + * 4: player 2 gun X position, lower 8 bits + * 5: player 2 gun X position, upper 3 bits + * 6: player 2 gun Y position, lower 8 bits + * 7: player 2 gun Y position, upper 3 bits + * 8: bit 0 = player 1 gun position status (0=aquired 1=lost) + * bit 1 = player 2 gun position status (0=aquired 1=lost) + * + * I think Stefano also said that the X and Y may be reversed and that the gun + * coordinates are only 10 bits, not 11. + */ + +static UINT8 gun_data[16]; +static int gun_data_ptr; // which address within gun_data[] + + +static UINT8 analog_axis[8]; +static int analog_control = 0; // Currently used register + +/******************************************************************/ +/* Interface */ +/******************************************************************/ + +void controls_shutdown(void) +{ + +} + +void controls_init(void) +{ + +} + +void controls_reset(UINT32 flags) +{ + memset(controls_reg_bank, 0xFF, 2); + memset(controls_reg, 0xFF, 0x40); + memset(controls_reg, 0x00, 8); + +// controls_reg[0x18] = 0xDF; // clear bit 0x20 for Virtual On 2 + controls_reg[0x18] = 0xff; +} + +void controls_update(void) +{ + int i; + OSD_CONTROLS *c; + UINT gun_x, gun_y; + + c = osd_input_update_controls(); + + controls_reg_bank[0] = c->system_controls[0]; + controls_reg_bank[1] = c->system_controls[1]; + + controls_reg[0x08] = c->game_controls[0]; + controls_reg[0x0C] = c->game_controls[1]; + + /* + * TEMP: This should be changed so that only games with guns have this + * updated + */ + + /* + * Gun Coordinates: + * + * Coordinates returned by the MCU are sight position coordinates. The OSD + * input code returns coordinates in the range of (0,0)-(485,383). + * + * X adjustment: 400 must be added to the sight position in order to + * locate the gun at screen X = 0. + * + * Y adjustment: Sight coordinate 0 maps to screen coordinate 272. Sight + * coordinate 272 maps to screen coordinate 0. Sight coordinate 383 maps + * to -111. + */ + + gun_y = c->gun_y[0]; +// if (gun_y <= 272) +// gun_y = 272 - gun_y; +// else + gun_x = c->gun_x[0];// + 400; + gun_data[0] = gun_y & 0xFF; + gun_data[1] = (gun_y >> 8) & 7; + gun_data[2] = gun_x & 0xFF; + gun_data[3] = (gun_x >> 8) & 7; + + gun_y = c->gun_y[1]; + gun_x = c->gun_x[1] + 400; + gun_data[4] = gun_y & 0xFF; + gun_data[5] = (gun_y >> 8) & 7; + gun_data[6] = gun_x & 0xFF; + gun_data[7] = (gun_x >> 8) & 7; + + gun_data[8] = (!!c->gun_acquired[0]) | ((!!c->gun_acquired[1]) << 1); + + // Steering Wheel controls + // Register 0: Steering wheel, 0x80 is center + // Register 1: Acceleration, 0x00 - 0xFF + // Register 2: Brake, 0x00 - 0xFF + // Registers 3 - 7 are either unused or unknown + + for (i=0; i < 8; i++) + { + analog_axis[i] = c->analog_axis[i] & 0xff; + } +} + +/* + * void controls_save_state(FILE *fp); + * + * Saves the state of the controls to a file. + * + * Parameters: + * fp = File to save to. + */ + +void controls_save_state(FILE *fp) +{ + fwrite(controls_reg, sizeof(UINT8), 0x40, fp); + fwrite(controls_reg_bank, sizeof(UINT8), 2, fp); + fwrite(&controls_bank_select, sizeof(BOOL), 1, fp); +} + +/* + * void controls_load_state(FILE *fp); + * + * Loads the state of the controls from a file. + * + * Parameters: + * fp = File to load from. + */ + +void controls_load_state(FILE *fp) +{ + fread(controls_reg, sizeof(UINT8), 0x40, fp); + fread(controls_reg_bank, sizeof(UINT8), 2, fp); + fread(&controls_bank_select, sizeof(BOOL), 1, fp); +} + +/******************************************************************/ +/* Access */ +/******************************************************************/ + +/* these are only 8-bit wide, byte-aligned */ +/* additional data/address adjustement must be performed by the main handler */ + +UINT8 controls_read(UINT32 a) +{ + a &= 0x3F; + + switch (a) + { + case 0x4: + { + // should this only be done when bank_select = 1? + controls_reg_bank[1] &= ~0x20; // clear data bit before ORing it in + controls_reg_bank[1] |= (eeprom_read_bit() & 1) << 5; + return controls_reg_bank[controls_bank_select]; + } + case 0x3C: + { + // I don't know if the register to be read can be selected. + UINT8 analog_data = analog_axis[analog_control & 0x7]; + analog_control++; + + return analog_data; + } + } + +// LOG("model3.log", "CTRL %02X READ\n", a); + + return controls_reg[a]; +} + +void controls_write(UINT32 a, UINT8 d) +{ + a &= 0x3F; + controls_reg[a] = d; + + switch(a) + { + case 0x0: + { + controls_bank_select = d & 1; + // if(controls_bank_select == 1) + { + eeprom_set_clk((d & 0x80) ? 1 : 0); + eeprom_set_ce((d & 0x40) ? 1 : 0); + eeprom_set_data((d & 0x20) ? 1 : 0); + } + break; + } + case 0x24: // MCU command + { + switch (d) + { + case 0x00: // set address for gun data (it's already in the arg reg) + gun_data_ptr = controls_reg[0x28] & 0xF; + break; + + case 0x87: // read data back from gun + controls_reg[0x2c] = 0; // unused? + controls_reg[0x30] = gun_data[gun_data_ptr]; + break; + } + break; + } + } + +// LOG("model3.log", "CTRL%02X = %02X\n", a, d); +} + diff --git a/core/controls.h b/core/controls.h new file mode 100644 index 0000000..548386b --- /dev/null +++ b/core/controls.h @@ -0,0 +1,41 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * controls.h + * + * Controls header. + */ + +#ifndef INCLUDED_CONTROLS_H +#define INCLUDED_CONTROLS_H + +extern void controls_init(void); +extern void controls_shutdown(void); +extern void controls_reset(UINT32 flags); + +extern void controls_update(void); + +extern void controls_save_state(FILE *); +extern void controls_load_state(FILE *); + +extern UINT8 controls_read(UINT32 a); +extern void controls_write(UINT32 a, UINT8 d); + +#endif // INCLUDED_CONTROLS_H + diff --git a/core/dma.c b/core/dma.c new file mode 100644 index 0000000..d5d0e63 --- /dev/null +++ b/core/dma.c @@ -0,0 +1,371 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * dma.c + * + * Step 2.0+ DMA device emulation. We're unsure whether or not this is a SCSI + * controller; it appears to only be used for its DMA capabilities and is + * thought to be a Sega custom part. + */ + +/* + * 0xC2000000 32-bit -W DMA Source + * 0xC2000004 32-bit -W DMA Destination + * 0xC2000008 32-bit -W DMA Length (in words) + * 0xC200000C 8-bit RW DMA Status? AxxxxxxB (A and B must be cleared) + * 0xC200000D 8-bit -W DMA Control? xxxxxxx? (bit0 clears C200000C bit0) + * 0xC200000E 8-bit -W DMA Config? + * 0xC2000010 32-bit -W DMA Command? (Written, result appears at 0x14) + * 0xC2000014 32-bit R- DMA Command Result + */ + +#include "model3.h" + +/******************************************************************/ +/* Private Variables */ +/******************************************************************/ + +/* + * Registers + */ + +static UINT8 dma_regs[0x20]; + +/* + * Read/Write Handlers + * + * These are used as an interface to the rest of the system. + */ + +static UINT32 (*read_32)(UINT32); +static void (*write_32)(UINT32, UINT32); + +/******************************************************************/ +/* DMA Transfer */ +/******************************************************************/ + +/* + * do_dma(): + * + * Performs a DMA transfer. The paramaters are expected to be in the + * appropriate registers. + */ + +#ifdef _PROFILE_ +extern UINT is_dma; +#endif + +static void do_dma(void) +{ + UINT32 src, dest, len; + + PROFILE_SECT_ENTRY("dma"); + + #ifdef _PROFILE_ + is_dma = 1; + #endif + + src = *(UINT32 *) &dma_regs[0x00]; + dest = *(UINT32 *) &dma_regs[0x04]; + len = (*(UINT32 *) &dma_regs[0x08]) * 4; + + LOG("model3.log", "DMA %08X -> %08X, %X\n", src, dest, len); + + if ((dma_regs[0x0E] & 0x80)) // swap words + { + /*while (len) + { + write_32(dest, BSWAP32(read_32(src))); + src += 4; + dest += 4; + len -= 4; + }*/ + + model3_dma_transfer(src, dest, len, TRUE); + } + else + { + /*while (len) + { + write_32(dest, read_32(src)); + src += 4; + dest += 4; + len -= 4; + }*/ + + model3_dma_transfer(src, dest, len, FALSE); + } + + #ifdef _PROFILE_ + is_dma = 0; + #endif + + *(UINT32 *) &dma_regs[0x08] = 0; // not sure if this is necessary + + /* + * An IRQ may be generated by the DMA device after a copy is performed (or + * at some other time.) + * + * Evidence for this is in Harley Davidson's ISR. The subroutine at 0x8ABE8 + * appears to check the status register bit 0 and performs a copy if it is + * set (after first clearing it.) + * + * Here, bit 0 is set, an IRQ is triggered, and the code will clear bit 0 by + * writing a 1 to bit 0 of DMA reg 0xD. + */ + + dma_regs[0x0C] |= 1; // this bit may indicate IRQ raised + ppc_set_irq_line(1); + + PROFILE_SECT_EXIT("dma"); +} + +/******************************************************************/ +/* Interface */ +/******************************************************************/ + +/* + * void dma_shutdown(void); + * + * Shuts down the DMA device emulation. + */ + +void dma_shutdown(void) +{ +} + +/* + * void dma_init(UINT32 (*read32)(UINT32), void (*write32)(UINT32, UINT32)); + * + * Initializes the DMA device emulation by setting the memory access handlers. + * + * Parameters: + * read32 = Handler to use for 32-bit reads. + * write32 = Handler to use for 32-bit writes. + */ + +void dma_init(UINT32 (*read32)(UINT32), void (*write32)(UINT32, UINT32)) +{ + read_32 = read32; + write_32 = write32; +} + +/* + * void dma_reset(void); + * + * Resets the DMA device. + */ + +void dma_reset(void) +{ + memset(dma_regs, 0, 0x20); +} + +/* + * void dma_save_state(FILE *fp); + * + * Saves the state of the DMA device (for Step 2.0 or higher games only) to a + * file. + * + * Parameters: + * fp = File to save to. + */ + +void dma_save_state(FILE *fp) +{ + if (m3_config.step < 0x20) + return; + fwrite(dma_regs, sizeof(UINT8), 0x20, fp); +} + +/* + * void dma_load_state(FILE *fp); + * + * Loads the state of the DMA device (for Step 2.0 or higher games only) from + * a file. + * + * Parameters: + * fp = File to load from. + */ + +void dma_load_state(FILE *fp) +{ + if (m3_config.step < 0x20) + return; + fread(dma_regs, sizeof(UINT8), 0x20, fp); +} + +/******************************************************************/ +/* Access */ +/******************************************************************/ + +/* + * UINT8 dma_read_8(UINT32 a); + * + * Reads a byte from the DMA device. + * + * Parameters: + * a = Address. + * + * Returns: + * Data read. + */ + +UINT8 dma_read_8(UINT32 a) +{ +// message(0, "%08X: Unknown DMA read8, %08X", PPC_PC, a); + + return dma_regs[a & 0x1F]; +} + +/* + * UINT32 dma_read_32(UINT32 a); + * + * Reads a word from the DMA device. + * + * Parameters: + * a = Address. + * + * Returns: + * Data read. + */ + +UINT32 dma_read_32(UINT32 a) +{ +// message(0, "%08X: Unknown DMA read32, %08X", PPC_PC, a); + + return BSWAP32(*(UINT32 *) &dma_regs[a & 0x1F]); +} + +/* + * void dma_write_8(UINT32 a, UINT8 d); + * + * Writes a byte to the DMA device. + * + * Parameters: + * a = Address. + * d = Data to write. + */ + +void dma_write_8(UINT32 a, UINT8 d) +{ + dma_regs[a & 0x1F] = d; + + switch (a & 0x1F) + { + case 0xD: + if ((d & 1)) // clear status bit 0 + dma_regs[0xC] &= ~1; + break; + default: + LOG("model3.log", "%08X: Unknown DMA write8, %08X = %02X\n", ppc_get_pc(), a, d); + break; + } +} + +/* + * void dma_write_16(UINT32 a, UINT16 d); + * + * Writes a half-word to the DMA device. + * + * Parameters: + * a = Address. + * d = Data to write. + */ + +void dma_write_16(UINT32 a, UINT16 d) +{ + switch (a & 0x1F) + { + case 0x14: + message(0, "%08X = %04X", a, d); + LOG("model3.log", "DMA %08X = %04X\n", a, d); + break; + default: + error("unknown DMA write: %08X = %04X", a, d); + break; + } +} + +/* + * void dma_write_32(UINT32 a, UINT32 d); + * + * Writes a word to the DMA device. + * + * Parameters: + * a = Address. + * d = Data to write. + */ + +void dma_write_32(UINT32 a, UINT32 d) +{ + d = BSWAP32(d); // this is a little endian device, only bswap here once + + *(UINT32 *) &dma_regs[a & 0x1F] = d; + + switch (a & 0x1F) + { + case 0x00: // DMA Source +// message(0, "DMA SRC = %08X", d); + return; + case 0x04: // DMA Destination +// message(0, "DMA DST = %08X", d); + return; + case 0x08: // DMA Length +// message(0, "DMA LEN = %X", d * 4); + do_dma(); + return; + case 0x10: // DMA Command + + /* + * Virtual On 2 has been observed to write commands to reg 0x10 and + * then expects particular values back from 0x14. + * + * Command 0x80000000 is a little strange. It is issued and twice and + * each time, a bit of the result is expected to be different. This + * is crudely simulated by flipping a bit. + * + * Virtua Striker 2 '99 does something similar, except that it writes + * commands 0x80000000, 0x80000004, ... 0x80000020. + */ + + if (d & 0x20000000) + *(UINT32 *) &dma_regs[0x14] = 0x178611db; //0x16C311DB; // PCI Vendor and Device ID + else if ((d & 0x80000000)) + *(UINT32 *) &dma_regs[0x14] = r3d_read_32((d & 0xFF) | 0x84000000); +#if 0 + else if (d == 0x80000000) + { + static UINT32 result = 0x02000000; + result ^= 0x02000000; + *(UINT32 *) &dma_regs[0x14] = result; + } +#endif + else + message(0, "%08X: Unknown DMA command, %08X", ppc_get_pc(), d); + + return; + case 0x14: + *(UINT32 *) &dma_regs[0x14] = 0xffffffff; + return; + } + + message(0, "%08X: Unknown DMA write32, %08X = %08X", ppc_get_pc(), a, d); +} + diff --git a/core/dma.h b/core/dma.h new file mode 100644 index 0000000..3beee44 --- /dev/null +++ b/core/dma.h @@ -0,0 +1,42 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * dma.h + * + * Step 2.0+ DMA device header. + */ + +#ifndef INCLUDED_DMA_H +#define INCLUDED_DMA_H + +extern void dma_init(UINT32 (*)(UINT32), void (*)(UINT32, UINT32)); +extern void dma_shutdown(void); +extern void dma_reset(void); + +extern void dma_save_state(FILE *); +extern void dma_load_state(FILE *); + +extern UINT8 dma_read_8(UINT32 a); +extern UINT32 dma_read_32(UINT32 a); +extern void dma_write_8(UINT32 a, UINT8 d); +extern void dma_write_16(UINT32 a, UINT16 d); +extern void dma_write_32(UINT32 a, UINT32 d); + +#endif // INCLUDED_DMA_H + diff --git a/core/dsb1.c b/core/dsb1.c new file mode 100644 index 0000000..99c8ea9 --- /dev/null +++ b/core/dsb1.c @@ -0,0 +1,71 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * dsb1.c + * + * DSB1 Digital Sound Board emulation. + */ + +#include "model3.h" + +void dsb1_init(void) +{ + +} + +void dsb1_reset(void) +{ + +} + +void dsb1_shutdown(void) +{ + +} + +/* + * void dsb1_save_state(FILE *fp); + * + * Saves the state of the DSB1 (for games which have it) to a file. + * + * Parameters: + * fp = File to save to. + */ + +void dsb1_save_state(FILE *fp) +{ + if (!(m3_config.flags & GAME_OWN_DSB1)) + return; +} + +/* + * void dsb1_load_state(FILE *fp); + * + * Loads the state of the DSB1 (for games which have it) from a file. + * + * Parameters: + * fp = File to load from. + */ + +void dsb1_load_state(FILE *fp) +{ + if (!(m3_config.flags & GAME_OWN_DSB1)) + return; +} + diff --git a/core/dsb1.h b/core/dsb1.h new file mode 100644 index 0000000..19f86ac --- /dev/null +++ b/core/dsb1.h @@ -0,0 +1,36 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * dsb1.h + * + * DSB1 Digital Sound Board header. + */ + +#ifndef _DSB1_H_ +#define _DSB1_H_ + +extern void dsb1_init(void); +extern void dsb1_shutdown(void); +extern void dsb1_reset(void); + +extern void dsb1_save_state(FILE *); +extern void dsb1_load_state(FILE *); + +#endif /* _DSB1_H_ */ + diff --git a/core/eeprom.c b/core/eeprom.c new file mode 100644 index 0000000..a57431b --- /dev/null +++ b/core/eeprom.c @@ -0,0 +1,391 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * eeprom.c + * + * 93C46 EEPROM emulation courtesy of R. Belmont. + * + * NOTE: Save state code assumes enums will be the same across all compilers + * and systems. The eeprom_store[] array is endian-dependent. + */ + +/*************************************************************************** + eeprom.cpp - handles a serial eeprom with 64 16-bit addresses and 4-bit commands + as seen in st-v, system 32, many konami boards, etc. + + originally written: May 20, 2000 by R. Belmont for "sim" + update: Jan 27, 2001 (RB): implemented "erase" opcode, + made opcode fetch check for start bit + like the real chip. + Mar 26, 2001 (FF): added get_image to access the eeprom + Jan 28, 2004 (Bart): Interface changes to work with Supermodel. + Crudely simulated busy status by setting olatch to 0 in + ES_DESELECT. + ***************************************************************************/ + +#include +#include +#include +#include "model3.h" + +#define LOG_EEPROM 0 // log channel for EEPROM + +static INT32 eeprom_state; + +static UINT16 eeprom_store[64]; // 6 address bits times 16 bits per location +static UINT8 opcode; // current opcode +static UINT8 adr; // current address in eeprom_store +static UINT8 curbit; // current bit # in read/write/addr fetch operation +static UINT8 lastclk; // last clock +static UINT8 dlatch; // input data latch +static UINT8 olatch; // output data latch +static UINT16 curio; + +// states for the eeprom state machine +enum +{ + ES_DESELECT = 0,// chip select not asserted + ES_ASSERT, // chip select asserted, waiting for opcode + ES_OPCODE0, // got opcode bit 0 + ES_OPCODE1, // got opcode bit 1 + ES_OPCODE2, // got opcode bit 2 + ES_ADRFETCH, // fetching address + ES_READBITS, // reading bits, 1 out every time clock goes high + ES_WRITEBITS, // writing bits, 1 in every time clock goes high + ES_WAITING // done with read/write, waiting for deselect to finalize +}; + +/* + * UINT8 eeprom_read_bit(void); + * + * Reads a data bit from the EEPROM. + * + * Returns: + * Latched data bit. + */ + +UINT8 eeprom_read_bit(void) +{ + return olatch; +} + +/* + * void eeprom_set_ce(UINT8 ce); + * + * Passes the status of the chip enable. + * + * Parameters: + * ce = Chip enable bit (must be 0 or 1.) + */ + +void eeprom_set_ce(UINT8 ce) +{ + // chip enable + if (ce) + { + // asserting CE - if deselected, + // select. if selected already, + // ignore + if (eeprom_state == ES_DESELECT) + { +// printf("EEPROM: asserting chip enable\n"); + eeprom_state = ES_ASSERT; + opcode = 0; + } + } + else + { + // deasserting CE +// printf("EEPROM: deasserting chip enable\n"); + eeprom_state = ES_DESELECT; + } +} + +/* + * void eeprom_set_data(UINT8 data); + * + * Sets the data bit latch. + * + * Parameters: + * data = Data bit (must be 0 or 1.) + */ + +void eeprom_set_data(UINT8 data) +{ + dlatch = (data&0x01); // latch the data +} + +/* + * void eeprom_set_clk(UINT8 clk); + * + * Sets the clock pin. + * + * Parameters: + * clk = Clock (zero or non-zero.) + */ + +void eeprom_set_clk(UINT8 clk) +{ + // things only happen on the rising edge of the clock + if ((!lastclk) && (clk)) + { + switch (eeprom_state) + { + case ES_DESELECT: + olatch = 0; + break; + + case ES_ASSERT: + case ES_OPCODE0: + case ES_OPCODE1: + case ES_OPCODE2: + // first command bit must be a "1" in the real device + if ((eeprom_state == ES_OPCODE0) && (dlatch == 0)) + { +#if LOG_EEPROM + LOG("model3.log", "EEPROM: waiting for start bit\n"); +#endif + olatch = 1; // assert READY + } + else + { + opcode <<= 1; + opcode |= dlatch; +#if LOG_EEPROM + LOG("model3.log", "EEPROM: opcode fetch state, currently %x\n", opcode); +#endif + eeprom_state++; + } + + curbit = 0; + adr = 0; + break; + + case ES_ADRFETCH: // fetch address + adr <<= 1; + adr |= dlatch; +#if LOG_EEPROM + LOG("model3.log", "EEPROM: address fetch state, cur addr = %x\n", adr); +#endif + curbit++; + if (curbit == 6) + { + switch (opcode) + { + case 4: // write enable - go back to accept a new opcode immediately + opcode = 0; + eeprom_state = ES_ASSERT; + //printf("EEPROM: write enable\n"); + break; + + case 5: // write + eeprom_state = ES_WRITEBITS; + olatch = 0; // indicate not ready yet + curbit = 0; + curio = 0; + break; + + case 6: // read + eeprom_state = ES_READBITS; + curbit = 0; + curio = eeprom_store[adr]; + //printf("EEPROM: read %04x from address %d\n", curio, adr); + break; + + case 7: // erase location to ffff and assert READY + eeprom_store[adr] = 0xffff; + olatch = 1; + eeprom_state = ES_WAITING; + //printf("EEPROM: erase at address %d\n", adr); + break; + + default: +#if LOG_EEPROM + LOG("model3.log", "Unknown EEPROM opcode %d!\n", opcode); +#endif + eeprom_state = ES_WAITING; + olatch = 1; // assert READY anyway + break; + } + } + break; + + case ES_READBITS: + olatch = ((curio & 0x8000)>>15); + curio <<= 1; + + curbit++; + if (curbit == 16) + { + eeprom_state = ES_WAITING; + } + break; + + case ES_WRITEBITS: + curio <<= 1; + curio |= dlatch; + + curbit++; + if (curbit == 16) + { + olatch = 1; // indicate success + eeprom_store[adr] = curio; +#if LOG_EEPROM + LOG("model3.log", "EEPROM: Wrote %04x to address %d\n", curio, adr); +#endif + eeprom_state = ES_WAITING; + } + break; + + case ES_WAITING: + break; + } + } + + lastclk = clk; +} + +/* + * void eeprom_save_state(FILE *fp); + * + * Save the EEPROM state. + * + * Parameters: + * fp = File to save to. + */ + +void eeprom_save_state(FILE *fp) +{ + if (fp != NULL) + { + fwrite(&eeprom_state, sizeof(INT32), 1, fp); + fwrite(eeprom_store, sizeof(UINT16), 64, fp); + fwrite(&opcode, sizeof(UINT8), 1, fp); + fwrite(&adr, sizeof(UINT8), 1, fp); + fwrite(&curbit, sizeof(UINT8), 1, fp); + fwrite(&lastclk, sizeof(UINT8), 1, fp); + fwrite(&dlatch, sizeof(UINT8), 1, fp); + fwrite(&olatch, sizeof(UINT8), 1, fp); + fwrite(&curio, sizeof(UINT16), 1, fp); + } +} + +/* + * void eeprom_load_state(FILE *fp); + * + * Load the EEPROM state. + * + * Parameters: + * fp = File to load from. + */ + +void eeprom_load_state(FILE *fp) +{ + if (fp != NULL) + { + fread(&eeprom_state, sizeof(INT32), 1, fp); + fread(eeprom_store, sizeof(UINT16), 64, fp); + fread(&opcode, sizeof(UINT8), 1, fp); + fread(&adr, sizeof(UINT8), 1, fp); + fread(&curbit, sizeof(UINT8), 1, fp); + fread(&lastclk, sizeof(UINT8), 1, fp); + fread(&dlatch, sizeof(UINT8), 1, fp); + fread(&olatch, sizeof(UINT8), 1, fp); + fread(&curio, sizeof(UINT16), 1, fp); + } +} + +/* + * INT eeprom_load(CHAR *fname); + * + * Loads data from the file specified. If the file does not exist, the EEPROM + * data is initialized with all 1's. + * + * Parameters: + * fname = File name. + * + * Returns: + * MODEL3_OKAY = Success. + * MODEL3_ERROR = Error reading from the file. + */ + +INT eeprom_load(CHAR *fname) +{ + FILE *fp; + INT error_code = MODEL3_ERROR; + + message(0, "loading EEPROM from %s", fname); + + if ((fp = fopen(fname, "rb")) != NULL) + { + error_code = fread(eeprom_store, sizeof(UINT16), 64, fp); + fclose(fp); + + if (error_code == 64) + return MODEL3_OKAY; + } + + memset(eeprom_store, 0xFF, sizeof(UINT16) * 64); + + return error_code; +} + +/* + * INT eeprom_save(CHAR *fname); + * + * Writes out the EEPROM data to the specified file. + * + * Parameters: + * fname = File name to write. + * + * Returns: + * MODEL3_OKAY = Success. + * MODEL3_ERROR = Unable to open or write file. + */ + +INT eeprom_save(CHAR *fname) +{ + FILE *fp; + INT i = MODEL3_ERROR; + + message(0, "saving EEPROM to %s", fname); + + if ((fp = fopen(fname, "wb")) != NULL) + { + i = fwrite(eeprom_store, sizeof(UINT16), 64, fp); + fclose(fp); + + if (i == 64) + return MODEL3_OKAY; + } + + return i; +} + +/* + * void eeprom_reset(void); + * + * Resets the EEPROM emulation. + */ + +void eeprom_reset(void) +{ + eeprom_state = ES_DESELECT; + lastclk = 0; +} diff --git a/core/eeprom.h b/core/eeprom.h new file mode 100644 index 0000000..2a0ea05 --- /dev/null +++ b/core/eeprom.h @@ -0,0 +1,41 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * eeprom.h + * + * 93C46 EEPROM emulation header. + */ + +#ifndef INCLUDED_EEPROM_H +#define INCLUDED_EEPROM_H + +extern UINT8 eeprom_read_bit(void); +extern void eeprom_set_clk(UINT8 clk); +extern void eeprom_set_ce(UINT8 ce); +extern void eeprom_set_data(UINT8 data); + +extern void eeprom_save_state(FILE *); +extern void eeprom_load_state(FILE *); + +extern INT eeprom_load(CHAR *); +extern INT eeprom_save(CHAR *); + +extern void eeprom_reset(void); + +#endif // INCLUDED_EEPROM_H diff --git a/core/model3.c b/core/model3.c new file mode 100644 index 0000000..629e5da --- /dev/null +++ b/core/model3.c @@ -0,0 +1,2391 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * model3.c + * + * Model 3 system emulation. + * + * Memory Regions: + * + * All Model 3 memory regions are allocated and freed in this file. + * However, RAM and backup RAM are the only RAM regions directly accessed + * here. Everything else is passed to its respective subsystem. This + * localizes all memory allocation to this single file and enforces + * separation between the different modules. + * + * VF3 SCSI Note: + * + * In VF3, the SCSI appears at 0xC0000000. We've observed that at this + * address on Step 1.5 there is some sort of 68K device. Oh, well :P + * + * TODO List: + * + * - von2_rev5_4g has what appears to be a spinning cursor effect when + * booting but sometimes the characters look invalid. Need to take a + * closer look... + * + * - Investigate backup RAM. Sega Rally 2 seems to want 256KB when R3D + * read commands are emulated with the DMA. This is emulated by making + * the Step 2.X backup RAM region (starting at 0xFE0C0000) 256KB in size + * but it is still kept as 128KB for Step 1.X. + * + * - Do more error checking when parsing games.ini (num_patches > 64, + * etc.) + */ + +#include "model3.h" + +#define PROFILE_MEMORY_OPERATIONS 0 + +/******************************************************************/ +/* Global Configuration Structure */ +/******************************************************************/ + +CONFIG m3_config; + +/******************************************************************/ +/* Internal Variables */ +/******************************************************************/ + +/* + * Model 3 Memory Regions + */ + +UINT8 *ram = NULL; // PowerPC RAM +static UINT8 *bram = NULL; // backup RAM +static UINT8 *sram = NULL; // sound RAM +static UINT8 *vram = NULL; // tile generator VRAM (scroll RAM) +static UINT8 *culling_ram_8e = NULL; // Real3D culling RAM +static UINT8 *culling_ram_8c = NULL; // Real3D culling RAM +static UINT8 *polygon_ram = NULL; // Real3D polygon RAM +static UINT8 *texture_ram = NULL; // Real3D texture RAM +static UINT8 *crom = NULL; // CROM (all CROM memory is allocated here) +static UINT8 *crom_bank; // points to current 8MB CROM bank +static UINT8 *vrom = NULL; // video ROM +static UINT8 *sprog = NULL; +static UINT8 *srom = NULL; // sound ROM +static UINT8 *dsbprog = NULL; +static UINT8 *dsbrom = NULL; // DSB1 ROM + +static UINT8 *crom0 = NULL; +static UINT8 *crom1 = NULL; +static UINT8 *crom2 = NULL; +static UINT8 *crom3 = NULL; + +/* + * Other + */ + +static UINT ppc_freq; // PowerPC clock speed + +/* + * Function Prototypes (for forward references) + */ + +static UINT8 model3_sys_read_8(UINT32); +static UINT32 model3_sys_read_32(UINT32); +static void model3_sys_write_8(UINT32, UINT8); +static void model3_sys_write_32(UINT32, UINT32); +static UINT8 model3_midi_read(UINT32); +static void model3_midi_write(UINT32, UINT8); + +/******************************************************************/ +/* Output */ +/******************************************************************/ + +void message(int flags, char * fmt, ...) +{ + /* a simple _message_ to the user. */ + /* must be used for unharmful warnings too. */ + /* do not pause the emulator to prompt the user! */ + /* using a cyclic buffer to output a few lines of */ + /* timed messages to the screen would be best. */ + + /* integrable in the renderer. */ + + /* flags are provided for future expansion (i.e. for */ + /* different text colors/priorities) */ + + va_list vl; + char string[512]; + + va_start(vl, fmt); + vsprintf(string, fmt, vl); + va_end(vl); + + LOG("model3.log", "%s\n", string); + + puts(string); + +// osd_message(flags, string); +} + +void error(char * fmt, ...) +{ + /* you can bypass this calling directly osd_error, but i */ + /* prefer it this way. :) */ + + char string[256] = ""; + va_list vl; + + va_start(vl, fmt); + vsprintf(string, fmt, vl); + va_end(vl); + + osd_error(string); +} + +void _log(char * path, char * fmt, ...) +{ + /* logs to a file. */ + + /* NOTE: "log" conflicts with math.h, so i'm using _log instead. */ + /* it doesn't make much difference since we're gonna log stuff */ + /* with the LOG macro. */ + + if(m3_config.log_enabled) + { + char string[1024]; + va_list vl; + FILE * file; + + file = fopen(path, "ab"); + if(file != NULL) + { + va_start(vl, fmt); + vsprintf(string, fmt, vl); + va_end(vl); + fprintf(file, string); + fclose(file); + } + } +} + +void _log_init(char * path) +{ + /* resets a file contents. */ + /* since i'm opening the log file with fopen(path, "ab") every */ + /* time (not to lost the file in the case of a crash), it's */ + /* necessary to reset it on startup. */ + + FILE * file; + + file = fopen(path, "wb"); + if(file != NULL) + fclose(file); +} + + + + +#if PROFILE_MEMORY_OPERATIONS +#define PROFILE_MEMORY_OP(x, y, z) profile_memory_operation(x, y, z) +#else +#define PROFILE_MEMORY_OP(x, y, z) +#endif + + +static UINT64 num_mem_ops = 0; +static UINT64 num_read_ops = 0; +static UINT64 num_write_ops = 0; + +static UINT64 num_read8_ops = 0; +static UINT64 num_read16_ops = 0; +static UINT64 num_read32_ops = 0; +static UINT64 num_read64_ops = 0; +static UINT64 num_write8_ops = 0; +static UINT64 num_write16_ops = 0; +static UINT64 num_write32_ops = 0; +static UINT64 num_write64_ops = 0; + +static UINT64 num_ram_reads = 0; +static UINT64 num_ram_writes = 0; +static UINT64 num_crom_reads = 0; +static UINT64 num_bankcrom_reads = 0; +static UINT64 num_other_reads = 0; +static UINT64 num_other_writes = 0; + +static int profile_memory_operation(int size, int write, UINT32 address) +{ + num_mem_ops++; + + if (write) + { + num_write_ops++; + + switch (size) + { + case 8: num_write8_ops++; break; + case 16: num_write16_ops++; break; + case 32: num_write32_ops++; break; + case 64: num_write64_ops++; break; + } + + if (address < 0x800000) + { + num_ram_writes++; + } + else + { + num_other_writes++; + } + } + else + { + num_read_ops++; + + switch (size) + { + case 8: num_read8_ops++; break; + case 16: num_read16_ops++; break; + case 32: num_read32_ops++; break; + case 64: num_read64_ops++; break; + } + + if (address < 0x800000) + { + num_ram_reads++; + } + else if (address >= 0xff000000 && address < 0xff800000) + { + num_bankcrom_reads++; + } + else if (address >= 0xff800000) + { + num_crom_reads++; + } + else + { + num_other_reads++; + } + } +} + +static void print_memory_profile_stats(void) +{ + printf("Total mem ops: %lld\n", num_mem_ops); + printf(" Reads: %lld, %f%%\n", num_read_ops, ((double)num_read_ops / (double)num_mem_ops) * 100.0f); + printf(" Writes: %lld, %f%%\n", num_write_ops, ((double)num_write_ops / (double)num_mem_ops) * 100.0f); + printf("\n"); + printf(" Read8: %lld, %f%%\n", num_read8_ops, ((double)num_read8_ops / (double)num_read_ops) * 100.0f); + printf(" Read16: %lld, %f%%\n", num_read16_ops, ((double)num_read16_ops / (double)num_read_ops) * 100.0f); + printf(" Read32: %lld, %f%%\n", num_read32_ops, ((double)num_read32_ops / (double)num_read_ops) * 100.0f); + printf(" Read64: %lld, %f%%\n", num_read64_ops, ((double)num_read64_ops / (double)num_read_ops) * 100.0f); + printf(" Write8: %lld, %f%%\n", num_write8_ops, ((double)num_write8_ops / (double)num_write_ops) * 100.0f); + printf(" Write16: %lld, %f%%\n", num_write16_ops, ((double)num_write16_ops / (double)num_write_ops) * 100.0f); + printf(" Write32: %lld, %f%%\n", num_write32_ops, ((double)num_write32_ops / (double)num_write_ops) * 100.0f); + printf(" Write64: %lld, %f%%\n", num_write64_ops, ((double)num_write64_ops / (double)num_write_ops) * 100.0f); + printf("\n"); + printf(" RAM reads: %lld, %f%%\n", num_ram_reads, ((double)num_ram_reads / (double)num_read_ops) * 100.0f); + printf(" RAM writes: %lld, %f%%\n", num_ram_writes, ((double)num_ram_writes / (double)num_write_ops) * 100.0f); + printf(" BANK CROM reads: %lld, %f%%\n", num_bankcrom_reads, ((double)num_bankcrom_reads / (double)num_read_ops) * 100.0f); + printf(" CROM reads: %lld, %f%%\n", num_crom_reads, ((double)num_crom_reads / (double)num_read_ops) * 100.0f); + printf(" Other reads: %lld, %f%%\n", num_other_reads, ((double)num_other_reads / (double)num_read_ops) * 100.0f); + printf(" Other writes: %lld, %f%%\n", num_other_writes, ((double)num_other_writes / (double)num_write_ops) * 100.0f); +} + + +static int prot_data_ptr = 0; + +static UINT16 vs299_prot_data[] = +{ + 0xc800, 0x4a20, 0x5041, 0x4e41, 0x4920, 0x4154, 0x594c, 0x4220, + 0x4152, 0x4953, 0x204c, 0x5241, 0x4547, 0x544e, 0x4e49, 0x2041, + 0x4547, 0x4d52, 0x4e41, 0x2059, 0x4e45, 0x4c47, 0x4e41, 0x2044, + 0x454e, 0x4854, 0x5245, 0x414c, 0x444e, 0x2053, 0x5246, 0x4e41, + 0x4543, 0x4320, 0x4c4f, 0x4d4f, 0x4942, 0x2041, 0x4150, 0x4152, + 0x5547, 0x5941, 0x4220, 0x4c55, 0x4147, 0x4952, 0x2041, 0x5053, + 0x4941, 0x204e, 0x5243, 0x414f, 0x4954, 0x2041, 0x4542, 0x474c, + 0x5549, 0x204d, 0x494e, 0x4547, 0x4952, 0x2041, 0x4153, 0x4455, + 0x2049, 0x4f4b, 0x4552, 0x2041, 0x4544, 0x4d4e, 0x5241, 0x204b, + 0x4f52, 0x414d, 0x494e, 0x2041, 0x4353, 0x544f, 0x414c, 0x444e, + 0x5520, 0x4153, 0x5320, 0x554f, 0x4854, 0x4641, 0x4952, 0x4143, + 0x4d20, 0x5845, 0x4349, 0x204f, 0x5559, 0x4f47, 0x4c53, 0x5641, + 0x4149, 0x4620, 0x5f43, 0x4553, 0x4147 +}; + +static UINT16 swt_prot_data[] = +{ + 0xffff, + 0x3d3d, 0x3d3d, 0x203d, 0x5453, 0x5241, 0x5720, 0x5241, 0x2053, + 0x3d3d, 0x3d3d, 0x0a3d, 0x6f43, 0x7970, 0x6952, 0x6867, 0x2074, + 0x4553, 0x4147, 0x4520, 0x746e, 0x7265, 0x7270, 0x7369, 0x7365, + 0x202c, 0x744c, 0x2e64, 0x410a, 0x756d, 0x6573, 0x656d, 0x746e, + 0x5220, 0x4426, 0x4420, 0x7065, 0x2e74, 0x2320, 0x3231, 0x4b0a, + 0x7461, 0x7573, 0x6179, 0x7573, 0x4120, 0x646e, 0x206f, 0x2026, + 0x614b, 0x6f79, 0x6f6b, 0x5920, 0x6d61, 0x6d61, 0x746f, 0x0a6f, +}; + +static UINT16 fvipers2_prot_data[] = +{ + 0x2a2a, + 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x202a, 0x5b5b, + 0x4620, 0x6769, 0x7468, 0x6e69, 0x2067, 0x6956, 0x6570, 0x7372, + 0x3220, 0x5d20, 0x205d, 0x6e69, 0x3c20, 0x4d3c, 0x444f, 0x4c45, + 0x332d, 0x3e3e, 0x4320, 0x706f, 0x7279, 0x6769, 0x7468, 0x2820, + 0x2943, 0x3931, 0x3839, 0x5320, 0x4745, 0x2041, 0x6e45, 0x6574, + 0x7072, 0x6972, 0x6573, 0x2c73, 0x544c, 0x2e44, 0x2020, 0x4120, + 0x6c6c, 0x7220, 0x6769, 0x7468, 0x7220, 0x7365, 0x7265, 0x6576, + 0x2e64, 0x2a20, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, 0x2a2a, +}; + +static UINT16 spikeout_prot_data[] = +{ + 0x0000, + 0x4f4d, 0x4544, 0x2d4c, 0x2033, 0x7953, 0x7473, 0x6d65, 0x5020, + 0x6f72, 0x7267, 0x6d61, 0x4320, 0x706f, 0x7279, 0x6769, 0x7468, + 0x2820, 0x2943, 0x3120, 0x3939, 0x2035, 0x4553, 0x4147, 0x4520, + 0x746e, 0x7265, 0x7270, 0x7369, 0x7365, 0x4c2c, 0x4454, 0x202e, + 0x6c41, 0x206c, 0x6972, 0x6867, 0x2074, 0x6572, 0x6573, 0x7672, + 0x6465, 0x202e, 0x2020, 0x0020 +}; + +static UINT16 eca_prot_data[] = +{ + 0x0000, + 0x2d2f, 0x202d, 0x4d45, 0x5245, 0x4547, 0x434e, 0x2059, 0x4143, + 0x4c4c, 0x4120, 0x424d, 0x4c55, 0x4e41, 0x4543, 0x2d20, 0x0a2d, + 0x6f43, 0x7970, 0x6952, 0x6867, 0x2074, 0x4553, 0x4147, 0x4520, + 0x746e, 0x7265, 0x7270, 0x7369, 0x7365, 0x202c, 0x744c, 0x2e64, + 0x530a, 0x666f, 0x7774, 0x7261, 0x2065, 0x2652, 0x2044, 0x6544, + 0x7470, 0x202e, 0x3123, 0x660a, 0x726f, 0x7420, 0x7365, 0x0a74, +}; + +/******************************************************************/ +/* PPC Access */ +/******************************************************************/ + +UINT8 m3_ppc_read_8(UINT32 a) +{ + PROFILE_MEMORY_OP(8, 0, a); + + /* + * RAM and ROM tested for first for speed + */ + + if (a <= 0x007FFFFF) + { + return ram[a]; + } + else if (a >= 0xFF000000 && a <= 0xFF7FFFFF) + { + return crom_bank[a - 0xFF000000]; + } + else if (a >= 0xFF800000 && a <= 0xFFFFFFFF) + { + return crom[a - 0xFF800000]; + } + + switch (a >> 28) + { + case 0xc: + { + if (a >= 0xC0000000 && a <= 0xC00000FF) // 53C810 SCSI (Step 1.0) + { + if (m3_config.step == 0x10) + return scsi_read_8(a); + } + else if (a >= 0xC1000000 && a <= 0xC10000FF) // 53C810 SCSI + { + return scsi_read_8(a); + } + else if (a >= 0xC2000000 && a <= 0xC200001F) // DMA device + { + return dma_read_8(a); + } + + break; + } + + case 0xf: + { + if ((a >= 0xF0040000 && a <= 0xF004003F) || + (a >= 0xFE040000 && a <= 0xFE04003F)) // control area + { + return controls_read(a); + } + else if ((a >= 0xF0080000 && a <= 0xF00800FF) || + (a >= 0xFE080000 && a <= 0xFE0800FF)) // MIDI? + { + return model3_midi_read(a); + } + else if ((a >= 0xF0100000 && a <= 0xF010003F) || + (a >= 0xFE100000 && a <= 0xFE10003F)) // system control + { + return model3_sys_read_8(a); + } + else if ((a >= 0xF0140000 && a <= 0xF014003F) || + (a >= 0xFE140000 && a <= 0xFE14003F)) // RTC + { + return rtc_read_8(a); + } + else if (a >= 0xFEE00000 && a <= 0xFEEFFFFF) // MPC106 CONFIG_DATA + { + return bridge_read_config_data_8(a); + } + else if (a >= 0xF9000000 && a <= 0xF90000FF) // 53C810 SCSI + { + return scsi_read_8(a); + } + + + switch (a) + { + case 0xF118000C: // TODO: 8-bit tilegen access is unimplemented + { + return 0xff; + } + } + } + break; + } + + error("%08X: unknown read8, %08X\n", ppc_get_pc(), a); + return 0xff; +} + +UINT16 m3_ppc_read_16(UINT32 a) +{ + PROFILE_MEMORY_OP(16, 0, a); + + /* + * RAM and ROM tested for first for speed + */ + + if (a <= 0x007FFFFF) + { + return BSWAP16(*(UINT16 *) &ram[a]); + } + else if (a >= 0xFF000000 && a <= 0xFF7FFFFF) + { + return BSWAP16(*(UINT16 *) &crom_bank[a - 0xFF000000]); + } + else if (a >= 0xFF800000 && a <= 0xFFFFFFFF) + { + return BSWAP16(*(UINT16 *) &crom[a - 0xFF800000]); + } + + switch (a >> 28) + { + case 0xf: + { + if ((a >= 0xF00C0000 && a <= 0xF00DFFFF) || + (a >= 0xFE0C0000 && a <= 0xFE0FFFFF)) // backup RAM + { + return BSWAP16(*(UINT16 *) &bram[a & 0x3FFFF]); + } + else if( a >= 0xF1000000 && a <= 0xF111FFFF ) // tilegen VRAM + { + return tilegen_vram_read_16(a); + } + + switch (a) + { + case 0xF0C00CFC: // MPC105/106 CONFIG_DATA (Sega Bass Fishing) + case 0xF0C00CFE: + case 0xFEE00CFC: // MPC105/106 CONFIG_DATA + case 0xFEE00CFE: + { + return bridge_read_config_data_16(a); + } + } + } + break; + } + + error("%08X: unknown read16, %08X\n", ppc_get_pc(), a); + return 0xffff; +} + +UINT32 m3_ppc_read_32(UINT32 a) +{ + PROFILE_MEMORY_OP(32, 0, a); + + /* + * RAM and ROM tested for first for speed + */ + + if (a <= 0x007FFFFF) + { + return BSWAP32(*(UINT32 *) &ram[a]); + } + else if (a >= 0xFF000000 && a <= 0xFF7FFFFF) + { + return BSWAP32(*(UINT32 *) &crom_bank[a - 0xFF000000]); + } + else if (a >= 0xFF800000 && a <= 0xFFFFFFFF) + { + return BSWAP32(*(UINT32 *) &crom[a - 0xFF800000]); + } + + switch (a >> 28) + { + case 0x8: + { + return r3d_read_32(a); + } + + case 0xc: + { + if (a >= 0xC0000000 && a <= 0xC00000FF) // 53C810 SCSI (Step 1.0) + { + if (m3_config.step == 0x10) + return scsi_read_32(a); + } + else if (a >= 0xC1000000 && a <= 0xC10000FF) // 53C810 SCSI + { + return scsi_read_32(a); + } + else if (a >= 0xC2000000 && a <= 0xC200001F) // DMA device + { + return dma_read_32(a); + } + + switch (a) + { + case 0xC0000000: + { + //return _C0000000; + return 0; + } + case 0xC0010110: // LeMans24 + case 0xC0010114: // LeMans24 + case 0xC0020000: // Network? Sega Rally 2 at 0x79268 + { + return 0; + } + } + break; + } + + case 0xf: + { + if ((a >= 0xF0040000 && a <= 0xF004003F) || // control area + (a >= 0xFE040000 && a <= 0xFE04003F)) + { + return (controls_read(a + 0) << 24) | + (controls_read(a + 1) << 16) | + (controls_read(a + 2) << 8) | + (controls_read(a + 3) << 0); + } + else if (a >= 0xF0080000 && a <= 0xF00800FF) // MIDI? + { + return 0xFFFFFFFF; + } + else if ((a >= 0xF00C0000 && a <= 0xF00DFFFF) || + (a >= 0xFE0C0000 && a <= 0xFE0FFFFF)) // backup RAM + { + return BSWAP32(*(UINT32 *) &bram[a & 0x3FFFF]); + } + else if ((a >= 0xF0100000 && a <= 0xF010003F) || + (a >= 0xFE100000 && a <= 0xFE10003F)) // system control + { + return model3_sys_read_32(a); + } + else if ((a >= 0xF0140000 && a <= 0xF014003F) || + (a >= 0xFE140000 && a <= 0xFE14003F)) // RTC + { + return rtc_read_32(a); + } + else if (a >= 0xF1000000 && a <= 0xF111FFFF) // tile generator VRAM + { + return tilegen_vram_read_32(a); + } + else if (a >= 0xF1180000 && a <= 0xF11800FF) // tile generator regs + { + return tilegen_read_32(a); + } + else if (a >= 0xFEE00000 && a <= 0xFEEFFFFF) // MPC106 CONFIG_DATA + { + return bridge_read_config_data_32(a); + } + else if (a >= 0xF9000000 && a <= 0xF90000FF) // 53C810 SCSI + { + return scsi_read_32(a); + } + + switch (a) + { + case 0xF0C00CFC: // MPC105/106 CONFIG_DATA + { + return bridge_read_config_data_32(a); + } + + case 0xFE180000: // ? SWT + { + return 0; + } + + case 0xFE1A0000: // ? Virtual On 2 -- important to return 0 + { + return 0; // see my message on 13May ("VROM Port?") + } + + case 0xFE1A001C: + { + if (_stricmp(m3_config.game_id, "vs299") == 0 || + _stricmp(m3_config.game_id, "vs2v991") == 0) + { + UINT32 data = (UINT32)(vs299_prot_data[prot_data_ptr++]) << 16; + if (prot_data_ptr > 0x65) + { + prot_data_ptr = 0; + } + return data; + } + else if (_stricmp(m3_config.game_id, "swtrilgy") == 0 || + _stricmp(m3_config.game_id, "swtrilga") == 0) + { + UINT32 data = (UINT32)swt_prot_data[prot_data_ptr++] << 16; + if (prot_data_ptr > 0x38) + { + prot_data_ptr = 0; + } + return data; + } + else if (_stricmp(m3_config.game_id, "fvipers2") == 0) + { + UINT32 data = (UINT32)fvipers2_prot_data[prot_data_ptr++] << 16; + if (prot_data_ptr >= 0x41) + { + prot_data_ptr = 0; + } + return data; + } + else if (_stricmp(m3_config.game_id, "spikeout") == 0 || + _stricmp(m3_config.game_id, "spikeofe") == 0) + { + UINT32 data = (UINT32)spikeout_prot_data[prot_data_ptr++] << 16; + if (prot_data_ptr >= 0x55) + { + prot_data_ptr = 0; + } + return data; + } + else if (_stricmp(m3_config.game_id, "eca") == 0) + { + UINT32 data = (UINT32)(eca_prot_data[prot_data_ptr++]) << 16; + if (prot_data_ptr >= 0x31) + { + prot_data_ptr = 0; + } + + return data; + } + else + { + return 0xffffffff; + } + } + } + } + break; + } + + error("%08X: unknown read32, %08X\n", ppc_get_pc(), a); + return 0xFFFFFFFF; +} + +UINT64 m3_ppc_read_64(UINT32 a) +{ + UINT64 d; + PROFILE_MEMORY_OP(64, 0, a); + + d = m3_ppc_read_32(a + 0); + d <<= 32; + d |= m3_ppc_read_32(a + 4); + + return d; +} + +void m3_ppc_write_8(UINT32 a, UINT8 d) +{ + PROFILE_MEMORY_OP(8, 1, a); + + /* + * RAM tested for first for speed + */ + + if (a <= 0x007FFFFF) + { + ram[a] = d; + return; + } + + switch (a >> 28) + { + case 0xC: + + if (a >= 0xC0000000 && a <= 0xC00000FF) // 53C810 SCSI + { + if (m3_config.step == 0x10) + { + scsi_write_8(a, d); + return; + } + } + else if (a >= 0xC2000000 && a <= 0xC200001F) // DMA device + { + dma_write_8(a, d); + return; + } + else if (a >= 0xc3800000 && a <= 0xc380001f) // Daytona 2 protection/bank-switch + { + crom_bank = &crom[0x800000 + (((~d) & 0xf) * 0x800000)]; + return; + } + + switch (a) + { + case 0xC0010180: // ? Lost World, PC = 0x11B510 + case 0xC1000014: // ? Lost World, PC = 0xFF80098C + case 0xC1000038: // ? Sega Rally, PC = 0x7B1F0 + case 0xC1000039: // ? Lost World, PC = 0x118BD8 + case 0xC100003B: // Scud Race Plus + return; + } + + break; + + case 0xF: + + if ((a >= 0xF0040000 && a <= 0xF004003F) || // control area + (a >= 0xFE040000 && a <= 0xFE04003F)) + { + controls_write(a, d); + return; + } + else if ((a >= 0xF0080000 && a <= 0xF00800FF) || + (a >= 0xFE080000 && a <= 0xFE0800FF)) // MIDI? + { + model3_midi_write(a, d); + return; + } + else if ((a >= 0xF0100000 && a <= 0xF010003F) || + (a >= 0xFE100000 && a <= 0xFE10003F)) // system control + { + model3_sys_write_8(a, d); + return; + } + else if ((a >= 0xF0140000 && a <= 0xF014003F) || + (a >= 0xFE140000 && a <= 0xFE14003F)) // RTC? (Sega Rally 2) + { + rtc_write(a, d); + return; + } + else if (a >= 0xF8FFF000 && a <= 0xF8FFF0FF) // MPC105 regs + { + bridge_write_8(a, d); + return; + } + else if (a >= 0xFEE00000 && a <= 0xFEEFFFFF) // MPC106 CONFIG_DATA + { + bridge_write_config_data_8(a, d); + return; + } + else if (a >= 0xF9000000 && a <= 0xF90000FF) // 53C810 SCSI + { + scsi_write_8(a, d); + return; + } + + switch (a) + { + case 0xFE000004: // Sega Rally 2 + case 0xF118000C: // Harley Davidson (tilegen 8-bit) + + return; + + } + + break; + } + + error("%08X: unknown write8, %08X = %02X\n", ppc_get_pc(), a, d); +} + +void m3_ppc_write_16(UINT32 a, UINT16 d) +{ + PROFILE_MEMORY_OP(16, 1, a); + + /* + * RAM tested for first for speed + */ + + if (a <= 0x007FFFFF) + { + *(UINT16 *) &ram[a] = BSWAP16(d); + return; + } + + switch (a >> 28) + { + case 0xC: + + if (a >= 0xC2000000 && a <= 0xC200001F) // DMA device + { + dma_write_16(a, d); + return; + } + + break; + + case 0xF: + + if (a >= 0xF8FFF000 && a <= 0xF8FFF0FF) // MPC105 regs + { + bridge_write_16(a, d); + return; + } + else if (a >= 0xFEE00000 && a <= 0xFEEFFFFF) // MPC106 CONFIG_DATA + { + bridge_write_config_data_16(a, d); + return; + } + else if ((a >= 0xF00C0000 && a <= 0xF00DFFFF) || + (a >= 0xFE0C0000 && a <= 0xFE0FFFFF)) // backup RAM + { + *(UINT16 *) &bram[a & 0x3FFFF] = BSWAP16(d); + return; + } + + switch (a) + { + case 0xF0C00CFC: // MPC105/106 CONFIG_DATA + bridge_write_config_data_16(a, d); + return; + } + + break; + } + + error("%08X: unknown write16, %08X = %04X\n", ppc_get_pc(), a, d); +} + +void m3_ppc_write_32(UINT32 a, UINT32 d) +{ + PROFILE_MEMORY_OP(32, 1, a); + + /* + * RAM tested for first for speed + */ + + if (a <= 0x007FFFFF) + { + *(UINT32 *) &ram[a] = BSWAP32(d); + return; + } + + switch (a >> 28) + { + case 0x8: + case 0x9: + { + r3d_write_32(a, d); // Real3D memory regions + return; + } + + case 0xc: + { + if (a >= 0xC0000000 && a <= 0xC00000FF) // 53C810 SCSI + { + if (m3_config.step == 0x10) + { + scsi_write_32(a, d); + return; + } + } + else if (a >= 0xC1000000 && a <= 0xC10000FF) // 53C810 SCSI + { + scsi_write_32(a, d); + return; + } + else if (a >= 0xC2000000 && a <= 0xC200001F) // DMA device + { + dma_write_32(a, d); + return; + } + + switch (a) + { + case 0xC0000000: // latched value + { + //_C0000000 = d; + return; + } + case 0xC0010180: // Network ? Scud Race at 0xB2A4 + { + return; + } + case 0xC0020000: // Network? Sega Rally 2 at 0x79264 + { + return; + } + } + break; + } + + case 0xf: + { + if ((a >= 0xF0040000 && a <= 0xF004003F) || // control area + (a >= 0xFE040000 && a <= 0xFE04003F)) + { + controls_write(a + 0, (UINT8) (d >> 24)); + controls_write(a + 1, (UINT8) (d >> 16)); + controls_write(a + 2, (UINT8) (d >> 8)); + controls_write(a + 3, (UINT8) (d >> 0)); + return; + } + else if ((a >= 0xF00C0000 && a <= 0xF00DFFFF) || + (a >= 0xFE0C0000 && a <= 0xFE0FFFFF)) // backup RAM + { + *(UINT32 *) &bram[a & 0x3FFFF] = BSWAP32(d); + return; + } + else if ((a >= 0xF0100000 && a <= 0xF010003F) || + (a >= 0xFE100000 && a <= 0xFE10003F)) // system control + { + model3_sys_write_32(a, d); + return; + } + else if ((a >= 0xF0140000 && a <= 0xF014003F) || + (a >= 0xFE140000 && a <= 0xFE14003F)) // RTC + { + rtc_write(a, (UINT8) (d >> 24)); + return; + } + else if (a >= 0xFE180000 && a <= 0xFE19FFFF) // ? + { + // LOG("model3.log", "security %08X = %04X\n", a, d >> 16); + return; + } + else if (a >= 0xF1000000 && a <= 0xF111FFFF) // tile generator VRAM + { + tilegen_vram_write_32(a, d); + return; + } + else if (a >= 0xF1180000 && a <= 0xF11800FF) // tile generator regs + { + tilegen_write_32(a, d); + return; + } + else if (a >= 0xF8FFF000 && a <= 0xF8FFF0FF) // MPC105 regs + { + bridge_write_32(a, d); + return; + } + else if (a >= 0xFEC00000 && a <= 0xFEDFFFFF) // MPC106 CONFIG_ADDR + { + bridge_write_config_addr_32(a, d); + return; + } + else if (a >= 0xFEE00000 && a <= 0xFEEFFFFF) // MPC106 CONFIG_DATA + { + bridge_write_config_data_32(a, d); + return; + } + else if (a >= 0xF9000000 && a <= 0xF90000FF) // 53C810 SCSI + { + scsi_write_32(a, d); + return; + } + + switch (a) + { + case 0xF0800CF8: // MPC105/106 CONFIG_ADDR + { + bridge_write_config_addr_32(a, d); + return; + } + case 0xF0C00CFC: // MPC105/106 CONFIG_DATA + { + bridge_write_config_data_32(a, d); + return; + } + case 0xFE1A0000: // ? Virtual On 2 + { + return; + } + case 0xFE1A0010: + { + return; + } + case 0xFE1A0014: + { + LOG("model3.log", "security reset = %08X\n", d); + return; + } + case 0xFE1A0018: + { + LOG("model3.log", "security key = %08X\n", d); + return; + } + } + } + break; + } + + error("%08X: unknown write32, %08X = %08X\n", ppc_get_pc(), a, d); +} + +void m3_ppc_write_64(UINT32 a, UINT64 d) +{ + PROFILE_MEMORY_OP(64, 1, a); + + m3_ppc_write_32(a + 0, (UINT32) (d >> 32)); + m3_ppc_write_32(a + 4, (UINT32) d); +} + + + +void model3_dma_transfer(UINT32 src, UINT32 dst, int length, BOOL swap_words) +{ + UINT32 *s; + if (src < 0x800000) + { + s = (UINT32 *)&ram[src]; + } + else if (src >= 0xff000000 && src < 0xff800000) + { + s = (UINT32 *)&crom_bank[src - 0xff000000]; + } + else if (src >= 0xff800000) + { + s = (UINT32 *)&crom[src - 0xff800000]; + } + else + { + error("model3_dma_transfer: source = %08X\n", src); + } + + switch ((dst >> 24) & 0xff) + { + case 0x8c: r3d_dma_culling_ram_8c(s, dst, length, swap_words); break; + case 0x8e: r3d_dma_culling_ram_8e(s, dst, length, swap_words); break; + case 0x94: r3d_dma_texture_ram(s, dst, length, swap_words); break; + case 0x98: r3d_dma_polygon_ram(s, dst, length, swap_words); break; + + default: + { + int i; + if (swap_words) + { + for (i=0; i < length; i+=4) + { + UINT32 d = *s++; + r3d_write_32(dst, d); + dst += 4; + } + } + else + { + for (i=0; i < length; i+=4) + { + UINT32 d = BSWAP32(*s++); + r3d_write_32(dst, d); + dst += 4; + } + } + break; + } + } +} + + + +/******************************************************************/ +/* System Control (0xFx100000 - 0xFx10003F) */ +/******************************************************************/ + +static UINT8 model3_irq_state = 0; // 0xF0100018 +static UINT8 model3_irq_enable = 0; // 0xF0100014 +static UINT8 crom_bank_reg; + +/* + * void m3_add_irq(UINT8 mask); + * + * Raises an IRQ (sets its status bit.) + * + * Parameters: + * mask = Mask corresponding to upper 8 bits of IRQ status register. + */ + +void model3_add_irq(UINT8 mask) +{ + model3_irq_state |= mask; +} + +/* + * void m3_remove_irq(UINT8 mask); + * + * Removes an IRQ (lowers its status bit.) + * + * Parameters: + * mask = Mask corresponding to upper 8 bits of IRQ status register. + */ + +void model3_remove_irq(UINT8 mask) +{ + model3_irq_state &= ~mask; +} + +static UINT32 model3_ppc_irq_callback(void) +{ + return(0); /* no other IRQs in the queue */ +} + +/* + * m3_set_crom_bank(): + * + * Sets the CROM bank register and maps the requested 8MB CROM bank in. + * Note that all CROMs are stored in the same 72MB buffer which is why 8MB is + * added (to skip over CROM0-3.) + */ + +static void model3_set_crom_bank(UINT8 d) +{ + crom_bank_reg = d; + crom_bank = &crom[0x800000 + ((~d) & 0xf) * 0x800000]; + + LOG("model3.log", "CROM bank = %02X\n", d); +} + +static UINT8 model3_sys_read_8(UINT32 a) +{ + static UINT8 x = 0x20; + + switch(a & 0xFF) + { + case 0x08: // CROM bank + { + return crom_bank_reg; + } + + case 0x10: // JTAG TAP + { + return ((tap_read() & 1) << 5); + } + + case 0x14: // IRQ enable + { + return model3_irq_enable; + } + + case 0x18: // IRQ status + { + return model3_irq_state; + } + + case 0x1C: // ? + { + // LOG("model3.log", "%08X: unknown sys read8, %08X\n", PPC_PC, a); + return 0xff; + } + } + + LOG("model3.log", "%08X: unknown sys read8, %08X\n", ppc_get_pc(), a); + message(0, "%08X: unknown sys read8, %08X", ppc_get_pc(), a); + return 0xff; +} + +static UINT32 model3_sys_read_32(UINT32 a) +{ + switch(a & 0xFF) + { + case 0x10: // JTAG TAP + { + return ((tap_read() & 1) << (5+24)); + } + + case 0x14: // IRQ enable + { + return (model3_irq_enable << 24); + } + + case 0x18: // IRQ status + { + return (model3_irq_state << 24); + } + } + + LOG("model3.log", "%08X: unknown sys read32, %08X\n", ppc_get_pc(), a); + message(0, "%08X: unknown sys read32, %08X", ppc_get_pc(), a); + return 0xffffffff; +} + +static void model3_sys_write_8(UINT32 a, UINT8 d) +{ + switch(a & 0xff) + { + case 0x00: // ? + { + LOG("model3.log", "%08X: unknown sys write8, %08X = %02X\n", ppc_get_pc(), a, d); + return; + } + + case 0x04: // ? + { + LOG("model3.log", "%08X: unknown sys write8, %08X = %02X\n", ppc_get_pc(), a, d); + return; + } + + case 0x08: // CROM bank + { + model3_set_crom_bank(d); + return; + } + + case 0x0c: // JTAG TAP + { + tap_write( + (d >> 6) & 1, // TCK + (d >> 2) & 1, // TMS + (d >> 5) & 1, // TDI + (d >> 7) & 1 // TRST + ); + return; + } + + case 0x14: // IRQ enable + { + model3_irq_enable = d; + return; + } + + case 0x1c: // ? this may be the LED control + { + // LOG("model3.log", "%08X: unknown sys write8, %08X = %02X\n", PPC_PC, a, d); + return; + } + + case 0x3c: // ? + { + LOG("model3.log", "%08X: unknown sys write8, %08X = %02X\n", ppc_get_pc(), a, d); + return; + } + } + + LOG("model3.log", "%08X: unknown sys write8, %08X = %02X\n", ppc_get_pc(), a, d); + message(0, "%08X: unknown sys write8, %08X = %02X", ppc_get_pc(), a, d); +} + +static void model3_sys_write_32(UINT32 a, UINT32 d) +{ + switch(a & 0xff) + { + case 0x0c: // JTAG TAP + { + tap_write( + (d >> (6+24)) & 1, + (d >> (2+24)) & 1, + (d >> (5+24)) & 1, + (d >> (7+24)) & 1 + ); + return; + } + + case 0x14: // IRQ mask + { + model3_irq_enable = (d >> 24); + return; + } + + case 0x1c: // ? + { + LOG("model3.log", "%08X: unknown sys write32, %08X = %08X\n", ppc_get_pc(), a, d); + return; + } + } + + LOG("model3.log", "%08X: unknown sys write32, %08X = %08X\n", ppc_get_pc(), a, d); + message(0, "%08X: unknown sys write32, %08X = %08X", ppc_get_pc(), a, d); +} + +static UINT8 model3_midi_read(UINT32 a) +{ + /* 0xFx0800xx */ + + return 0xFF; +// return(0); +} + +static void model3_midi_write(UINT32 a, UINT8 d) +{ + /* 0xFx0800xx */ + + //message(0, "%08X: MIDI write, %08X = %02X", ppc_get_pc(), a, d); + + if ((a & 0xf) == 0) + { + model3_remove_irq(0x40); + } +} + +/******************************************************************/ +/* PCI Command Callback */ +/******************************************************************/ + +static UINT32 pci_command_callback(UINT32 cmd) +{ + int pci_device = (cmd >> 11) & 0x1f; + int pci_reg = (cmd >> 2) & 0x3f; + + switch (cmd) + { + case 0x80006800: // reg 0 of PCI config header + { + if (m3_config.step <= 0x15) + return 0x16C311DB; // 0x11DB = PCI vendor ID (Sega), 0x16C3 = device ID + else + return 0x178611DB; + } + + case 0x80007000: // VF3 + case 0x80007002: // Sega Rally 2 + { + return 0x00011000; + } + + case 0x80008000: // Daytona 2, protection/bank-switch + { + return 0x182711db; + } + + default: + { + LOG("PCI callback: %08X (device %d, reg %d)\n", cmd, pci_device, pci_reg); + break; + } + } + + //LOG("model3.log", "%08X (%08X): PCI command issued: %08X\n", PPC_PC, PPC_LR, cmd); + return 0; +} + +/******************************************************************/ +/* Load/Save Stuff */ +/******************************************************************/ + +static void word_swap(UINT8 *src, INT size) +{ + while (size -= 4) + { + *((UINT32 *) src) = BSWAP32(*((UINT32 *) src)); + src += sizeof(UINT32); + } +} + +void model3_load_eeprom(void) +{ + char string[512]; + INT i; + + sprintf( string, "%s/%s.epr", m3_config.backup_path, m3_config.game_id ); + + if((i = eeprom_load(string)) != MODEL3_OKAY) + { + message(0, "Can't load EEPROM from %s (%d)", string, i); + } +} + +void model3_save_eeprom(void) +{ + char string[512]; + INT i; + + sprintf( string, "%s/%s.epr", m3_config.backup_path, m3_config.game_id ); + + if((i = eeprom_save(string)) != MODEL3_OKAY) + { + message(0, "Can't save EEPROM to %s (%d)", string, i); + } +} + +void model3_load_bram(void) +{ + char string[512]; + + sprintf( string, "%s/%s.brm", m3_config.backup_path, m3_config.game_id ); + + if(load_file(string, bram, 256*1024)) + { + message(0, "Can't load Backup RAM from file, creating a new file."); + memset(bram, 0xFF, 256*1024); + save_file(string, bram, 256*1024, 0); + } +} + +void model3_save_bram(void) +{ + char string[512]; + sprintf( string, "%s/%s.brm", m3_config.backup_path, m3_config.game_id ); + + save_file(string, bram, 256*1024, 0); +} + +/* + * BOOL model3_save_state(CHAR *file); + * + * Saves a state. + * + * Parameters: + * file = Name of save state file to generate. + * + * Returns: + * MODEL3_OKAY = Success. + * MODEL3_ERROR = Unable to open the save state file. + */ + +BOOL model3_save_state(CHAR *file) +{ + FILE *fp; + + if ((fp = fopen(file, "wb")) == NULL) + { + error("Unable to save state to %s", file); + return MODEL3_ERROR; + } + + /* + * Write out the main data: PowerPC RAM, backup RAM, and system control + * registers + */ + + fwrite(ram, sizeof(UINT8), 8*1024*1024, fp); + fwrite(bram, sizeof(UINT8), 256*1024, fp); + fwrite(&model3_irq_state, sizeof(UINT8), 1, fp); + fwrite(&model3_irq_enable, sizeof(UINT8), 1, fp); + fwrite(&crom_bank_reg, sizeof(UINT8), 1, fp); + + /* + * Save the rest of the system state + */ + + //ppc_save_state(fp); + bridge_save_state(fp); + controls_save_state(fp); + dma_save_state(fp); + dsb1_save_state(fp); + eeprom_save_state(fp); + r3d_save_state(fp); + rtc_save_state(fp); + scsi_save_state(fp); + tilegen_save_state(fp); +// scsp_save_state(fp); + + fclose(fp); + LOG("model3.log", "saved state: %s\n", file); + return MODEL3_OKAY; +} + +/* + * void m3_load_state(CHAR *file); + * + * Loads a state. + * + * Parameters: + * file = Name of save state file to load. + * + * Returns: + * MODEL3_OKAY = Success. + * MODEL3_ERROR = Unable to open the save state file. + */ + +BOOL model3_load_state(CHAR *file) +{ + FILE *fp; + + if ((fp = fopen(file, "rb")) == NULL) + { + error("Unable to load state from %s", file); + return MODEL3_ERROR; + } + + /* + * Load main data: PowerPC RAM, backup RAM, and system control registers + */ + + fread(ram, sizeof(UINT8), 8*1024*1024, fp); + fread(bram, sizeof(UINT8), 256*1024, fp); + fread(&model3_irq_state, sizeof(UINT8), 1, fp); + fread(&model3_irq_enable, sizeof(UINT8), 1, fp); + fread(&crom_bank_reg, sizeof(UINT8), 1, fp); + model3_set_crom_bank(crom_bank_reg); + + /* + * Load the rest of the system state + */ + + //ppc_load_state(fp); + bridge_load_state(fp); + controls_load_state(fp); + dma_load_state(fp); + dsb1_load_state(fp); + eeprom_load_state(fp); + r3d_load_state(fp); + rtc_load_state(fp); + scsi_load_state(fp); + tilegen_load_state(fp); +// scsp_load_state(fp); + + fclose(fp); + LOG("model3.log", "loaded state: %s\n", file); + return MODEL3_OKAY; +} + +/******************************************************************/ +/* Machine Execution Loop */ +/******************************************************************/ + +UINT m3_irq_bit = 0; // debug + +static LONGLONG timer_start, timer_end; +static LONGLONG timer_frequency; + +static int frame = 0; + +void model3_run_frame(void) +{ + /* + * Reset all profiling sections + */ + + PROFILE_SECT_RESET("-"); + PROFILE_SECT_RESET("ppc"); + PROFILE_SECT_RESET("68k"); + PROFILE_SECT_RESET("tilegen"); + PROFILE_SECT_RESET("real3d"); + PROFILE_SECT_RESET("dma"); + PROFILE_SECT_RESET("scsi"); + + PROFILE_SECT_ENTRY("-"); + + QueryPerformanceFrequency((LARGE_INTEGER*)&timer_frequency); + + if (m3_config.fps_limit) + { + double time = 0.0f; + do + { + QueryPerformanceCounter((LARGE_INTEGER*)&timer_end); + + time = (double)(timer_end - timer_start) / (double)(timer_frequency); + } while (time <= 1.0/60.0); + + timer_start = timer_end; + } + + + /* + * Run the PowerPC and 68K + */ + + LOG("model3.log", "-- ACTIVE SCAN\n"); + //model3_add_irq(model3_irq_enable & 0x0D); + //ppc_set_irq_line(1); + + PROFILE_SECT_ENTRY("ppc"); + ppc_execute(ppc_freq / 60); + PROFILE_SECT_EXIT("ppc"); + + PROFILE_SECT_ENTRY("68k"); + PROFILE_SECT_EXIT("68k"); + + /* + * Enter VBlank and update the graphics + */ + + rtc_step_frame(); + render_frame(); + controls_update(); + + /* + * Generate interrupts for this frame and run the VBlank + */ + + LOG("model3.log", "-- VBL\n"); + + //if (frame & 1) + { + model3_add_irq(model3_irq_enable & 0x4a); + } + + ppc_set_irq_line(1); + + frame++; + + //PROFILE_SECT_ENTRY("ppc"); + //ppc_execute(100000); + //PROFILE_SECT_EXIT("ppc"); + + //model3_remove_irq(0xFF); // some games expect a bunch of IRQs to go low after some time + + PROFILE_SECT_EXIT("-"); +} + +void model3_reset(void) +{ + /* the ROM must be already loaded at this point. */ + /* it must _always_ be called when you load a ROM. */ + + /* profiler */ + + #ifdef _PROFILE_ + profile_cleanup(); + #endif + + /* init log file */ + + LOG_INIT("model3.log"); + LOG("model3.log", "XMODEL "VERSION", built on "__DATE__" "__TIME__".\n\n"); + + /* reset all the buffers */ + + memset(ram, 0, 8*1024*1024); + memset(vram, 0, 1*1024*1024+2*65536); + memset(sram, 0, 1*1024*1024); + memset(bram, 0, 256*1024); + + /* reset all the modules */ + + ppc_reset(); + //if (ppc_reset() != PPC_OKAY) + // error("ppc_reset failed"); + + bridge_reset(m3_config.bridge); + eeprom_reset(); + scsi_reset(); + dma_reset(); + + tilegen_reset(); + r3d_reset(); +// scsp_reset(); +// if(m3_config.flags & GAME_OWN_DSB1) dsb_reset(); + controls_reset(m3_config.flags & (GAME_OWN_STEERING_WHEEL | GAME_OWN_GUN)); + + model3_remove_irq(0xFF); + model3_set_crom_bank(0xFF); + + /* load NVRAMs */ + + model3_load_eeprom(); + model3_load_bram(); +} + +/******************************************************************/ +/* File (and ROM) Management */ +/******************************************************************/ + +/* + * Byteswap a buffer. + */ + +static void byteswap(UINT8 *buf, UINT size) +{ + UINT i; + UINT8 tmp; + + for (i = 0; i < size; i += 2) + { + tmp = buf[i]; + buf[i] = buf[i + 1]; + buf[i + 1] = tmp; + } +} + +static void byteswap32(UINT8 *buf, UINT size) +{ + UINT i; + + for(i = 0; i < size; i += 4) + *(UINT32 *)&buf[i] = BSWAP32(*(UINT32 *)&buf[i]); +} + +#define NO_ITLV 1 +#define ITLV_2 2 +#define ITLV_4 4 +#define ITLV_16 16 + +typedef struct +{ + ROMFILE prog[4]; + ROMFILE crom[4][4]; + ROMFILE vrom[16]; + ROMFILE sprog; + ROMFILE srom[4]; + ROMFILE dsbprog; + ROMFILE dsbrom[4]; +} ROM_LIST; + +static BOOL load_rom(UINT8 *buffer, ROMFILE *romfile, UINT32 offset, UINT32 interleave) +{ + int j; + int size; + UINT32 crc; + UINT8 *temp_buffer; + + size = (int)get_file_size_crc(romfile->crc32); + if (size <= 0) + { + return FALSE; + } + + //message(0, "loading %s\r", romfile->name); + { + static longest_line = 0; + char string[200]; + int length; + sprintf(string, "Loading %s", romfile->name); + length = strlen(string); + longest_line = max(longest_line, length); + + for (j=0; j < longest_line; j++) + { + printf(" "); + } + printf("\r"); + printf("%s\r", string); + } + + if (size != romfile->size) + { + message(0, "File %s has wrong size ! (%d bytes, should be %d bytes)\n", romfile->name, size, romfile->size); + return FALSE; + } + + temp_buffer = (UINT8*)malloc(size); + if (read_file_crc(romfile->crc32, temp_buffer, size) == FALSE) + { + return FALSE; + } + + /* check file CRC */ + crc = 0; + crc = crc32(crc, temp_buffer, size); + if (crc != romfile->crc32) + { + message(0, "File %s has wrong CRC: %08X (should be %08X)\n", romfile->name, crc, romfile->crc32); + return FALSE; + } + + /* interleave */ + for (j = 0; j < romfile->size; j += 2) + { + buffer[offset + (j*interleave) + 0] = temp_buffer[j+0]; + buffer[offset + (j*interleave) + 1] = temp_buffer[j+1]; + } + + SAFE_FREE(temp_buffer); + return TRUE; +} + +static void load_romfiles(ROM_LIST *list) +{ + int i; + + // Load program ROMs + for (i=0; i < 4; i++) + { + if (list->prog[i].load) + { + if (load_rom(&crom[0x800000 - (list->prog[0].size * 4)], &list->prog[i], i*2, ITLV_4) == TRUE) + { + list->prog[i].load = 0; + } + } + } + + // Load CROMs + for (i=0; i < 4; i++) + { + if (list->crom[0][i].load) + { + if (load_rom(crom0, &list->crom[0][i], i*2, ITLV_4) == TRUE) list->crom[0][i].load = 0; + } + } + for (i=0; i < 4; i++) + { + if (list->crom[1][i].load) + { + if (load_rom(crom1, &list->crom[1][i], i*2, ITLV_4) == TRUE) list->crom[1][i].load = 0; + } + } + for (i=0; i < 4; i++) + { + if (list->crom[2][i].load) + { + if (load_rom(crom2, &list->crom[2][i], i*2, ITLV_4) == TRUE) list->crom[2][i].load = 0; + } + } + for (i=0; i < 4; i++) + { + if (list->crom[3][i].load) + { + if (load_rom(crom3, &list->crom[3][i], i*2, ITLV_4) == TRUE) list->crom[3][i].load = 0; + } + } + + // Load VROMs + for (i=0; i < 16; i++) + { + if (list->vrom[i].load) + { + if (load_rom(vrom, &list->vrom[i], i*2, ITLV_16) == TRUE) + { + list->vrom[i].load = 0; + } + } + } + + // Load sound program + if (list->sprog.load) + { + if (load_rom(sprog, &list->sprog, 0, NO_ITLV) == TRUE) + { + list->sprog.load = 0; + } + } + + // Load sound ROMs + for (i=0; i < 4; i++) + { + if (list->srom[i].load) + { + if (load_rom(&srom[i*0x400000], &list->srom[i], 0, NO_ITLV) == TRUE) + { + list->srom[i].load = 0; + } + } + } + + // Load DSB program + if (list->dsbprog.load) + { + if (load_rom(dsbprog, &list->dsbprog, 0, NO_ITLV) == TRUE) + { + list->dsbprog.load = 0; + } + } + + // Load DSB ROMs + for (i=0; i < 4; i++) + { + if (list->dsbrom[i].load) + { + if (load_rom(&dsbrom[i*0x400000], &list->dsbrom[i], 0, NO_ITLV) == TRUE) + { + list->dsbrom[i].load = 0; + } + } + } +} + +static BOOL load_romset(char *gamename, ROMSET *romset, int num_romsets) +{ + int i, j; + ROMSET *game = NULL; + + ROM_LIST list; + int romload_ok; + + memset(&list, 0, sizeof(ROM_LIST)); + + // find the game + for (i=0; i < num_romsets; i++) + { + if (_stricmp(romset[i].game, gamename) == 0) + { + game = &romset[i]; + break; + } + } + if (game == NULL) + { + message(0, "Game %s was not found in gamelist!\n", gamename); + return FALSE; + } + + strcpy(m3_config.game_name, game->title); + message(0, "Loading \"%s\"\n", game->title); + + for (i=0; i < 64; i++) + { + if (game->rom[i].size > 0) + { + switch (game->rom[i].type) + { + case ROMTYPE_PROG0: memcpy(&list.prog[3], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_PROG1: memcpy(&list.prog[2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_PROG2: memcpy(&list.prog[1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_PROG3: memcpy(&list.prog[0], &game->rom[i], sizeof(ROMFILE)); break; + + case ROMTYPE_CROM00: memcpy(&list.crom[0][3], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM01: memcpy(&list.crom[0][2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM02: memcpy(&list.crom[0][1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM03: memcpy(&list.crom[0][0], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM10: memcpy(&list.crom[1][3], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM11: memcpy(&list.crom[1][2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM12: memcpy(&list.crom[1][1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM13: memcpy(&list.crom[1][0], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM20: memcpy(&list.crom[2][3], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM21: memcpy(&list.crom[2][2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM22: memcpy(&list.crom[2][1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM23: memcpy(&list.crom[2][0], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM30: memcpy(&list.crom[3][3], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM31: memcpy(&list.crom[3][2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM32: memcpy(&list.crom[3][1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_CROM33: memcpy(&list.crom[3][0], &game->rom[i], sizeof(ROMFILE)); break; + + case ROMTYPE_VROM00: memcpy(&list.vrom[ 1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM01: memcpy(&list.vrom[ 0], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM02: memcpy(&list.vrom[ 3], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM03: memcpy(&list.vrom[ 2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM04: memcpy(&list.vrom[ 5], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM05: memcpy(&list.vrom[ 4], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM06: memcpy(&list.vrom[ 7], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM07: memcpy(&list.vrom[ 6], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM10: memcpy(&list.vrom[ 9], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM11: memcpy(&list.vrom[ 8], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM12: memcpy(&list.vrom[11], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM13: memcpy(&list.vrom[10], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM14: memcpy(&list.vrom[13], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM15: memcpy(&list.vrom[12], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM16: memcpy(&list.vrom[15], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_VROM17: memcpy(&list.vrom[14], &game->rom[i], sizeof(ROMFILE)); break; + + case ROMTYPE_SPROG: memcpy(&list.sprog, &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_SROM0: memcpy(&list.srom[0], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_SROM1: memcpy(&list.srom[1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_SROM2: memcpy(&list.srom[2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_SROM3: memcpy(&list.srom[3], &game->rom[i], sizeof(ROMFILE)); break; + + case ROMTYPE_DSBPROG: memcpy(&list.dsbprog, &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_DSBROM0: memcpy(&list.dsbrom[0], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_DSBROM1: memcpy(&list.dsbrom[1], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_DSBROM2: memcpy(&list.dsbrom[2], &game->rom[i], sizeof(ROMFILE)); break; + case ROMTYPE_DSBROM3: memcpy(&list.dsbrom[3], &game->rom[i], sizeof(ROMFILE)); break; + } + } + } + + if (game->cromsize > 0) + { + // if CROM banksize = 64MB + crom0 = &crom[0x00800000]; + crom1 = &crom[0x02800000]; + crom2 = &crom[0x04800000]; + crom3 = &crom[0x06800000]; + } + else + { + crom0 = &crom[0x00800000]; + crom1 = &crom[0x01800000]; + crom2 = &crom[0x02800000]; + crom3 = &crom[0x03800000]; + } + + /* load ROM files into memory */ + + // mark the files that need to be loaded + for (i=0; i < 4; i++) + { + if (list.prog[i].size > 0) list.prog[i].load = 1; + if (list.crom[0][i].size > 0) list.crom[0][i].load = 1; + if (list.crom[1][i].size > 0) list.crom[1][i].load = 1; + if (list.crom[2][i].size > 0) list.crom[2][i].load = 1; + if (list.crom[3][i].size > 0) list.crom[3][i].load = 1; + if (list.vrom[ 0+i].size > 0) list.vrom[ 0+i].load = 1; + if (list.vrom[ 4+i].size > 0) list.vrom[ 4+i].load = 1; + if (list.vrom[ 8+i].size > 0) list.vrom[ 8+i].load = 1; + if (list.vrom[12+i].size > 0) list.vrom[12+i].load = 1; + if (list.sprog.size > 0) list.sprog.load = 1; + if (list.srom[i].size > 0) list.srom[i].load = 1; + if (list.dsbprog.size > 0) list.dsbprog.load = 1; + if (list.dsbrom[i].size > 0) list.dsbrom[i].load = 1; + } + + if (set_directory_zip("%s/%s.zip", m3_config.rom_path, game->game) == FALSE) + { + message(0, "Could not open zip file %s/%s.zip", m3_config.rom_path, game->game); + return FALSE; + } + + load_romfiles(&list); + + if (strlen(game->parent) > 0) + { + if (set_directory_zip("%s/%s.zip", m3_config.rom_path, game->parent) == FALSE) + { + message(0, "Could not open zip file %s/%s.zip", m3_config.rom_path, game->parent); + return FALSE; + } + + load_romfiles(&list); + } + + // check if everything was loaded + romload_ok = 1; + for (i=0; i < 4; i++) + { + if (list.prog[i].load) + { + romload_ok = 0; + message(0, "File %s was not found", list.prog[i].name); + } + } + for (j=0; j < 4; j++) + { + for (i=0; i < 4; i++) + { + if (list.crom[j][i].load) + { + romload_ok = 0; + message(0, "File %s was not found", list.crom[j][i].name); + } + } + } + for (i=0; i < 16; i++) + { + if (list.vrom[i].load) + { + romload_ok = 0; + message(0, "File %s was not found", list.vrom[i].name); + } + } + if (list.sprog.load) + { + romload_ok = 0; + message(0, "File %s was not found", list.sprog.name); + } + for (i=0; i < 4; i++) + { + if (list.srom[i].load) + { + romload_ok = 0; + message(0, "File %s was not found", list.srom[i].name); + } + } + if (list.dsbprog.load) + { + romload_ok = 0; + message(0, "File %s was not found", list.dsbprog.name); + } + for (i=0; i < 4; i++) + { + if (list.dsbrom[i].load) + { + romload_ok = 0; + message(0, "File %s was not found", list.dsbrom[i].name); + } + } + + if (!romload_ok) + { + return FALSE; + } + + + /* byteswap buffers */ + byteswap(&crom[8*1024*1024 - (list.prog[0].size * 4)], list.prog[0].size * 4); + byteswap(crom0, list.crom[0][0].size * 4); + byteswap(crom1, list.crom[1][0].size * 4); + byteswap(crom2, list.crom[2][0].size * 4); + byteswap(crom3, list.crom[3][0].size * 4); + byteswap(vrom, list.vrom[0].size * 16); + byteswap32(vrom, list.vrom[0].size * 16); + + /* set stepping */ + + m3_config.step = game->step; + + /* set bridge controller */ + + if (game->bridge == 0) + game->bridge = (game->step < 0x20) ? 1 : 2; + + m3_config.bridge = game->bridge; + + // copy controls + memcpy(&m3_config.controls, &game->controls, sizeof(GAME_CONTROLS)); + + /* mirror CROM0 to CROM if needed */ + + if ((list.prog[0].size * 4) < 8*1024*1024) + { + memcpy(crom, crom0, 8*1024*1024 - list.prog[0].size*4); + } + + if (game->cromsize < 1) + { + memcpy(&crom[0x4800000], crom0, 0x1000000); + memcpy(&crom[0x5800000], crom1, 0x1000000); + memcpy(&crom[0x6800000], crom2, 0x1000000); + memcpy(&crom[0x7800000], crom3, 0x1000000); + } + + /* + * Perhaps mirroring must occur between the CROMx + * and the CROMx space, if CROMx is < 16MB? + */ + + /* mirror lower VROM if necessary */ + + if ((list.vrom[0].size * 16) < 64*1024*1024) + { + memcpy(&vrom[list.vrom[0].size * 16], vrom, 64*1024*1024 - list.vrom[0].size * 16); + } + + /* if we're here, everything went fine! */ + + message(0, "ROM loaded successfully!"); + + /* + * Debug ROM dump + */ + +// save_file("crom.bin", &crom[0x800000 - romset.crom[0].size * 4], romset.crom[0].size * 4, 0); +// save_file("crom.bin", crom, 8*1024*1024, 0); +// save_file("vrom.bin", vrom, 64*1024*1024, 0); +// save_file("crom0.bin", crom0, 16*1024*1024, 0); +// save_file("crom1.bin", crom1, 16*1024*1024, 0); +// save_file("crom2.bin", crom2, 16*1024*1024, 0); + + /* + * Apply the patches + */ + + for( i=0; i < game->num_patches; i++ ) + { + switch (game->patch[i].size) + { + case 8: + crom[game->patch[i].address] = BSWAP32(game->patch[i].data); + break; + case 16: + *(UINT16*) &crom[game->patch[i].address] = BSWAP16((UINT16) game->patch[i].data); + break; + case 32: + *(UINT32*) &crom[game->patch[i].address] = BSWAP32(game->patch[i].data); + break; + default: + message(0, "internal error, line %d of %s: invalid patch size (%d)\n", __LINE__, __FILE__, game->patch[i].size); + break; + } + } + + return TRUE; +} + + +/******************************************************************/ +/* Machine Interface */ +/******************************************************************/ + +void model3_shutdown(void) +{ + /* save NVRAMs */ + + model3_save_eeprom(); + model3_save_bram(); + + /* shutdown all the modules */ + controls_shutdown(); +// scsp_shutdown(); +// if(m3_config.flags & GAME_OWN_DSB1) dsb_reset(); + render_shutdown(); + r3d_shutdown(); + tilegen_shutdown(); + dma_shutdown(); + scsi_shutdown(); + + ppc_shutdown(); + + /* free any allocated buffer */ + //save_file("rom", crom, 0x800000, 0); + //save_file("ram", ram, 8*1024*1024, 0); + //save_file("vram", vram, 1*1024*1024+2*65536, 0); + //save_file("8e000000", culling_ram_8e, 1*1024*1024, 0); + //save_file("8c000000", culling_ram_8c, 4*1024*1024, 0); + //save_file("98000000", polygon_ram, 2*1024*1024, 0); + //save_file("texture.bin", texture_ram, 2048*2048*2, 0); + + SAFE_FREE(ram); + SAFE_FREE(vram); + SAFE_FREE(sram); + SAFE_FREE(bram); + SAFE_FREE(culling_ram_8e); + SAFE_FREE(culling_ram_8c); + SAFE_FREE(polygon_ram); + SAFE_FREE(texture_ram); + + SAFE_FREE(crom); + SAFE_FREE(vrom); + +#if PROFILE_MEMORY_OPERATIONS + print_memory_profile_stats(); +#endif +} + +static PPC_FETCH_REGION m3_ppc_fetch[3]; + +static ROMSET romset[256]; +static int num_romsets = 0; + +BOOL model3_load(void) +{ + int i; + crom = (UINT8 *)malloc(136*1024*1024); + vrom = (UINT8 *)malloc(64*1024*1024); + sprog = (UINT8 *)malloc(0x80000); + srom = (UINT8 *)malloc(0x1000000); + dsbprog = (UINT8 *)malloc(0x80000); + dsbrom = (UINT8 *)malloc(0x1000000); + + if ((crom == NULL) || (vrom == NULL) || (srom == NULL) || (dsbrom == NULL) || + (sprog == NULL) || (dsbprog == NULL)) + { + SAFE_FREE(crom); + SAFE_FREE(vrom); + + message(0, "ERROR: Couldn't allocate RAM for ROMs"); + return FALSE; + } + + memset(crom, 0xFF, 136*1024*1024); + + num_romsets = parse_romlist(m3_config.rom_list, romset); + if (num_romsets == 0) + { + return FALSE; + } + + if (load_romset(m3_config.game_id, romset, num_romsets) == FALSE) + { + return FALSE; + } + + return TRUE; +} + +BOOL model3_init(void) +{ + PPC_CONFIG ppc_config; + /* setup m3_config (which is already partially done in parse_command_line) */ + + m3_config.log_enabled = 1; + + /* allocate memory */ + + ram = (UINT8 *) malloc(8*1024*1024); + vram = (UINT8 *) malloc(2*1024*1024); + sram = (UINT8 *) malloc(1*1024*1024); + bram = (UINT8 *) malloc(256*1024); + culling_ram_8e = (UINT8 *) malloc(1*1024*1024); + culling_ram_8c = (UINT8 *) malloc(4*1024*1024); + polygon_ram = (UINT8 *) malloc(2*1024*1024); + texture_ram = (UINT8 *) malloc(2048*2048*2); + + if ((ram == NULL) || (vram == NULL) || (sram == NULL) || (bram == NULL) || + (culling_ram_8e == NULL) || (culling_ram_8c == NULL) || (polygon_ram == NULL) || + (texture_ram == NULL)) + { + SAFE_FREE(ram); + SAFE_FREE(vram); + SAFE_FREE(sram); + SAFE_FREE(bram); + SAFE_FREE(culling_ram_8e); + SAFE_FREE(culling_ram_8c); + SAFE_FREE(polygon_ram); + SAFE_FREE(texture_ram); + + message(0, "Out of memory!"); + return FALSE; + } + + /* attach m3_shutdown to atexit */ + + atexit(model3_shutdown); + + /* setup the PPC */ + + if (m3_config.step >= 0x20) + { + ppc_config.pvr = PPC_MODEL_603R; + ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; + ppc_config.bus_frequency_multiplier = 0x25; // multiplier 2.5 + } + else if (m3_config.step == 0x15) + { + ppc_config.pvr = PPC_MODEL_603E; + ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; + ppc_config.bus_frequency_multiplier = 0x15; // multiplier 1.5 + } + else + { + ppc_config.pvr = PPC_MODEL_603E; + ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; + ppc_config.bus_frequency_multiplier = 0x10; // multiplier 1.0 + } + + ppc_init(&ppc_config); + + m3_ppc_fetch[0].start = 0; + m3_ppc_fetch[0].end = 0x7FFFFF; + m3_ppc_fetch[0].ptr = (UINT32 *)ram; + + m3_ppc_fetch[1].start = 0xFF800000; + m3_ppc_fetch[1].end = 0xFFFFFFFF; + m3_ppc_fetch[1].ptr = (UINT32 *)crom; + + m3_ppc_fetch[2].start = 0; + m3_ppc_fetch[2].end = 0; + m3_ppc_fetch[2].ptr = (UINT32 *)NULL; + + ppc_set_fetch(m3_ppc_fetch); + + switch (m3_config.step) // set frequency + { + case 0x15: ppc_freq = 100000000; break; // Step 1.5 PPC @ 100MHz + case 0x20: ppc_freq = 166000000; break; // Step 2.0 PPC @ 166MHz + case 0x21: ppc_freq = 166000000; break; // Step 2.1 PPC @ 166MHz + default: // assume Step 1.0... + case 0x10: ppc_freq = 66000000; break; // Step 1.0 PPC @ 66MHz + } + + //ppc_freq = 20000000; + + /* setup the 68K */ + + /* A68K INIT! */ + + /* setup remaining peripherals -- renderer and sound output is */ + /* already setup at this point. */ + + bridge_init(pci_command_callback); + scsi_init(m3_ppc_read_8, m3_ppc_read_16, m3_ppc_read_32, m3_ppc_write_8, m3_ppc_write_16, m3_ppc_write_32); + dma_init(m3_ppc_read_32, m3_ppc_write_32); + tilegen_init(vram); + r3d_init(culling_ram_8e, culling_ram_8c, polygon_ram, texture_ram, vrom); + render_init(culling_ram_8e, culling_ram_8c, polygon_ram, texture_ram, vrom); +// scsp_init(); +// if(m3_config.flags & GAME_OWN_DSB1) dsb_reset(); + controls_init(); + + return TRUE; +} diff --git a/core/model3.h b/core/model3.h new file mode 100644 index 0000000..83099a3 --- /dev/null +++ b/core/model3.h @@ -0,0 +1,417 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * model3.h + * + * Model 3 header. This serves as the primary header file for all modules to + * include. + */ + +#ifndef INCLUDED_MODEL3_H +#define INCLUDED_MODEL3_H + +/******************************************************************/ +/* Program Information */ +/******************************************************************/ + +#define VERSION "0.01" // program version +#define VERSION_MAJOR 0x00 // major version number (BCD) +#define VERSION_MINOR 0x01 // minor version number (BCD) + +/******************************************************************/ +/* Includes */ +/******************************************************************/ + +#include +#include +#include +#include +#include +//#include "zlib.h" + +#include "osd.h" // provided by the port to define data types, etc. + +#include "ppc_itp/ppc.h" + +//#include "m68k/m68k.h" + +#include "controls.h" +#include "dma.h" +#include "dsb1.h" +#include "eeprom.h" +#include "bridge.h" +#include "r3d.h" +#include "render.h" +#include "rtc.h" +#include "scsi.h" +#include "scsp.h" +#include "tilegen.h" +#include "file.h" + +#include "osd_common.h" // defines OSD interface (must be included last) + +/******************************************************************/ +/* Helpful Macros */ +/******************************************************************/ + +#define MODEL3_OKAY 0 /* Everything went okay */ +#define MODEL3_ERROR -1 /* Some error happened */ + +#define MODEL3_SCREEN_WIDTH 496 +#define MODEL3_SCREEN_HEIGHT 384 + +#define SAFE_FREE(p) { if(p != NULL) free(p); p = NULL; } + +#define PPC_PC ppc_get_reg(PPC_REG_PC) +#define PPC_LR ppc_get_reg(PPC_REG_LR) + +#ifdef _MSC_VER + +#define BSWAP16(x) _byteswap_ushort(x) +#define BSWAP32(x) _byteswap_ulong(x) + +#else + +static UINT16 BSWAP16(UINT16 d) +{ + return(((d >> 8) & 0x00FF) | + ((d << 8) & 0xFF00)); +} + +static UINT32 BSWAP32(UINT32 d) +{ + return(((d >> 24) & 0x000000FF) | + ((d >> 8) & 0x0000FF00) | + ((d << 8) & 0x00FF0000) | + ((d << 24) & 0xFF000000)); +} + +#endif + +/******************************************************************/ +/* Configuration Structure */ +/******************************************************************/ + +/* + * Game Flags + * + * Identify various properties that the games can have. + */ + +#define GAME_OWN_STEERING_WHEEL (1 << 0) // analog steering wheel +#define GAME_OWN_GUN (1 << 1) // light gun +#define GAME_OWN_DSB1 (1 << 2) // DSB1 sound board + +typedef enum +{ + P1_BUTTON_1, + P1_BUTTON_2, + P1_BUTTON_3, + P1_BUTTON_4, + P1_BUTTON_5, + P1_BUTTON_6, + P1_BUTTON_7, + P1_BUTTON_8, + P2_BUTTON_1, + P2_BUTTON_2, + P2_BUTTON_3, + P2_BUTTON_4, + P2_BUTTON_5, + P2_BUTTON_6, + P2_BUTTON_7, + P2_BUTTON_8, + P1_JOYSTICK_UP, + P1_JOYSTICK_DOWN, + P1_JOYSTICK_LEFT, + P1_JOYSTICK_RIGHT, + P2_JOYSTICK_UP, + P2_JOYSTICK_DOWN, + P2_JOYSTICK_LEFT, + P2_JOYSTICK_RIGHT, +} GAME_BUTTON; + +typedef enum +{ + ANALOG_AXIS_1, + ANALOG_AXIS_2, + ANALOG_AXIS_3, + ANALOG_AXIS_4, + ANALOG_AXIS_5, + ANALOG_AXIS_6, + ANALOG_AXIS_7, + ANALOG_AXIS_8, +} GAME_ANALOG; + +typedef struct +{ + struct + { + UINT8 control_set; + UINT8 control_bit; + GAME_BUTTON mapping; + int enabled; + } button[16]; + + struct + { + GAME_ANALOG mapping; + int enabled; + UINT8 center; + } analog_axis[8]; + +} GAME_CONTROLS; + +/* + * CONFIG Structure + * + * Emulator configuration and game information. + */ + +typedef struct +{ + /* + * Emulator Configuration + * + * Determines the behavior of the emulator itself. These fields can be + * loaded, saved, and modified. The user has control over these options. + */ + + BOOL log_enabled; // whether to log (no effect if _LOG_ not defined) + BOOL fullscreen; + BOOL triple_buffer; + INT width; + INT height; + BOOL stretch; + FLAGS layer_enable; + CHAR rom_path[512]; + CHAR rom_list[512]; + CHAR backup_path[512]; + BOOL fps_limit; + BOOL show_fps; + + /* + * Game Configuration + * + * Information on the game currently being emulated. The user has no + * control over this stuff -- it's internal to the emulator only. + */ + + CHAR game_id[8+1]; // game ID string (max 8 chars + null terminator) + CHAR game_name[128]; + INT step; // hardware step (0x15 = Step 1.5, etc.) + INT bridge; // type of PCIBMC (1=MPC105, 2=MPC106) + FLAGS flags; // game info flags + BOOL has_lightgun; + + // Game controls + GAME_CONTROLS controls; + +} CONFIG; + +enum +{ + ROMTYPE_NONE = 0, + ROMTYPE_PROG0 = 1, + ROMTYPE_PROG1, + ROMTYPE_PROG2, + ROMTYPE_PROG3, + ROMTYPE_CROM00, + ROMTYPE_CROM01, + ROMTYPE_CROM02, + ROMTYPE_CROM03, + ROMTYPE_CROM10, + ROMTYPE_CROM11, + ROMTYPE_CROM12, + ROMTYPE_CROM13, + ROMTYPE_CROM20, + ROMTYPE_CROM21, + ROMTYPE_CROM22, + ROMTYPE_CROM23, + ROMTYPE_CROM30, + ROMTYPE_CROM31, + ROMTYPE_CROM32, + ROMTYPE_CROM33, + ROMTYPE_VROM00, + ROMTYPE_VROM01, + ROMTYPE_VROM02, + ROMTYPE_VROM03, + ROMTYPE_VROM04, + ROMTYPE_VROM05, + ROMTYPE_VROM06, + ROMTYPE_VROM07, + ROMTYPE_VROM10, + ROMTYPE_VROM11, + ROMTYPE_VROM12, + ROMTYPE_VROM13, + ROMTYPE_VROM14, + ROMTYPE_VROM15, + ROMTYPE_VROM16, + ROMTYPE_VROM17, + ROMTYPE_SPROG, + ROMTYPE_SROM0, + ROMTYPE_SROM1, + ROMTYPE_SROM2, + ROMTYPE_SROM3, + ROMTYPE_DSBPROG, + ROMTYPE_DSBROM0, + ROMTYPE_DSBROM1, + ROMTYPE_DSBROM2, + ROMTYPE_DSBROM3, +}; + +typedef struct +{ + int type; + char name[20]; + int size; + UINT32 crc32; + int load; +} ROMFILE; + +typedef struct { + UINT32 address; + UINT32 data; + INT size; // 8, 16, or 32 +} PATCH; + +typedef struct +{ + char game[20]; + char parent[20]; + char title[256]; + char manufacturer[32]; + int year; + int step; + int bridge; + int cromsize; + FLAGS flags; + int num_patches; + PATCH patch[64]; + + ROMFILE rom[64]; + + GAME_CONTROLS controls; + +} ROMSET; + +typedef struct +{ + char id[60]; + UINT32 int_id; +} STRING_ID; + +static int get_string_id(const char *string, STRING_ID *idtable) +{ + int i=0; + + while (strlen(idtable[i].id) > 0) + { + if (_stricmp(string, idtable[i].id) == 0) + { + return idtable[i].int_id; + } + i++; + } + + return -1; +} + +/* + * m3_config + * + * A global variable accessible by all parts of the emulator after emulation + * begins successfully. + */ + +extern CONFIG m3_config; + +extern void message(int, char * fmt, ...); +extern void error(char * fmt, ...); + +extern BOOL parse_config(const char *config_name); +extern int parse_romlist(char *romlist_name, ROMSET *_romset); + +/* + * Profile + */ + +extern void profile_section_entry(CHAR * name); +extern void profile_section_exit(CHAR * name); +extern UINT64 profile_get_stat(CHAR * name); +extern void profile_reset_sect(CHAR * name); +extern void profile_cleanup(void); +extern void profile_print(CHAR * string); + +#ifdef _PROFILE_ +#define PROFILE_SECT_ENTRY(n) profile_section_entry(n); +#define PROFILE_SECT_EXIT(n) profile_section_exit(n); +#define PROFILE_SECT_RESET(n) profile_reset_sect(n); +#else // !_PROFILE_ +#define PROFILE_SECT_ENTRY(n) +#define PROFILE_SECT_EXIT(n) +#define PROFILE_SECT_RESET(n) +#endif // _PROFILE_ + +/******************************************************************/ +/* Functions */ +/******************************************************************/ + +#ifdef _LOG_ +#define LOG_INIT _log_init +#define LOG _log +#else // !_LOG_ +#define LOG_INIT +#define LOG +#endif // _LOG + +extern void _log(char * path, char * fmt, ...); +extern void _log_init(char * path); + +extern BOOL model3_init(void); +extern void model3_shutdown(void); + +extern BOOL model3_load(void); + +extern void model3_reset(void); +extern void model3_run_frame(void); +extern void model3_add_irq(UINT8); +extern void model3_remove_irq(UINT8); + +extern BOOL model3_save_state(CHAR *); +extern BOOL model3_load_state(CHAR *); + +extern void model3_load_eeprom(void); +extern void model3_save_eeprom(void); +extern void model3_load_bram(void); +extern void model3_save_bram(void); + +extern UINT8 m3_ppc_read_8(UINT32 a); +extern UINT16 m3_ppc_read_16(UINT32 a); +extern UINT32 m3_ppc_read_32(UINT32 a); +extern UINT64 m3_ppc_read_64(UINT32 a); +extern void m3_ppc_write_8(UINT32 a, UINT8 d); +extern void m3_ppc_write_16(UINT32 a, UINT16 d); +extern void m3_ppc_write_32(UINT32 a, UINT32 d); +extern void m3_ppc_write_64(UINT32 a, UINT64 d); + +extern void model3_dma_transfer(UINT32 src, UINT32 dst, int length, BOOL swap_words); + +/******************************************************************/ + +#endif // INCLUDED_MODEL3_H diff --git a/core/r3d.c b/core/r3d.c new file mode 100644 index 0000000..ee40a92 --- /dev/null +++ b/core/r3d.c @@ -0,0 +1,937 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * r3d.c + * + * Real3D Model 3 graphics system emulation. The 3D hardware in Model 3 is + * supposedly based on the Pro-1000. + * + * To-Do List: + * ----------- + * - In VS2_98, in the attract mode, when the camera zooms in on the score + * board for South Africa vs. Nigeria, the "Nigeria" text texture is + * garbage. + * - RAM texture uploading is too weird to be true. + */ + +/* + * RAM Size: + * --------- + * + * It appears that there is 2MB total of "culling RAM." 1MB appears at + * 0x8C000000 and the other at 0x8E000000. Step 1.0 and 1.5 appear to have + * 1MB of polygon RAM, but Step 2.0 (and probably 2.1) clearly uses 2MB. + */ + +#include "model3.h" + +extern UINT8 *ram; + +/******************************************************************/ +/* Privates */ +/******************************************************************/ + +static UINT8 *culling_ram_8e; // culling RAM at 0x8E000000 +static UINT8 *culling_ram_8c; // culling RAM at 0x8C000000 +static UINT8 *polygon_ram; // polygon RAM at 0x98000000 +static UINT8 *texture_ram; // texture RAM +static UINT8 *vrom; + +static UINT8 texture_buffer_ram[1*1024*1024]; + +static UINT32 vrom_texture_address; +static UINT32 vrom_texture_header; + +static UINT32 texture_last_addr = 0; +static UINT32 texture_header = 0; + +/******************************************************************/ +/* Interface */ +/******************************************************************/ + +/* + * void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr, + * UINT8 *polygon_ram_ptr, UINT8 *texture_ram, UINT8 *vrom_ptr); + * + * Initializes the Real3D graphics emulation. + * + * Parameters: + * culling_ram_8e_ptr = Pointer to 0x8E000000 culling RAM. + * culling_ram_8c_ptr = Pointer to 0x8C000000 culling RAM. + * polygon_ram_ptr = Pointer to polygon RAM. + * texture_ram = Pointer to texture RAM. + * vrom_ptr = Pointer to VROM. + */ + +void r3d_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr, + UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, UINT8 *vrom_ptr) +{ + culling_ram_8e = culling_ram_8e_ptr; + culling_ram_8c = culling_ram_8c_ptr; + polygon_ram = polygon_ram_ptr; + texture_ram = texture_ram_ptr; + vrom = vrom_ptr; + + LOG_INIT("texture.log"); +} + +/* + * void r3d_shutdown(void); + * + * Shuts down the Real3D emulation. + */ + +void r3d_shutdown(void) +{ +} + +/* + * void r3d_reset(void); + * + * Resets the Real3D graphics hardware. RAM is cleared in order to prevent + * the renderer from drawing garbage and possibly locking up as a result. + */ + +void r3d_reset(void) +{ + memset(culling_ram_8e, 0, 1*1024*1024); + memset(culling_ram_8c, 0, 4*1024*1024); + memset(polygon_ram, 0, 2*1024*1024); + memset(texture_ram, 0, 2048*2048*2); + tap_reset(); +} + +/* + * void r3d_save_state(FILE *fp); + * + * Saves the state of the Real3D graphics hardware to a file. + * + * Parameters: + * fp = File to save to. + */ + +void r3d_save_state(FILE *fp) +{ + fwrite(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp); + fwrite(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp); + fwrite(polygon_ram, sizeof(UINT8), 2*1024*1024, fp); + fwrite(texture_ram, sizeof(UINT8), 2048*2048*2, fp); +} + +/* + * void r3d_load_state(FILE *fp); + * + * Loads the state of the Real3D graphics hardware from a file. + * + * Parameters: + * fp = File to load from. + */ + +void r3d_load_state(FILE *fp) +{ + fread(culling_ram_8e, sizeof(UINT8), 1*1024*1024, fp); + fread(culling_ram_8c, sizeof(UINT8), 4*1024*1024, fp); + fread(polygon_ram, sizeof(UINT8), 2*1024*1024, fp); + fread(texture_ram, sizeof(UINT8), 2048*2048*2, fp); + + osd_renderer_invalidate_textures(0, 0, 2048, 2048, texture_ram); +} + +/******************************************************************/ +/* Texture Memory Management */ +/******************************************************************/ + +static const INT decode[64] = +{ + 0, 1, 4, 5, 8, 9,12,13, + 2, 3, 6, 7,10,11,14,15, + 16,17,20,21,24,25,28,29, + 18,19,22,23,26,27,30,31, + 32,33,36,37,40,41,44,45, + 34,35,38,39,42,43,46,47, + 48,49,52,53,56,57,60,61, + 50,51,54,55,58,59,62,63 +}; + +/* + * store_texture_tile(): + * + * Writes a single 8x8 texture tile into the appropriate part of the texture + * sheet. + */ + +static void store_texture_tile(UINT x, UINT y, UINT8 *src, UINT bpp, BOOL little_endian) +{ + UINT xi, yi, pixel_offs; + UINT16 rgb16; + UINT8 gray8; + + for (yi = 0; yi < 8; yi++) + { + for (xi = 0; xi < 8; xi++) + { + /* + * Grab the pixel offset from the decode[] array and fetch the + * pixel word + */ + + if (little_endian) + { + if (bpp == 2) + { + /* + * XOR with 1 in little endian mode -- every word contains + * 2 16-bit pixels, thus they are swapped + */ + + pixel_offs = decode[(yi * 8 + xi) ^ 1] * 2; + rgb16 = *(UINT16 *) &src[pixel_offs]; + } + else + { + pixel_offs = decode[((yi ^ 1) * 8 + (xi ^ 1))]; + gray8 = src[pixel_offs]; + } + } + else + { + if (bpp == 2) + { + pixel_offs = decode[yi * 8 + xi] * 2; + rgb16 = (src[pixel_offs + 0] << 8) | src[pixel_offs + 1]; + } + else + { + pixel_offs = decode[yi * 8 + xi]; + gray8 = src[pixel_offs + 0]; + } + } + + /* + * Store within the texture sheet + */ + + if (bpp == 2) + *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2] = rgb16; + else + texture_ram[(((y + yi) * 2048 + x) * 2) + xi] = gray8; + } + } +} + +/* + * store_texture(): + * + * Writes a texture into the texture sheet. The pixel words are not decoded, + * but the 16-bit pixels are converted into a common endianness (little.) + * 8-bit pixels are not expanded into 16-bits. + * + * bpp (bytes per pixel) must be 1 or 2. + */ + +static void store_texture(UINT x, UINT y, UINT w, UINT h, UINT8 *src, UINT bpp, BOOL little_endian) +{ + UINT xi, yi; + UINT bw; + + if(bpp == 2) + bw = 1; + else + bw = 2; + + for (yi = 0; yi < h; yi += 8) + { + for (xi = 0; xi < w; xi += 8) + { + store_texture_tile(x + (xi / bw), y + yi, src, bpp, little_endian); + src += 8 * 8 * bpp; // each texture tile is 8x8 and 16-bit color + } + } +} + +/* + * upload_texture(): + * + * Uploads a texture to texture memory. + */ + +// Mipmap starting positions for each level +static const int mipmap_xpos[11] = +{ 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 }; +static const int mipmap_ypos[11] = +{ 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023, 0 }; + +// Mipmap size dividers +static const int mipmap_size[9] = +{ 2, 4, 8, 16, 32, 64, 128, 256, 512 }; + +static void upload_texture(UINT32 header, UINT8 *src, BOOL little_endian) +{ + UINT size_x, size_y, xpos, ypos, bit_depth, mip_ypos, page; + int mipmap_num = 0; + int mxpos, mypos, msize_x, msize_y; + + PROFILE_SECT_ENTRY("real3d"); + + /* + * Model 3 texture RAM appears as 2 2048x1024 textures. When textures are + * uploaded, their size and position within a sheet is given. I treat the + * texture sheet selection bit as an additional bit to the Y coordinate. + */ + + size_x = (header >> 14) & 7; + size_y = (header >> 17) & 7; + size_x = (32 << size_x); // width in pixels + size_y = (32 << size_y); // height + + ypos = (((header >> 7) & 0x1F) | ((header >> 15) & 0x20)) * 32; + xpos = ((header >> 0) & 0x3F) * 32; + + mip_ypos = ((header >> 7) & 0x1F) * 32; + page = (header >> 15 & 0x20) ? 1 : 0; + + if( header & 0x00800000 ) + bit_depth = 2; // 16-bit texture + else + bit_depth = 1; // 8-bit texture + + LOG("texture.log", "%08X %d,%d\t%dx%d\n", header, xpos, ypos, size_x, size_y); + + /* + * Render the texture into the texture buffer + */ + + switch( (header >> 24) & 0xF ) + { + case 0: // Texture with mipmaps + store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian); + osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0); + + msize_x = size_x; + msize_y = size_y; + + // Store mipmaps + while( msize_y > 8 && msize_x > 8 ) { + + src += (msize_x * msize_y * bit_depth); + msize_x /= 2; + msize_y /= 2; + + mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]); + mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]); + if(page) + mypos += 1024; + mipmap_num++; + + store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian); + //osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num); + } + break; + + case 1: // Texture without mipmaps + store_texture(xpos, ypos, size_x, size_y, src, bit_depth, little_endian); + osd_renderer_invalidate_textures(xpos, ypos, xpos, ypos, size_x, size_y, texture_ram, 0); + break; + + case 2: // Only mipmaps + msize_x = size_x; + msize_y = size_y; + while( msize_y > 8 && msize_x > 8 ) { + + msize_x /= 2; + msize_y /= 2; + + mxpos = mipmap_xpos[mipmap_num] + (xpos / mipmap_size[mipmap_num]); + mypos = mipmap_ypos[mipmap_num] + (mip_ypos / mipmap_size[mipmap_num]); + if(page) + mypos += 1024; + mipmap_num++; + + store_texture(mxpos, mypos, msize_x, msize_y, src, bit_depth, little_endian); + //osd_renderer_invalidate_textures(mxpos, mypos, xpos, ypos, size_x, size_y, texture_ram, mipmap_num); + + src += (msize_x * msize_y * bit_depth); + } + break; + } + + /* + * Remove any existing textures that may have been overwritten + */ + + //osd_renderer_invalidate_textures(xpos, ypos, size_x, size_y); + + PROFILE_SECT_EXIT("real3d"); +} + +/******************************************************************/ +/* Access */ +/******************************************************************/ + +static BOOL trigger = 0; +static UINT64 trigger_time; + +/* + * UINT32 r3d_read_32(UINT32 a); + * + * Reads a 32-bit word from the Real3D regions. + * + * Parameters: + * a = Address. + * + * Returns: + * Data read. + */ + +UINT32 r3d_read_32(UINT32 a) +{ + static UINT32 _84000000 = 0; + +// message(0, "%08X (%08X): Real3D read32 to %08X", PPC_PC, PPC_LR, a); + + switch (a) + { + /* + * In Lost World, routine at 0x1174E0 reads all the 0x840000XX status + * registers and at 0x117A30, bit 0x02000000 is checked for. + */ + + case 0x84000000: + return (_84000000 ^= 0xFFFFFFFF); + case 0x84000004: // unknown + case 0x84000008: + case 0x8400000C: + case 0x84000010: + case 0x84000014: + case 0x84000018: + case 0x8400001C: + case 0x84000020: + return 0xFFFFFFFF; + } + + error("Unknown R3D read: %08X: %08X\n", ppc_get_pc(), a); + return(0); +} + +/* + * void r3d_write_32(UINT32 a, UINT32 d); + * + * Writes a 32-bit word to the Real3D regions. + * + * Parameters: + * a = Address. + * d = Data to write. + */ + +UINT32 _9C000000, _9C000004, _9C000008; +static int texture_start_pos = 8; +static int texture_ram_ptr = 0; + +void r3d_write_32(UINT32 a, UINT32 d) +{ + static UINT32 last_addr; + + if (a >= 0x8E000000 && a <= 0x8E0FFFFF) // culling RAM + { + *(UINT32 *) &culling_ram_8e[a & 0xFFFFF] = BSWAP32(d); + return; + } + else if (a >= 0x8C000000 && a <= 0x8C3FFFFF) // culling RAM + { + *(UINT32 *) &culling_ram_8c[a & 0x3FFFFF] = BSWAP32(d); + return; + } + else if (a >= 0x98000000 && a <= 0x981FFFFF) // polygon RAM + { +// if(a >= 0x98001000 && a < 0x98002000) +// message(1, "color table: %08X = %08X", a, BSWAP32(d)); + + *(UINT32 *) &polygon_ram[a & 0x1FFFFF] = BSWAP32(d); + return; + } + else if (a >= 0x94000000 && a <= 0x940FFFFF) // texture buffer + { + d = BSWAP32(d); + *(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d; + + texture_ram_ptr += 4; + return; + } + + switch (a) + { + case 0x88000000: // trigger? + + //message(0, "%08X (%08X): 88000000 = %08X", PPC_PC, PPC_LR, BSWAP32(d)); + + if( texture_ram_ptr > 0 ) { + int i=0; + while( i < texture_ram_ptr ) { + UINT32 length = (*(UINT32*)&texture_buffer_ram[i+0] / 2) + 2; + UINT32 header = *(UINT32*)&texture_buffer_ram[i+4]; + upload_texture( header, &texture_buffer_ram[i+8], 1 ); + i += length; + }; + } + texture_ram_ptr = 0; + + return; + case 0x90000000: // VROM texture address + vrom_texture_address = BSWAP32(d); + LOG("model3.log", "VROM1 ADDR = %08X\n", BSWAP32(d)); + //message(0, "VROM texture address = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR); + return; + case 0x90000004: + vrom_texture_header = BSWAP32(d); + LOG("model3.log", "VROM1 HEAD = %08X\n", BSWAP32(d)); + //message(0, "VROM texture header = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR); + return; + case 0x90000008: + upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1); + LOG("model3.log", "VROM1 SIZE = %08X\n", BSWAP32(d)); + //message(0, "VROM texture length = %08X @ %08X (%08X)", BSWAP32(d), PPC_PC, PPC_LR); + return; + case 0x9000000C: // ? Virtual On 2: These are almost certainly for VROM textures as well (I was too lazy to check :P) + vrom_texture_address = BSWAP32(d); + LOG("model3.log", "VROM2 ADDR = %08X\n", BSWAP32(d)); + //message(0, "90000000C = %08X", BSWAP32(d)); + return; + case 0x90000010: // ? + vrom_texture_header = BSWAP32(d); + LOG("model3.log", "VROM2 HEAD = %08X\n", BSWAP32(d)); + //message(0, "900000010 = %08X", BSWAP32(d)); + return; + case 0x90000014: // ? + upload_texture(vrom_texture_header, &vrom[(vrom_texture_address & 0xFFFFFF) * 4], 1); + LOG("model3.log", "VROM2 SIZE = %08X\n", BSWAP32(d)); + //message(0, "900000014 = %08X", BSWAP32(d)); + return; + case 0x9C000000: // ? + //message(0, "9C000000 = %08X", BSWAP32(d)); + LOG("model3.log", "%08X = %08X\n", a, d); + _9C000000 = BSWAP32(d); + return; + case 0x9C000004: // ? + //message(0, "9C000004 = %08X", BSWAP32(d)); + LOG("model3.log", "%08X = %08X\n", a, d); + _9C000004 = BSWAP32(d); + return; + case 0x9C000008: // ? + //message(0, "9C000008 = %08X", BSWAP32(d)); + LOG("model3.log", "%08X = %08X\n", a, d); + _9C000008 = BSWAP32(d); + return; + } + + error("Unknown R3D write: %08X: %08X = %08X\n", ppc_get_pc(), a, d); +} + +void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words) +{ + int i; + + dst &= 0xffffff; + + if (swap_words) + { + for (i=0; i < length; i+=4) + { + UINT32 d = BSWAP32(*src++); + *(UINT32 *)&culling_ram_8c[dst] = d; + dst += 4; + } + } + else + { + for (i=0; i < length; i+=4) + { + UINT32 d = (*src++); + *(UINT32 *)&culling_ram_8c[dst] = d; + dst += 4; + } + } +} + +void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words) +{ + int i; + + dst &= 0xffffff; + + if (swap_words) + { + for (i=0; i < length; i+=4) + { + UINT32 d = BSWAP32(*src++); + *(UINT32 *)&culling_ram_8e[dst] = d; + dst += 4; + } + } + else + { + for (i=0; i < length; i+=4) + { + UINT32 d = (*src++); + *(UINT32 *)&culling_ram_8e[dst] = d; + dst += 4; + } + } +} + +void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words) +{ + int i; + + dst &= 0xffffff; + + if (swap_words) + { + for (i=0; i < length; i+=4) + { + UINT32 d = BSWAP32(*src++); + *(UINT32 *) &polygon_ram[dst] = d; + dst += 4; + } + } + else + { + for (i=0; i < length; i+=4) + { + UINT32 d = (*src++); + *(UINT32 *) &polygon_ram[dst] = d; + dst += 4; + } + } +} + +void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words) +{ + int i; + + dst &= 0xffffff; + + if (swap_words) + { + for (i=0; i < length; i+=4) + { + UINT32 d = BSWAP32(*src++); + *(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d; + texture_ram_ptr += 4; + } + } + else + { + for (i=0; i < length; i+=4) + { + UINT32 d = (*src++); + *(UINT32 *)&texture_buffer_ram[texture_ram_ptr] = d; + texture_ram_ptr += 4; + } + } +} + +/******************************************************************/ +/* Real3D TAP Port */ +/******************************************************************/ + +/* + * State (corresponding to fsm[][] Y) and Instruction Names + */ + +static char *state_name[] = { "Test-Logic/Reset", "Run-Test/Idle", "Select-DR-Scan", + "Capture-DR", "Shift-DR", "Exit1-DR", "Pause-DR", + "Exit2-DR", "Update-DR", "Select-IR-Scan", + "Capture-IR", "Shift-IR", "Exit1-IR", "Pause-IR", + "Exit2-IR", "Update-IR" + }; + +/* + * TAP Finite State Machine + * + * Y are states and X are outgoing paths. Constructed from information on page + * 167 of the 3D-RAM manual. + */ + +#define NEXT(new_state) fsm[state][new_state] + +static INT state; // current state +static INT fsm[][2] = { + { 1, 0 }, // 0 Test-Logic/Reset + { 1, 2 }, // 1 Run-Test/Idle + { 3, 9 }, // 2 Select-DR-Scan + { 4, 5 }, // 3 Capture-DR + { 4, 5 }, // 4 Shift-DR + { 6, 8 }, // 5 Exit1-DR + { 6, 7 }, // 6 Pause-DR + { 4, 8 }, // 7 Exit2-DR + { 1, 2 }, // 8 Update-DR + { 10, 0 }, // 9 Select-IR-Scan + { 11, 12 }, // 10 Capture-IR + { 11, 12 }, // 11 Shift-IR + { 13, 15 }, // 12 Exit1-IR + { 13, 14 }, // 13 Pause-IR + { 11, 15 }, // 14 Exit2-IR + { 1, 2 } // 15 Update-IR + }; + +/* + * TAP Registers + */ + +static UINT64 current_instruction; // latched IR (not always equal to IR) +static UINT64 ir; // instruction register (46 bits) + +static UINT8 id_data[32]; // ASIC ID code data buffer +static INT id_size; // size of ID data in bits +static INT ptr; // current bit ptr for data + +static BOOL tdo; // bit shifted out to TDO + +/* + * insert_bit(): + * + * Inserts a bit into an arbitrarily long bit field. Bit 0 is assumed to be + * the MSB of the first byte in the buffer. + */ + +static void insert_bit(UINT8 *buf, INT bit_num, INT bit) +{ + INT bit_in_byte; + + bit_in_byte = 7 - (bit_num & 7); + + buf[bit_num / 8] &= ~(1 << bit_in_byte); + buf[bit_num / 8] |= (bit << bit_in_byte); +} + +/* + * insert_id(): + * + * Inserts a 32-bit ID code into the ID bit field. + */ + +static void insert_id(UINT32 id, INT start_bit) +{ + INT i; + + for (i = 31; i >= 0; i--) + insert_bit(id_data, start_bit++, (id >> i) & 1); +} + +/* + * shift(): + * + * Shifts the data buffer right (towards LSB at byte 0) by 1 bit. The size of + * the number of bits must be specified. The bit shifted out of the LSB is + * returned. + */ + +static BOOL shift(UINT8 *data, INT num_bits) +{ + INT i; + BOOL shift_out, shift_in; + + /* + * This loop takes care of all the fully-filled bytes + */ + + shift_in = 0; + for (i = 0; i < num_bits / 8; i++) + { + shift_out = data[i] & 1; + data[i] >>= 1; + data[i] |= (shift_in << 7); + shift_in = shift_out; // carry over to next element's MSB + } + + /* + * Take care of the last partial byte (if there is one) + */ + + if ((num_bits & 7) != 0) + { + shift_out = (data[i] >> (8 - (num_bits & 7))) & 1; + data[i] >>= 1; + data[i] |= (shift_in << 7); + } + + return shift_out; +} + +/* + * BOOL tap_read(void); + * + * Reads TDO. + * + * Returns: + * TDO. + */ + +BOOL tap_read(void) +{ + return tdo; +} + +/* + * void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst); + * + * Writes to the TAP. State changes only occur on the rising edge of the clock + * (tck = 1.) + * + * Parameters: + * tck = Clock. + * tms = Test mode select. + * tdi = Serial data input. Must be 0 or 1 only! + * trst = Reset. + */ + +void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst) +{ + if (!tck) + return; + + state = NEXT(tms); + + switch (state) + { + case 3: // Capture-DR + + /* + * Read ASIC IDs. + * + * The ID Sequence is: + * - Jupiter + * - Mercury + * - Venus + * - Earth + * - Mars + * - Mars (again) + * + * Note that different Model 3 steps have different chip + * revisions, hence the different IDs returned below. + * + * On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve + * the ID codes but Step 2.0 is a little weirder. It seems to use this + * and either the state of the TAP after reset or other instructions + * to read the IDs as well. This can be emulated in one of 2 ways: + * Ignore the instruction and always load up the data or load the + * data on TAP reset and when the instruction is issued. + */ + + if (m3_config.step == 0x10) + { + insert_id(0x116C7057, 1 + 0 * 32); + insert_id(0x216C3057, 1 + 1 * 32); + insert_id(0x116C4057, 1 + 2 * 32); + insert_id(0x216C5057, 1 + 3 * 32); + insert_id(0x116C6057, 1 + 4 * 32 + 1); + insert_id(0x116C6057, 1 + 5 * 32 + 1); + } + else if (m3_config.step == 0x15) + { + insert_id(0x316C7057, 1 + 0 * 32); + insert_id(0x316C3057, 1 + 1 * 32); + insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057 + insert_id(0x316C5057, 1 + 3 * 32); + insert_id(0x216C6057, 1 + 4 * 32 + 1); + insert_id(0x216C6057, 1 + 5 * 32 + 1); + } + else if (m3_config.step >= 0x20) + { + insert_id(0x416C7057, 1 + 0 * 32); + insert_id(0x416C3057, 1 + 1 * 32); + insert_id(0x316C4057, 1 + 2 * 32); + insert_id(0x416C5057, 1 + 3 * 32); + insert_id(0x316C6057, 1 + 4 * 32 + 1); + insert_id(0x316C6057, 1 + 5 * 32 + 1); + } + + break; + + case 4: // Shift-DR + + tdo = shift(id_data, id_size); + break; + + case 10: // Capture-IR + + /* + * Load lower 2 bits with 01 as per IEEE 1149.1-1990 + */ + + ir = 1; + break; + + case 11: // Shift-IR + + /* + * Shift IR towards output and load in new data from TDI + */ + + tdo = ir & 1; // shift LSB to output + ir >>= 1; + ir |= ((UINT64) tdi << 45); + break; + + case 15: // Update-IR + + /* + * Latch IR (technically, this should occur on the falling edge of + * TCK) + */ + + ir &= 0x3fffffffffff; + current_instruction = ir; + +#if 0 + { + UINT8 *i = (UINT8 *) &ir; + LOG("tap.log", "current instruction set: %02X%02X%02X%02X%02X%02X\n", i[5], i[4], i[3], i[2], i[1], i[0]); + } +#endif + + break; + + default: + break; + } + +#if 0 + if (state == 4) + LOG("tap.log", "state: Shift-DR %d\n", tdi); + else if (state == 11) + LOG("tap.log", "state: Shift-IR %d\n", tdi); + else + LOG("tap.log", "state: %s\n", state_name[state]); +#endif +} + + +/* + * void tap_reset(void); + * + * Resets the TAP (simulating a power up or SCAN_RST signal.) + */ + +void tap_reset(void) +{ + id_size = 197; // 197 bits + + state = 0; // test-logic/reset +} diff --git a/core/r3d.h b/core/r3d.h new file mode 100644 index 0000000..21b19d0 --- /dev/null +++ b/core/r3d.h @@ -0,0 +1,49 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * r3d.h + * + * Real3D Model 3 graphics system header. + */ + +#ifndef INCLUDED_R3D_H +#define INCLUDED_R3D_H + +extern void r3d_init(UINT8 *, UINT8 *, UINT8 *, UINT8 *, UINT8 *); +extern void r3d_shutdown(void); +extern void r3d_reset(void); + +extern void r3d_save_state(FILE *); +extern void r3d_load_state(FILE *); + +extern UINT32 r3d_read_32(UINT32 a); +extern void r3d_write_32(UINT32 a, UINT32 d); + +extern void r3d_dma_culling_ram_8c(UINT32 *src, UINT32 dst, int length, BOOL swap_words); +extern void r3d_dma_culling_ram_8e(UINT32 *src, UINT32 dst, int length, BOOL swap_words); +extern void r3d_dma_polygon_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words); +extern void r3d_dma_texture_ram(UINT32 *src, UINT32 dst, int length, BOOL swap_words); + + +extern void tap_reset(void); +extern BOOL tap_read(void); +extern void tap_write(BOOL tck, BOOL tms, BOOL tdi, BOOL trst); + +#endif // INCLUDED_R3D_H + diff --git a/core/render.c b/core/render.c new file mode 100644 index 0000000..82b92e0 --- /dev/null +++ b/core/render.c @@ -0,0 +1,823 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * render.c + * + * Rendering engine. Responsible for both Real3D graphics emulation and + * for drawing the tile layers with correct priorities. + * + * NOTES: + * ------ + * + * - The "hardware coordinate system" is the default Model 3 coordinate system + * before any matrices are applied. In it, +X is to the right, +Y is down, + * and +Z is further into the screen. + */ + +#include "model3.h" + +extern BOOL render_scene(void); + +#define LOG_MODEL_ADDR 0 // logs model addresses to models.log + +/******************************************************************/ +/* Useful Macros */ +/******************************************************************/ + +/* + * Single-Precision Floating Point + */ + +#define GET_FLOAT(ptr) (*((float *) ptr)) + +/* + * Trigonometry + */ + +#define PI 3.14159265358979323846264338327 +#define CONVERT_TO_DEGREES(a) (((a) * 180.0) / PI) + +/******************************************************************/ +/* Private Data */ +/******************************************************************/ + +/* + * Memory Regions + * + * These will be passed to us before rendering begins. + */ + +static UINT8 *culling_ram_8e; // pointer to Real3D culling RAM +static UINT8 *culling_ram_8c; // pointer to Real3D culling RAM +static UINT8 *polygon_ram; // pointer to Real3D polygon RAM +static UINT8 *texture_ram; // pointer to Real3D texture RAM +static UINT8 *vrom; // pointer to VROM + +/* + * Matrix Base + */ + +static float *matrix_base; // current scene's matrix table +static float *lod_base; // current scene's LOD table + +/* + * Matrix Conversion Tables + * + * These tables map Model 3 matrix indices to column-major form. + */ + +static INT normal_matrix[4*4] = // normal matrices + { + 3*4+0, 3*4+1, 3*4+2, + 0*4+0, 1*4+0, 2*4+0, + 0*4+1, 1*4+1, 2*4+1, + 0*4+2, 1*4+2, 2*4+2 + }; +static INT coord_matrix[4*4] = // coordinate system matrix + { + 3*4+2, 3*4+0, 3*4+1, + 0*4+2, 1*4+2, 2*4+2, + 0*4+0, 1*4+0, 2*4+0, + 0*4+1, 1*4+1, 2*4+1 + }; + +/******************************************************************/ +/* Function Prototypes */ +/******************************************************************/ + +static void draw_block(UINT32 *); + +/******************************************************************/ +/* TEMPORARY Model Tracking Code */ +/* */ +/* This code builds a list of VROM model addresses as they are */ +/* referenced. */ +/******************************************************************/ + +#if LOG_MODEL_ADDR + +static struct model_addr +{ + UINT32 addr; // model address in VROM + INT num_polys; // number of polygons in model + struct model_addr *next; // next in list +} *model_addr_list = NULL; + +static INT count_polys(UINT32 *mdl) +{ + UINT32 link_data, mask; + INT num_polys = 0, num_verts, i, stop; + + do + { + stop = BSWAP32(mdl[1]) & 4; // get stop bit + link_data = BSWAP32(mdl[0]); // link data + + /* + * Count how many vertices the polygon has by subtracting the number + * of vertices used from the previous polygon from 4 (quad) or 3 (tri) + */ + + num_verts = (link_data & 0x40) ? 4 : 3; + mask = 8; + for (i = 0; i < 4 && num_verts; i++) + { + if ((link_data & mask)) + --num_verts; + mask >>= 1; + } + + /* + * Advance to next polygon + */ + + mdl += 7 + num_verts * 4; + ++num_polys; // increment count + } while (!stop); + + return num_polys; +} + +static void record_model(UINT32 addr) +{ + struct model_addr *l; + + /* + * Search for this entry -- if already in the list, exit + for (l = model_addr_list; l != NULL; l = l->next) + { + if (addr == l->addr) + return; + } + + /* + * Add new entry + */ + + l = malloc(sizeof(struct model_addr)); + if (l == NULL) + error("out of memory in record_model()"); + l->addr = addr; + l->num_polys = count_polys((UINT32 *) &vrom[addr * 4]); + l->next = model_addr_list; + model_addr_list = l; +} + +#endif + +/******************************************************************/ +/* Real3D Address Translation */ +/******************************************************************/ + +/* + * translate_scene_graph_address(): + * + * Returns a pointer to scene graph (culling RAM) memory given a scene graph + * address (only lower 24 bits are relevant.) + */ + +static UINT32 *translate_scene_graph_address(UINT32 addr) +{ + addr &= 0x00FFFFFF; // only lower 24 bits matter + if ((addr & 0x00800000)) // 8E culling RAM + { + if (addr >= 0x00840000) + error("translate_scene_graph_address(): addr = %08X", addr); + return (UINT32 *) &culling_ram_8e[(addr & 0x0003FFFF) * 4]; + } + else // 8C culling RAM + { + if (addr >= 0x00100000) + error("translate_scene_graph_address(): addr = %08X", addr); + return (UINT32 *) &culling_ram_8c[(addr & 0x000FFFFF) * 4]; + } +} + +/* + * draw_model(): + * + * Translates the model address and draws the model (accounting for + * endianness.) + */ + +static void draw_model(UINT32 addr) +{ + addr &= 0x00FFFFFF; // only lower 24 bits matter + if (addr > 0x00100000) // VROM + { +#if LOG_MODEL_ADDR + record_model(addr); // TEMP: this tracks model addresses in VROM +#endif + osd_renderer_draw_model((UINT32 *) &vrom[(addr & 0x00FFFFFF) * 4], addr, 0); + } + else // polygon RAM (may actually be 4MB) + { + osd_renderer_draw_model((UINT32 *) &polygon_ram[(addr & 0x000FFFFF) * 4], addr, 1); + } +} + +/******************************************************************/ +/* Matrices */ +/* */ +/* Model 3 matrices are 4x3 in size (they lack the translational */ +/* component.) They are layed out like this: */ +/* */ +/* 03 04 05 00 */ +/* 06 07 08 01 */ +/* 09 10 11 02 */ +/* */ +/* Matrix #0 is for coordinate system selection, it is layed out */ +/* as: */ +/* */ +/* 06 07 08 01 */ +/* 09 10 11 02 */ +/* 03 04 05 00 */ +/* */ +/* By default, the Model 3 appears to have a form of left-handed */ +/* coordinate system where positive Z means further away from the */ +/* camera and the positive Y axis points downward along the */ +/* screen. */ +/******************************************************************/ + +/* + * get_matrix(): + * + * Reads a Model 3 matrix and converts it to column-major 4x4 form using the + * supplied conversion table. + */ + +static void get_matrix(MATRIX dest, INT convert[3*4], UINT num) +{ + INT m = num * 12, i; + + for (i = 0; i < 3*4; i++) // fetch Model 3 4x3 matrix + dest[convert[i]] = matrix_base[m + i]; + dest[0*4+3] = 0.0; // fill in translation component to make 4x4 + dest[1*4+3] = 0.0; + dest[2*4+3] = 0.0; + dest[3*4+3] = 1.0; +} + + +/******************************************************************/ +/* Scene Graph Traversal */ +/******************************************************************/ + +int list_depth = 0; + +/* + * draw_list(): + * + * Processes a list backwards. Each list element references a block. + */ + +static void draw_list(UINT32 *list) +{ + UINT32 *list_ptr; + UINT32 addr; + + list_ptr = list; + + if (list_depth > 2) + return; + + list_depth++; + + /* + * Go to end of list + */ + + while (1) + { + addr = *list_ptr; + if ((addr & 0x02000000)) // last pointer in list + { + //--list_ptr; + break; + } + if (addr == 0 || addr == 0x800800) // safeguard in case memory hasn't been set up + { + --list_ptr; + break; + } + ++list_ptr; + } + + while (list_ptr >= list) + { + addr = *list_ptr; + if ((addr & 0x00FFFFFF) != 0x00FFFFFF) + draw_block(translate_scene_graph_address(addr)); + --list_ptr; // next element + } + + list_depth--; +} + +/* + * draw_pointer_list(): + * + * Draws a 4-element pointer list for model LOD selection. + */ + +static void draw_pointer_list(UINT lod_num, UINT32* list) +{ + float *lod_control = (float *)((UINT32)lod_base + lod_num * 8); + + /* + * Perform the actual LOD calculation, select the LOD model + * to draw -- and perform additional LOD blending. + */ + + #if 0 + printf( "LOD control = %f, %f\n" + " %f, %f\n" + " %f, %f\n" + " %f, %f\n", + lod_control[0], lod_control[1], + lod_control[2], lod_control[3], + lod_control[4], lod_control[5], + lod_control[6], lod_control[7] + ); + #endif + + if(1) + draw_model( list[0] ); + else if(0) + draw_model( list[1] ); + else if(0) + draw_model( list[2] ); + else + draw_model( list[3] ); +} + +/* + * draw_block(): + * + * Traverses a 10- (or 8-) word block (culling node.) The blocks have this + * format: + * + * 0: ID code (upper 22 bits) and control bits + * 1: Scaling? Not present in Step 1.0 + * 2: Flags? Not present in Step 1.0 + * 3: Lower 12 bits are matrix select. Upper bits contain flags. + * 4: X translation (floating point) + * 5: Y translation + * 6: Z translation + * 7: Pointer to model data, list, or pointer list + * 8: Pointer to next block + * 9: Pair of 16-bit values, related to rendering order + * + * Lower 16 bits of word 2 control "texture offset": -P-X XXXX X--Y YYYY, same + * as in polygon headers. The purpose of this is unknown. + */ + +static void draw_block(UINT32 *block) +{ + MATRIX m; + UINT32 addr; + INT offset; + INT txoffs_x, txoffs_y, txoffs_page; + + if (m3_config.step == 0x10) // Step 1.0 blocks are only 8 words + offset = 2; + else + offset = 0; + + addr = block[7 - offset]; + + txoffs_x = ((block[2] >> 7) & 0x3F) * 32; + txoffs_y = (block[2] & 0x1F) * 32; + txoffs_page = !!(block[2] & 0x4000); + + /* + * Apply matrix and translation + */ + + get_matrix(m, normal_matrix, block[3 - offset] & 0xFFF); + osd_renderer_push_matrix(); + + if ((block[0] & 0x10)) // this bit appears to control translation + { + osd_renderer_translate_matrix(GET_FLOAT(&block[4 - offset]), GET_FLOAT(&block[5 - offset]), GET_FLOAT(&block[6 - offset])); + } + else + { + if ((block[3 - offset] & 0xFFF) != 0) + osd_renderer_multiply_matrix(m); + } + + /* + * Bit 0x08 of word 0 indicates a pointer list + */ + + if ((block[0] & 0x08)) + draw_pointer_list((block[3 - offset] >> 12) & 127, translate_scene_graph_address(addr)); + else + { + if (addr != 0x0FFFFFFF && addr != 0x01000000 && addr != 0x00800800 && addr != 0) // valid? + { + switch ((addr >> 24) & 0xFF) // decide what address points to + { + case 0x00: // block + draw_block(translate_scene_graph_address(addr)); + break; + case 0x01: // model + case 0x03: // model (Scud Race, model in VROM) + draw_model(addr); + break; + case 0x04: // list + draw_list(translate_scene_graph_address(addr)); + break; + default: + break; + } + } + } + + osd_renderer_pop_matrix(); + + /* + * NOTE: This second pointer needs to be investigated further. + */ + + addr = block[8 - offset]; + if (addr != 0x01000000 && addr != 0x00800800 && addr != 0) // valid? + draw_block(translate_scene_graph_address(addr)); +} + +/* + * get_viewport_data(): + * + * Sets up a VIEWPORT structure. Is passed a pointer to the main node. + */ + +static void get_viewport_data(VIEWPORT *vp, UINT32 *node) +{ + vp->x = (node[0x1A] & 0xFFFF) >> 4; // position is in 12.4 format + vp->y = (node[0x1A] >> 16) >> 4; + vp->width = (node[0x14] & 0xFFFF) >> 2; // size is in 14.2 format + vp->height = (node[0x14] >> 16) >> 2; + + vp->left = asin(GET_FLOAT(&node[0x0C])); + vp->right = asin(GET_FLOAT(&node[0x10])); + vp->up = asin(GET_FLOAT(&node[0x0E])); + vp->down = asin(GET_FLOAT(&node[0x12])); + + vp->left = CONVERT_TO_DEGREES(vp->left); + vp->right = CONVERT_TO_DEGREES(vp->right); + vp->up = CONVERT_TO_DEGREES(vp->up); + vp->down = CONVERT_TO_DEGREES(vp->down); +} + +/* + * get_light_data(): + * + * Sets up a LIGHT structure based on ambient sun light. The sun vector + * indicates the direction of the parallel sun light. It is specified in the + * hardware coordinate system and must be applied before any matrices. + */ + +static void get_light_data(LIGHT* l, UINT32* node) +{ + memset( l, 0, sizeof(LIGHT) ); + l->u = GET_FLOAT(&node[5]); // it seems X needs to be inverted + l->v = GET_FLOAT(&node[6]); + l->w = GET_FLOAT(&node[4]); + + l->diffuse_intensity = GET_FLOAT(&node[7]); + l->ambient_intensity = (UINT8)((node[0x24] >> 8) & 0xFF) / 256.0f; + + LOG("model3.log", "sun light = (%f,%f,%f),%f,(%02X=%f)\n", l->u, l->v, l->w, l->diffuse_intensity, ((node[0x24] >> 8) & 0xFF), l->ambient_intensity); + + l->color = 0xFFFFFFFF; + + +} + +/* + * draw_viewport(): + * + * Traverses the main (scene descriptor) nodes and draws the ones with the + * given viewport priority. + */ + +static void draw_viewport(UINT pri, UINT32 addr) +{ + MATRIX m; + VIEWPORT vp; + LIGHT sun; + UINT32 *node; + UINT32 next_addr, ptr; + + node = translate_scene_graph_address(addr); + + /* + * Recurse until the last node has been reached + */ + + next_addr = node[1]; + if (next_addr == 0) // culling RAM probably hasn't been set up yet... + return; + if (next_addr != 0x01000000) + draw_viewport(pri, next_addr); + + /* + * Draw this node if the priority matches + */ + + if (pri == ((node[0] >> 3) & 3)) + { + /* + * Set up viewport and matrix table base + */ + + get_viewport_data(&vp, node); + osd_renderer_set_viewport(&vp); + matrix_base = (float *) translate_scene_graph_address(node[0x16]); + lod_base = (float *) translate_scene_graph_address(node[0x17]); + + /* + * Lighting -- seems to work nice if applied before coordinate system + * selection but I haven't done a thorough check. + */ + + get_light_data(&sun, node); + sun.type = LIGHT_PARALLEL; + osd_renderer_set_light( 0, &sun ); + + /* + * Set coordinate system (matrix 0) + */ + + get_matrix(m, coord_matrix, 0); + osd_renderer_set_coordinate_system(m); + + /* + * Process a block or list. So far, no other possibilities have been + * seen here... + */ + + ptr = node[2]; + + switch ((ptr >> 24) & 0xFF) + { + case 0x00: // block + draw_block(translate_scene_graph_address(node[2])); + break; + //case 0x04: // list + // draw_list(translate_scene_graph_address(node[2])); + // break; + default: // unknown + break; + } + } +} + + +/******************************************************************/ +/* Frame Update */ +/******************************************************************/ + +/* + * do_3d(): + * + * Draw the complete Real3D frame. + */ + +static void do_3d(void) +{ + INT i; + + + for (i = 0; i < 4; i++) + { + osd_renderer_clear(0, 1); // clear Z-buffer + osd_renderer_begin_3d_scene(); + draw_viewport(i, 0x00800000); + osd_renderer_end_3d_scene(); + + LOG("model3.log", "GOT HERE\n"); + } +} + +/* + * void set_color_offset(UINT32 reg); + * + * Sets color offset to the value specified by reg, and updates the + * renderer status. + */ + +static void set_color_offset(UINT32 reg) +{ + FLOAT32 r, g, b; + + /* + * Color offset is specified as a triplet of signed 8-bit values, one + * for each color component. 0 is the default value, it doesn't modify + * the output color. It's equal to disabling the color offset (though + * some bit in the tilegen ports could be used for this). + * 0x80 (-128) is the minimum value, and corresponds to complete black. + * 0x7F (+127) is the maximum value, and corresponds to complete white. + */ + + r = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 8) & 0xFF))) / 128.0f; + g = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 16) & 0xFF))) / 128.0f; + b = (FLOAT32)((INT32)((INT8)(((INT32)reg >> 24) & 0xFF))) / 128.0f; + +// osd_renderer_set_color_offset(r != 0.0f && g != 0.0f && b != 0.0f, r, g, b); +} + +/* + * void render_frame(void); + * + * Draws the entire frame (all 3D and 2D graphics) and blits it. + */ + +void render_frame(void) +{ + int i, j; + UINT32 color_offset; + LONGLONG counter_start, counter_end, counter_frequency; + LOG("model3.log", "RENDER START\n"); + + QueryPerformanceFrequency((LARGE_INTEGER*)&counter_frequency); + + tilegen_update(); + + { + UINT32 *priority = tilegen_get_priority_buffer(); + + for (i=0; i < 4; i++) + { + int pitch; + UINT8 *buffer; + osd_renderer_get_priority_buffer(i, &buffer, &pitch); + + for (j=0; j < 512; j++) + { + if (tilegen_is_priority_enabled()) + { + buffer[j*pitch] = (priority[j] >> ((3-i) * 8)) & 0xff; + } + else + { + if (i < 2) buffer[j*pitch] = 0xff; + else buffer[j*pitch] = 0x00; + } + } + + osd_renderer_free_priority_buffer(i); + } + } + + + osd_renderer_clear(1, 1); // clear both the frame and Z-buffer + +// set_color_offset(tilegen_read_32(0x44)); + + /*if (tilegen_is_layer_enabled(3)) + { + UINT32 scroll = tilegen_get_layer_scroll_pos(3); + color_offset = tilegen_get_layer_color_offset(3); + osd_renderer_draw_layer(3, color_offset, scroll & 0xffff, scroll >> 16); + } + if (tilegen_is_layer_enabled(2)) + { + UINT32 scroll = tilegen_get_layer_scroll_pos(2); + color_offset = tilegen_get_layer_color_offset(2); + osd_renderer_draw_layer(2, color_offset, scroll & 0xffff, scroll >> 16); + }*/ + + for (i=3; i >= 0; i--) + { + if (tilegen_is_layer_enabled(i)) + { + UINT32 scroll = tilegen_get_layer_scroll_pos(i); + color_offset = tilegen_get_layer_color_offset(i); + osd_renderer_draw_layer(i, color_offset, scroll & 0xffff, scroll >> 16, FALSE); + } + } + + QueryPerformanceCounter((LARGE_INTEGER*)&counter_start); + + do_3d(); + + QueryPerformanceCounter((LARGE_INTEGER*)&counter_end); + + for (i=3; i >= 0; i--) + { + if (tilegen_is_layer_enabled(i)) + { + UINT32 scroll = tilegen_get_layer_scroll_pos(i); + color_offset = tilegen_get_layer_color_offset(i); + osd_renderer_draw_layer(i, color_offset, scroll & 0xffff, scroll >> 16, TRUE); + } + } + + /*{ + double time = (double)(counter_end - counter_start) / (double)counter_frequency; + printf("Rendering time: %f ms\n", time*1000.0); + }*/ + +// set_color_offset(tilegen_read_32(0x40)); + + // osd_renderer_draw_layer(1); + + /*if (tilegen_is_layer_enabled(1)) + { + UINT32 scroll = tilegen_get_layer_scroll_pos(1); + color_offset = tilegen_get_layer_color_offset(1); + osd_renderer_draw_layer(1, color_offset, scroll & 0xffff, scroll >> 16); + } + if (tilegen_is_layer_enabled(0)) + { + UINT32 scroll = tilegen_get_layer_scroll_pos(0); + color_offset = tilegen_get_layer_color_offset(0); + osd_renderer_draw_layer(0, color_offset, scroll & 0xffff, scroll >> 16); + }*/ + + LOG("model3.log", "RENDER END\n"); +} + + +/******************************************************************/ +/* Initialization and Shutdown */ +/******************************************************************/ + +/* + * void render_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr, + * UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, + * UINT8 *vrom_ptr); + * + * Initializes the renderer by receiving the Real3D memory regions. Passes + * the memory to the OSD renderer. + * + * Parameters: + * culling_ram_8e_ptr = Pointer to Real3D culling RAM at 0x8E000000. + * culling_ram_8c_ptr = Pointer to Real3D culling RAM at 0x8C000000. + * polygon_ram_ptr = Pointer to Real3D polygon RAM. + * texture_ram_ptr = Pointer to Real3D texture RAM. + * vrom_ptr = Pointer to VROM. + */ + +void render_init(UINT8 *culling_ram_8e_ptr, UINT8 *culling_ram_8c_ptr, + UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, + UINT8 *vrom_ptr) +{ + culling_ram_8e = culling_ram_8e_ptr; + culling_ram_8c = culling_ram_8c_ptr; + polygon_ram = polygon_ram_ptr; + texture_ram = texture_ram_ptr; + vrom = vrom_ptr; +} + +/* + * void render_shutdown(void); + * + * Shuts down the rendering engine. + */ + +void render_shutdown(void) +{ +#if LOG_MODEL_ADDR + // TEMP code to print out model list + + FILE *fp; + struct model_addr *l, *next; + + fp = fopen("models.log", "w"); + if (fp == NULL) + { + printf("failed to write models.log\n"); + return; + } + + l = model_addr_list; + while (l != NULL) + { + fprintf(fp, "addr = %08X\tnum_polys = %d\n", l->addr, l->num_polys); + next = l->next; + free(l); + l = next; + } + + fclose(fp); +#endif +} diff --git a/core/render.h b/core/render.h new file mode 100644 index 0000000..e54bac2 --- /dev/null +++ b/core/render.h @@ -0,0 +1,86 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * render.h + * + * Rendering engine header. OSD renderers will want to include this because + * some important data structures are defined here. + */ + +#ifndef INCLUDED_RENDER_H +#define INCLUDED_RENDER_H + +/******************************************************************/ +/* Data Structures */ +/******************************************************************/ + +/* + * MATRIX + * + * A 4x4 matrix stored in column-major (OpenGL) format. + */ + +typedef float MATRIX [4*4]; + +/* + * VIEWPORT + * + * Viewport and projection data. The field-of-view angles are in degrees. The + * coordinates and size of the viewport are truncated from Model 3's fixed- + * point formats to integers. + * + * The viewport coordinate system maps directly to the Model 3's physical + * resolution and its origin is at the bottom-left corner of the screen. + */ + +typedef struct +{ + UINT x, y, width, height; // viewport position and size. + double up, down, left, right; // FOV angles from center +} VIEWPORT; + +/* + * LIGHT + */ + +enum { + LIGHT_PARALLEL, + LIGHT_POSITIONAL, + LIGHT_SPOT +}; + +typedef struct +{ + UINT type; + float u,v,w; // Direction vector + float x,y,z; // Position for point light + float diffuse_intensity; + float ambient_intensity; + UINT32 color; +} LIGHT; + +/******************************************************************/ +/* Functions */ +/******************************************************************/ + +extern void render_frame(void); +extern void render_init(UINT8 *, UINT8 *, UINT8 *, UINT8 *, UINT8 *); +extern void render_shutdown(void); + +#endif // INCLUDED_RENDER_H diff --git a/core/romparse.c b/core/romparse.c new file mode 100644 index 0000000..d1cd22d --- /dev/null +++ b/core/romparse.c @@ -0,0 +1,604 @@ +#include "model3.h" +#include "expat.h" + +enum +{ + ELEMENT_NONE = 1, + ELEMENT_GAMELIST, + ELEMENT_GAME, + ELEMENT_DESCRIPTION, + ELEMENT_YEAR, + ELEMENT_MANUFACTURER, + ELEMENT_STEP, + ELEMENT_CROMSIZE, + ELEMENT_ROM, + ELEMENT_PATCH, + ELEMENT_BRIDGE, + ELEMENT_INPUT, +}; + +enum +{ + ATTR_ROM_TYPE = 1, + ATTR_ROM_NAME, + ATTR_ROM_SIZE, + ATTR_ROM_CRC, + ATTR_ROM_SHA1, + ATTR_GAME_NAME, + ATTR_GAME_PARENT, + ATTR_PATCH_SIZE, + ATTR_PATCH_ADDRESS, + ATTR_PATCH_DATA, + ATTR_INPUT_TYPE, + ATTR_INPUT_CENTER, + ATTR_INPUT_MAPPING, +}; + +static STRING_ID element_id[] = +{ + { "gamelist", ELEMENT_GAMELIST }, + { "game", ELEMENT_GAME }, + { "description", ELEMENT_DESCRIPTION }, + { "year", ELEMENT_YEAR }, + { "manufacturer", ELEMENT_MANUFACTURER }, + { "step", ELEMENT_STEP }, + { "cromsize", ELEMENT_CROMSIZE }, + { "rom", ELEMENT_ROM }, + { "patch", ELEMENT_PATCH }, + { "bridge", ELEMENT_BRIDGE }, + { "input", ELEMENT_INPUT }, + { "", 0 }, +}; + +static STRING_ID rom_attr_id[] = +{ + { "type", ATTR_ROM_TYPE }, + { "name", ATTR_ROM_NAME }, + { "size", ATTR_ROM_SIZE }, + { "crc", ATTR_ROM_CRC }, + { "sha1", ATTR_ROM_SHA1 }, + { "", 0 }, +}; + +static STRING_ID game_attr_id[] = +{ + { "name", ATTR_GAME_NAME }, + { "parent", ATTR_GAME_PARENT }, + { "", 0 }, +}; + +static STRING_ID patch_attr_id[] = +{ + { "size", ATTR_PATCH_SIZE }, + { "address", ATTR_PATCH_ADDRESS }, + { "data", ATTR_PATCH_DATA }, + { "", 0 }, +}; + +static STRING_ID input_attr_id[] = +{ + { "type", ATTR_INPUT_TYPE }, + { "center", ATTR_INPUT_CENTER }, + { "mapping", ATTR_INPUT_MAPPING }, + { "", 0 }, +}; + +static STRING_ID step_id[] = +{ + { "1.0", 0x10 }, + { "1.5", 0x15 }, + { "2.0", 0x20 }, + { "2.1", 0x21 }, + { "", 0 }, +}; + +static STRING_ID rom_id[] = +{ + { "prog0", ROMTYPE_PROG0 }, + { "prog1", ROMTYPE_PROG1 }, + { "prog2", ROMTYPE_PROG2 }, + { "prog3", ROMTYPE_PROG3 }, + { "crom00", ROMTYPE_CROM00 }, + { "crom01", ROMTYPE_CROM01 }, + { "crom02", ROMTYPE_CROM02 }, + { "crom03", ROMTYPE_CROM03 }, + { "crom10", ROMTYPE_CROM10 }, + { "crom11", ROMTYPE_CROM11 }, + { "crom12", ROMTYPE_CROM12 }, + { "crom13", ROMTYPE_CROM13 }, + { "crom20", ROMTYPE_CROM20 }, + { "crom21", ROMTYPE_CROM21 }, + { "crom22", ROMTYPE_CROM22 }, + { "crom23", ROMTYPE_CROM23 }, + { "crom30", ROMTYPE_CROM30 }, + { "crom31", ROMTYPE_CROM31 }, + { "crom32", ROMTYPE_CROM32 }, + { "crom33", ROMTYPE_CROM33 }, + { "vrom00", ROMTYPE_VROM00 }, + { "vrom01", ROMTYPE_VROM01 }, + { "vrom02", ROMTYPE_VROM02 }, + { "vrom03", ROMTYPE_VROM03 }, + { "vrom04", ROMTYPE_VROM04 }, + { "vrom05", ROMTYPE_VROM05 }, + { "vrom06", ROMTYPE_VROM06 }, + { "vrom07", ROMTYPE_VROM07 }, + { "vrom10", ROMTYPE_VROM10 }, + { "vrom11", ROMTYPE_VROM11 }, + { "vrom12", ROMTYPE_VROM12 }, + { "vrom13", ROMTYPE_VROM13 }, + { "vrom14", ROMTYPE_VROM14 }, + { "vrom15", ROMTYPE_VROM15 }, + { "vrom16", ROMTYPE_VROM16 }, + { "vrom17", ROMTYPE_VROM17 }, + { "sprog", ROMTYPE_SPROG }, + { "srom0", ROMTYPE_SROM0 }, + { "srom1", ROMTYPE_SROM1 }, + { "srom2", ROMTYPE_SROM2 }, + { "srom3", ROMTYPE_SROM3 }, + { "dsbprog", ROMTYPE_DSBPROG }, + { "dsbrom0", ROMTYPE_DSBROM0 }, + { "dsbrom1", ROMTYPE_DSBROM1 }, + { "dsbrom2", ROMTYPE_DSBROM2 }, + { "dsbrom3", ROMTYPE_DSBROM3 }, + { "", 0 }, +}; + +#define INPUT_TYPE_BUTTON 0x10000 +#define INPUT_TYPE_ANALOG 0x20000 + +static STRING_ID input_id[] = +{ + { "button01", INPUT_TYPE_BUTTON | 0 }, + { "button02", INPUT_TYPE_BUTTON | 1 }, + { "button03", INPUT_TYPE_BUTTON | 2 }, + { "button04", INPUT_TYPE_BUTTON | 3 }, + { "button05", INPUT_TYPE_BUTTON | 4 }, + { "button06", INPUT_TYPE_BUTTON | 5 }, + { "button07", INPUT_TYPE_BUTTON | 6 }, + { "button08", INPUT_TYPE_BUTTON | 7 }, + { "button11", INPUT_TYPE_BUTTON | 8 }, + { "button12", INPUT_TYPE_BUTTON | 9 }, + { "button13", INPUT_TYPE_BUTTON | 10 }, + { "button14", INPUT_TYPE_BUTTON | 11 }, + { "button15", INPUT_TYPE_BUTTON | 12 }, + { "button16", INPUT_TYPE_BUTTON | 13 }, + { "button17", INPUT_TYPE_BUTTON | 14 }, + { "button18", INPUT_TYPE_BUTTON | 15 }, + { "analog1", INPUT_TYPE_ANALOG | 0 }, + { "analog2", INPUT_TYPE_ANALOG | 1 }, + { "analog3", INPUT_TYPE_ANALOG | 2 }, + { "analog4", INPUT_TYPE_ANALOG | 3 }, + { "analog5", INPUT_TYPE_ANALOG | 4 }, + { "analog6", INPUT_TYPE_ANALOG | 5 }, + { "analog7", INPUT_TYPE_ANALOG | 6 }, + { "analog8", INPUT_TYPE_ANALOG | 7 }, + { "", 0 }, +}; + +static STRING_ID input_mapping_id[] = +{ + { "p1_button_1", P1_BUTTON_1 }, + { "p1_button_2", P1_BUTTON_2 }, + { "p1_button_3", P1_BUTTON_3 }, + { "p1_button_4", P1_BUTTON_4 }, + { "p1_button_5", P1_BUTTON_5 }, + { "p1_button_6", P1_BUTTON_6 }, + { "p1_button_7", P1_BUTTON_7 }, + { "p1_button_8", P1_BUTTON_8 }, + { "p2_button_1", P2_BUTTON_1 }, + { "p2_button_2", P2_BUTTON_2 }, + { "p2_button_3", P2_BUTTON_3 }, + { "p2_button_4", P2_BUTTON_4 }, + { "p2_button_5", P2_BUTTON_5 }, + { "p2_button_6", P2_BUTTON_6 }, + { "p2_button_7", P2_BUTTON_7 }, + { "p2_button_8", P2_BUTTON_8 }, + { "analog_axis_1", ANALOG_AXIS_1 }, + { "analog_axis_2", ANALOG_AXIS_2 }, + { "analog_axis_3", ANALOG_AXIS_3 }, + { "analog_axis_4", ANALOG_AXIS_4 }, + { "analog_axis_5", ANALOG_AXIS_5 }, + { "analog_axis_6", ANALOG_AXIS_6 }, + { "analog_axis_7", ANALOG_AXIS_7 }, + { "analog_axis_8", ANALOG_AXIS_8 }, + { "p1_joystick_up", P1_JOYSTICK_UP }, + { "p1_joystick_down", P1_JOYSTICK_DOWN }, + { "p1_joystick_left", P1_JOYSTICK_LEFT }, + { "p1_joystick_right", P1_JOYSTICK_RIGHT }, + { "p2_joystick_up", P2_JOYSTICK_UP }, + { "p2_joystick_down", P2_JOYSTICK_DOWN }, + { "p2_joystick_left", P2_JOYSTICK_LEFT }, + { "p2_joystick_right", P2_JOYSTICK_RIGHT }, + { "", 0 }, +}; + + + +static UINT8 *romlist; + +static ROMSET *romset; + +static int current_attr; +static int current_element; + +static int current_rom; +static int current_romset; +static int current_patch; +static int current_input; + + + +static void XMLCALL element_start(void *data, const char *el, const char **attr) +{ + int element = get_string_id(el, element_id); + + if (element < 0) + { + message(0, "Unknown element %s while parsing XML file\n", el); + } + else + { + current_element = element; + + switch (element) + { + case ELEMENT_ROM: + { + int i=0; + + // handle ROM types + while (attr[i] != NULL) + { + int id = get_string_id(attr[i], rom_attr_id); + + if (id >= 0) + { + current_attr = id; + } + else + { + // not a type + switch (current_attr) + { + case ATTR_ROM_TYPE: + { + int romtype = get_string_id(attr[i], rom_id); + romset[current_romset].rom[current_rom].type = romtype; + break; + } + case ATTR_ROM_NAME: + { + strcpy(romset[current_romset].rom[current_rom].name, attr[i]); + break; + } + case ATTR_ROM_SIZE: + { + int romsize; + sscanf(attr[i], "%d", &romsize); + romset[current_romset].rom[current_rom].size = romsize; + break; + } + case ATTR_ROM_CRC: + { + UINT32 romcrc; + sscanf(attr[i], "%X", &romcrc); + romset[current_romset].rom[current_rom].crc32 = romcrc; + break; + } + case ATTR_ROM_SHA1: + { + // not handled + break; + } + } + } + i++; + }; + break; + } + + case ELEMENT_GAME: + { + int i=0; + + while (attr[i] != NULL) + { + int id = get_string_id(attr[i], game_attr_id); + + if (id >= 0) + { + current_attr = id; + } + else + { + switch (current_attr) + { + case ATTR_GAME_NAME: + { + strcpy(romset[current_romset].game, attr[i]); + break; + } + case ATTR_GAME_PARENT: + { + strcpy(romset[current_romset].parent, attr[i]); + break; + } + } + } + i++; + }; + break; + } + + case ELEMENT_PATCH: + { + int i=0; + + while (attr[i] != NULL) + { + int id = get_string_id(attr[i], patch_attr_id); + + if (id >= 0) + { + current_attr = id; + } + else + { + switch (current_attr) + { + case ATTR_PATCH_SIZE: + { + int patch_size; + sscanf(attr[i], "%d", &patch_size); + romset[current_romset].patch[current_patch].size = patch_size; + break; + } + case ATTR_PATCH_ADDRESS: + { + UINT32 address; + sscanf(attr[i], "%X", &address); + romset[current_romset].patch[current_patch].address = address; + break; + } + case ATTR_PATCH_DATA: + { + UINT32 data; + sscanf(attr[i], "%X", &data); + romset[current_romset].patch[current_patch].data = data; + break; + } + } + } + i++; + }; + break; + } + + case ELEMENT_INPUT: + { + int i=0; + + while (attr[i] != NULL) + { + int id = get_string_id(attr[i], input_attr_id); + + if (id >= 0) + { + current_attr = id; + } + else + { + switch (current_attr) + { + case ATTR_INPUT_TYPE: + { + current_input = get_string_id(attr[i], input_id); + + if (current_input & INPUT_TYPE_BUTTON) + { + int button = current_input & 0xffff; + int set = (button / 8) & 1; + int bit = 1 << (button % 8); + romset[current_romset].controls.button[button].enabled = 1; + romset[current_romset].controls.button[button].control_set = set; + romset[current_romset].controls.button[button].control_bit = bit; + } + else if (current_input & INPUT_TYPE_ANALOG) + { + int axis = current_input & 0xffff; + romset[current_romset].controls.analog_axis[axis].enabled = 1; + } + break; + } + case ATTR_INPUT_CENTER: + { + if (current_input & INPUT_TYPE_ANALOG) + { + int axis = current_input & 0xffff; + int center; + sscanf(attr[i], "%d", ¢er); + romset[current_romset].controls.analog_axis[axis].center = center; + } + break; + } + case ATTR_INPUT_MAPPING: + { + int mapping = get_string_id(attr[i], input_mapping_id); + if (current_input & INPUT_TYPE_BUTTON) + { + int button = current_input & 0xffff; + romset[current_romset].controls.button[button].mapping = mapping; + } + else if (current_input & INPUT_TYPE_ANALOG) + { + int axis = current_input & 0xffff; + romset[current_romset].controls.analog_axis[axis].mapping = mapping; + } + break; + } + } + } + i++; + }; + break; + } + } + } +} + +static void XMLCALL element_end(void *data, const char *el) +{ + int element = get_string_id(el, element_id); + + if (element < 0) + { + message(0, "Unknown element %s while parsing XML\n", el); + } + else + { + switch (element) + { + case ELEMENT_ROM: + { + current_rom++; + current_element = ELEMENT_GAMELIST; + break; + } + case ELEMENT_GAME: + { + romset[current_romset].num_patches = current_patch; + current_romset++; + current_rom = 0; + current_patch = 0; + current_element = ELEMENT_GAMELIST; + break; + } + case ELEMENT_DESCRIPTION: + case ELEMENT_YEAR: + case ELEMENT_MANUFACTURER: + case ELEMENT_STEP: + case ELEMENT_BRIDGE: + case ELEMENT_CROMSIZE: + { + current_element = ELEMENT_GAMELIST; + break; + } + case ELEMENT_PATCH: + { + current_patch++; + current_element = ELEMENT_GAMELIST; + break; + } + } + } +} + +static void XMLCALL character_data(void *data, const char *s, int len) +{ + char temp[2000]; + memcpy(temp, s, len); + temp[len] = 0; + + switch (current_element) + { + case ELEMENT_DESCRIPTION: + { + strcpy(romset[current_romset].title, temp); + break; + } + case ELEMENT_YEAR: + { + int year; + sscanf(temp, "%d", &year); + romset[current_romset].year = year; + break; + } + case ELEMENT_MANUFACTURER: + { + strcpy(romset[current_romset].manufacturer, temp); + break; + } + case ELEMENT_STEP: + { + int step = get_string_id(temp, step_id); + + if (step >= 0) + { + romset[current_romset].step = step; + } + else + { + message(0, "Invalid step %s while parsing XML file\n", temp); + } + break; + } + case ELEMENT_BRIDGE: + { + if (_stricmp(temp, "mpc106") == 0) + { + romset[current_romset].bridge = 2; + } + else + { + message(0, "Unknown bridge %s while parsing XML file\n", temp); + } + break; + } + case ELEMENT_CROMSIZE: + { + if (_stricmp(temp, "64M") == 0) + { + romset[current_romset].cromsize = 1; + } + else + { + message(0, "Unknown cromsize %s while parsing XML file\n", temp); + } + break; + } + } +} + +int parse_romlist(char *romlist_name, ROMSET *_romset) +{ + XML_Parser parser; + + int length; + FILE *file; + + file = open_file(FILE_READ|FILE_BINARY, "%s", romlist_name); + if (file == NULL) + { + message(0, "Couldn't open %s", romlist_name); + return 0; + } + + length = (int)get_open_file_size(file); + + romlist = (UINT8*)malloc(length); + + if (!read_from_file(file, romlist, length)) + { + message(0, "I/O error while reading %s", romlist_name); + return 0; + } + + close_file(file); + + romset = _romset; + + // parse the XML file + parser = XML_ParserCreate(NULL); + + XML_SetElementHandler(parser, element_start, element_end); + XML_SetCharacterDataHandler(parser, character_data); + + if (XML_Parse(parser, romlist, length, 1) != XML_STATUS_OK) + { + message(0, "Error while parsing the XML file %s", romlist_name); + return 0; + } + + XML_ParserFree(parser); + return current_romset; +} \ No newline at end of file diff --git a/core/rtc.c b/core/rtc.c new file mode 100644 index 0000000..fd58898 --- /dev/null +++ b/core/rtc.c @@ -0,0 +1,179 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * rtc.c + * + * Real-Time Clock (72421) emulation. + */ + +#include "model3.h" +#include + +static UINT8 rtc_step = 0; +static UINT8 rtc_reg[0x10]; /* 4-bit wide */ + +/******************************************************************/ +/* Interface */ +/******************************************************************/ + +void rtc_init(void) +{ + +} + +void rtc_shutdown(void) +{ + +} + +void rtc_reset(void) +{ + rtc_step = 0; + + memset(rtc_reg, 0, 0x10); +} + +void rtc_step_frame(void) +{ + +} + +/* + * void rtc_save_state(FILE *fp); + * + * Saves the state of the real-time clock to a file. + * + * Parameters: + * fp = File to save to. + */ + +void rtc_save_state(FILE *fp) +{ + // do nothing yet because this file isn't complete or used, it appears +} + +/* + * void rtc_load_state(FILE *fp); + * + * Loads the state of the real-time clock from a file. + * + * Parameters: + * fp = File to load from. + */ + +void rtc_load_state(FILE *fp) +{ + // do nothing yet because this file isn't complete or used, it appears +} + +/******************************************************************/ +/* Access */ +/******************************************************************/ + +static UINT8 get_register(int reg) +{ + time_t current_time; + struct tm* tms; + + time( ¤t_time ); + tms = localtime( ¤t_time ); + + switch(reg) + { + case 0: // 1-second digit + return (tms->tm_sec % 10) & 0xF; + break; + case 1: // 10-seconds digit + return (tms->tm_sec / 10) & 0x7; + break; + case 2: // 1-minute digit + return (tms->tm_min % 10) & 0xF; + break; + case 3: // 10-minute digit + return (tms->tm_min / 10) & 0x7; + break; + case 4: // 1-hour digit + return (tms->tm_hour % 10) & 0xF; + break; + case 5: // 10-hours digit + return (tms->tm_hour / 10) & 0x7; + break; + case 6: // 1-day digit (days in month) + return (tms->tm_mday % 10) & 0xF; + break; + case 7: // 10-days digit + return (tms->tm_mday / 10) & 0x3; + break; + case 8: // 1-month digit + return ((tms->tm_mon + 1) % 10) & 0xF; + break; + case 9: // 10-months digit + return ((tms->tm_mon + 1) / 10) & 0x1; + break; + case 10: // 1-year digit + return (tms->tm_year % 10) & 0xF; + break; + case 11: // 10-years digit + return ((tms->tm_year % 100) / 10) & 0xF; + break; + case 12: // day of the week + return tms->tm_wday & 0x7; + break; + case 13: + return 0; + break; + case 14: + return 0; + break; + case 15: + return 0; + break; + default: + error("ERROR: invalid RTC access reg%X\n", reg); + return 0; + } +} + +UINT8 rtc_read_8(UINT32 a) +{ + int address = (a >> 2) & 0xF; + + //message(0, "RTC: read %08X, %08X", address,ppc_get_reg(PPC_REG_PC)); + + return get_register( address ); +} + +UINT32 rtc_read_32(UINT32 a) +{ + int address = (a >> 2) & 0xF; + + //message(0, "RTC: read %08X, %08X", address,ppc_get_reg(PPC_REG_PC)); + + return get_register( address) << 24 | 0x30000; // Bits 0x30000 set to get battery voltage check to pass +} + +void rtc_write(UINT32 a, UINT8 d) +{ + a = (a >> 2) & 0xF; + //message(0, "RTC: write %08X = %X", a, d); + + a &= 0xF; + + rtc_reg[a] = d; +} diff --git a/core/rtc.h b/core/rtc.h new file mode 100644 index 0000000..734e592 --- /dev/null +++ b/core/rtc.h @@ -0,0 +1,41 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * rtc.h + * + * Real-Time Clock (72421) header. + */ + +#ifndef INCLUDED_RTC_H +#define INCLUDED_RTC_H + +extern void rtc_init(void); +extern void rtc_shutdown(void); +extern void rtc_reset(void); +extern void rtc_step_frame(void); + +extern void rtc_save_state(FILE *); +extern void rtc_load_state(FILE *); + +extern UINT8 rtc_read_8(UINT32 a); +extern UINT32 rtc_read_32(UINT32 a); +extern void rtc_write(UINT32 a, UINT8 d); + +#endif // INCLUDED_RTC_H + diff --git a/core/scsi.c b/core/scsi.c new file mode 100644 index 0000000..aa0bd31 --- /dev/null +++ b/core/scsi.c @@ -0,0 +1,367 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * scsi.c + * + * NCR 53C810 SCSI controller emulation. + * + * Multi-byte data written is assumed to be little endian and is therefore + * reversed because the PowerPC operates in big endian mode in the Model 3. + * + * NOTE: scsi_run() is often called with an argument of 100. This is + * actually incorrect. It should run until an interrupt condition. A count of + * 100 is used as a runaway counter to prevent lock-ups. + */ + +#include "model3.h" + +/* + * Read/Write Handlers + * + * These are used as an interface to the rest of the system. + */ + +static UINT8 (*read_8)(UINT32); +static UINT16 (*read_16)(UINT32); +static UINT32 (*read_32)(UINT32); +static void (*write_8)(UINT32, UINT8); +static void (*write_16)(UINT32, UINT16); +static void (*write_32)(UINT32, UINT32); + +/* + * 53C810 Context + * + * Offsets within the register array correspond to register addresses but the + * endianness in which they are stored is little endian. Macros are provided + * to access them. + */ + +#define REG8(r) scsi_regs[r] +#define REG16(r) *((UINT16 *) &scsi_regs[r]) +#define REG32(r) *((UINT32 *) &scsi_regs[r]) + +static UINT8 scsi_regs[0x60]; +static BOOL scripts_exec; // true if SCRIPTS code should be executed + +/* + * SCRIPTS Emulation + */ + +#include "scsiop.h" + +/* + * UINT8 scsi_read_8(UINT32 addr); + * + * Reads from the SCSI register space. + * + * Parameters: + * addr = Register address (only lower 8 bits matter.) + * + * Returns: + * Returns data from the register read. + */ + +UINT8 scsi_read_8(UINT32 addr) +{ + UINT8 reg; + + addr &= 0xFF; + //if (addr > 0x5F) + // error("%08X: SCSI invalid read from %02X", ppc_get_reg(PPC_REG_PC), addr); + + reg = REG8(addr); + + switch (addr) + { + case 0x14: + REG8(addr) &= 0xFE; // clear DIP + break; + default: + break; + } + + return reg; +} + +/* + * UINT32 scsi_read_32(UINT32 addr); + * + * Reads from the SCSI register space. + * + * Parameters: + * addr = Register address (only lower 8 bits matter.) + * + * Returns: + * Returns data from the register read. + */ + +UINT32 scsi_read_32(UINT32 addr) +{ + UINT32 reg; + +// error("SCSI 32-bit read from %08X", addr); + + addr &= 0xFF; + if (addr > 0x5F) + error("%08X: SCSI invalid read from %02X", ppc_get_pc(), addr); + + reg = REG32(addr); + + switch (addr) + { + case 0x14: + error("%08X: SCSI 32-bit read from reg %02X -- don't know what to do", ppc_get_pc(), addr); + break; + default: + // NOTE: some registers might have to be handled to clear certain + // bits + break; + } + + return reg; +} + + +/* + * void scsi_write_8(UINT32 addr, UINT8 data); + * + * Writes a byte to the SCSI register space. + * + * Parameters: + * addr = Register address (only lower 8 bits matter.) + * data = Data to write. + */ + +void scsi_write_8(UINT32 addr, UINT8 data) +{ + addr &= 0xFF; + if (addr > 0x5F) + error("%08X: SCSI invalid write8 to %02X", ppc_get_pc(), addr); + + //message(0, "%08X: SCSI %02X = %02X", ppc_get_pc(), addr, data); + + REG8(addr) = data; + + switch (addr) + { + case 0x3B: // DCNTL: DMA Control + + /* + * 7 6 5 4 3 2 1 0 + * +------+------+------+------+------+------+------+------+ + * | CLSE | PFF | PFEN | SSM | IRQM | STD | IRQD | COM | + * +------+------+------+------+------+------+------+------+ + * + * CLSE Cache Line Size Enable + * + * PFF Prefetch Flush + * + * PFEN Prefetch Enable + * + * SSM Single Step Mode + * + * Setting this bit causes the SCSI to stop after executing + * each SCRIPTS instruction and generate a single step + * interrupt. To restart the SCSI after the interrupt has + * been generated, read ISTAT and DSTAT to recognize and + * clear the interrupt, then set STD bit in this register + * to resume execution. + * + * IRQM IRQ Mode + * + * STD Start DMA Operation + * + * The SCSI fetches an instruction and executes it when this + * bit is set. It is required when the SCSI is in one of the + * following modes: + * + * - Manual start mode: Bit 0 in the DMODE register is + * set. + * - Single step mode: Bit 4 in the DCNTL register is + * set. + * + * When in manual mode, setting this bit starts instruction + * execution -- it remains set until an interrupt occurs. In + * single step mode, it restarts execution after an + * interrupt. + * + * IRQD IRQ Disable + * + * COM LSI53C700 Family Compatibility + */ + + /* + * Single-stepping is checked for in scsi_run() (the number of + * instructions to execute will be reduced to 1 there.) + */ + + if ((REG8(0x38) & 0x01) || // MAN=1, start SCRIPTS on STD=1 + (REG8(0x3B) & 0x10)) // single step, resume execution + { + scripts_exec = data & 0x04; + scsi_run(500); + } + break; + } +} + +/* + * void scsi_write_16(UINT32 addr, UINT16 data); + * + * Writes a word to the SCSI register space. + * + * Parameters: + * addr = Register address (only lower 8 bits matter.) + * data = Data to write. + */ + +void scsi_write_16(UINT32 addr, UINT16 data) +{ + data = BSWAP16(data); + //message(0, "%08X: SCSI %02X = %04X", ppc_get_pc(), addr, data); +} + +/* + * void scsi_write_32(UINT32 addr, UINT32 data); + * + * Writes a byte to the SCSI register space. + * + * Parameters: + * addr = Register address (only lower 8 bits matter.) + * data = Data to write. + */ + +void scsi_write_32(UINT32 addr, UINT32 data) +{ + if ((addr & 0xff) > 0x5C) + error("%08X: SCSI invalid write32 to %08X", ppc_get_pc(), addr); + addr &= 0xff; + + data = BSWAP32(data); + REG32(addr) = data; + +// message(0, "%08X: SCSI %02X = %08X", ppc_get_reg(PPC_REG_PC), addr, data); + + switch (addr) + { + case 0x2C: // DSP: DMA SCRIPTS Pointer + if ((REG8(0x38) & 0x01) == 0) // MAN=0, start SCRIPTS automatically + scripts_exec = 1; + scsi_run(500); + break; + default: + break; + } +} + +/* + * void scsi_save_state(FILE *fp); + * + * Saves the state of the SCSI controller to a file. + * + * Parameters: + * fp = File to save to. + */ + +void scsi_save_state(FILE *fp) +{ + fwrite(scsi_regs, sizeof(UINT8), 0x60, fp); + fwrite(&scripts_exec, sizeof(BOOL), 1, fp); +} + +/* + * void scsi_load_state(FILE *fp); + * + * Loads the state of the SCSI controller from a file. + * + * Parameters: + * fp = File to load from. + */ + +void scsi_load_state(FILE *fp) +{ + fread(scsi_regs, sizeof(UINT8), 0x60, fp); + fread(&scripts_exec, sizeof(BOOL), 1, fp); +} + +/* + * void scsi_reset(void); + * + * Initializes the SCSI controller to its power-on state. All bits which are + * marked as undefined by the manual are simply set to 0 here. + */ + +void scsi_reset(void) +{ + memset(scsi_regs, 0, sizeof(scsi_regs)); + scripts_exec = 0; + + REG8(0x00) = 0xc0; + REG8(0x0C) = 0x80; + REG8(0x0F) = 0x02; + REG8(0x18) = 0xff; + REG8(0x19) = 0xf0; + REG8(0x1A) = 0x01; + REG8(0x46) = 0x60; + REG8(0x47) = 0x0f; + REG8(0x4C) = 0x03; +} + +/* + * void scsi_init(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32), + * UINT32 (*read32)(UINT32), void (*write8)(UINT32, UINT8), + * void (*write16)(UINT32, UINT16), + * void (*write32)(UINT32, UINT32)); + * + * Initializes the SCSI controller emulation by building the SCRIPTS opcode + * table and setting the memory access handlers. + * + * Parameters: + * read8 = Handler to use for 8-bit reads. + * read16 = Handler to use for 16-bit reads. + * read32 = Handler to use for 32-bit reads. + * write8 = Handler to use for 8-bit writes. + * write16 = Handler to use for 16-bit writes. + * write32 = Handler to use for 32-bit writes. + */ + +void scsi_init(UINT8 (*read8)(UINT32), UINT16 (*read16)(UINT32), + UINT32 (*read32)(UINT32), void (*write8)(UINT32, UINT8), + void (*write16)(UINT32, UINT16), + void (*write32)(UINT32, UINT32)) +{ + read_8 = read8; + read_16 = read16; + read_32 = read32; + write_8 = write8; + write_16 = write16; + write_32 = write32; + + build_opcode_table(); +} + +/* + * void scsi_shutdown(void); + * + * Shuts down the SCSI emulation (actually does nothing.) + */ + +void scsi_shutdown(void) +{ +} diff --git a/core/scsi.h b/core/scsi.h new file mode 100644 index 0000000..cb15f42 --- /dev/null +++ b/core/scsi.h @@ -0,0 +1,51 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * scsi.h + * + * NCR 53C810 SCSI controller header. + */ + +#ifndef INCLUDED_SCSI_H +#define INCLUDED_SCSI_H + +/* + * Functions + */ + +extern UINT8 scsi_read_8(UINT32); +extern UINT32 scsi_read_32(UINT32); + +extern void scsi_write_8(UINT32, UINT8); +extern void scsi_write_16(UINT32, UINT16); +extern void scsi_write_32(UINT32, UINT32); + +extern void scsi_save_state(FILE *); +extern void scsi_load_state(FILE *); + +extern void scsi_run(INT); +extern void scsi_reset(void); + +extern void scsi_init(UINT8 (*)(UINT32), UINT16 (*)(UINT32), + UINT32 (*)(UINT32), void (*)(UINT32, UINT8), + void (*)(UINT32, UINT16), + void (*)(UINT32, UINT32)); +extern void scsi_shutdown(void); + +#endif // INCLUDED_SCSI_H diff --git a/core/scsiop.h b/core/scsiop.h new file mode 100644 index 0000000..e4b5646 --- /dev/null +++ b/core/scsiop.h @@ -0,0 +1,221 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * scsiop.h + * + * NCR 53C810 SCSI controller SCRIPTS emulation. This file is intended to be + * included by scsi.c only. + */ + +#ifndef INCLUDED_SCSIOP_H +#define INCLUDED_SCSIOP_H + +/* + * Macros + */ + +#define INSTRUCTION(name) static BOOL name() + +#define FETCH(dest) do { dest = read_32(REG32(0x2c)); REG32(0x2c) += 4; dest = BSWAP32(dest); } while (0); + +#define DBC (REG32(0x24) & 0xffffff) +#define DSPS (REG32(0x30)) +#define TEMP (REG32(0x1c)) + + +/* + * Opcode Table + * + * Use the upper 8 bits of a SCRIPTS instruction as an index into this table. + */ + +static BOOL (*op_table[256])(); + + +/* + * Move Memory + */ + +#ifdef _PROFILE_ +extern UINT is_dma; +#endif + +INSTRUCTION(move_memory) +{ + UINT32 source = DSPS, dest; + INT num_bytes = DBC; + + PROFILE_SECT_ENTRY("scsi"); + + #ifdef _PROFILE_ + is_dma = 1; + #endif + + FETCH(TEMP); + dest = TEMP; + +// message(0, "%08X (%08X): SCSI move memory: %08X->%08X, %X", ppc_get_reg(PPC_REG_PC), ppc_get_reg(PPC_REG_LR), source, dest, num_bytes); + + /* + * Perform a 32-bit copy if possible and if necessary, finish off with a + * byte-for-byte copy + */ + + /*for (i = 0; i < num_bytes / 4; i++) + { + write_32(dest, read_32(source)); + dest += 4; + source += 4; + }*/ + + model3_dma_transfer(source, dest, num_bytes, FALSE); + + if (num_bytes & 3) + { + error("unaligned SCSI op !!!\n"); + num_bytes &= 3; + while (num_bytes--) + write_8(dest++, read_8(source++)); + } + + source += num_bytes; + dest += num_bytes; + + #ifdef _PROFILE_ + is_dma = 0; + #endif + + REG32(0x24) &= 0xff000000; // update DBC (is any of this necessary???) + DSPS = source; + TEMP = dest; + + PROFILE_SECT_EXIT("scsi"); + + return 0; +} + +/* + * INT and INTFLY + */ + +INSTRUCTION(int_and_intfly) +{ + if ((DBC & 0x100000)) // INTFLY -- not yet emulated! + return 1; + + if (((REG32(0x24) >> 21) & 1) || ((REG32(0x24) >> 18) & 1) || ((REG32(0x24) >> 17) & 1)) + return 1; // conditional tests not yet emulated + + REG8(0x14) |= 0x01; // DIP=1 + scripts_exec = 0; // halt execution + + /* + * NOTE: I haven't seen any games rely on this, so if you observe SCSI + * problems, remove this to see if it helps. + */ + + REG8(0x14) |= 0x01; // DIP=1 + REG8(0x0c) |= 0x04; // SIR=1 + //model3_add_irq(0x60); + ppc_set_irq_line(1); + return 0; +} + +/* + * Invalid Instruction + */ + +INSTRUCTION(invalid) +{ +// message(0, "INVALID SCSI INSTRUCTION @ %08X", REG32(0x2c)); + return 1; +} + +/* + * void scsi_run(INT num); + * + * Runs SCSI SCRIPTS instructions until the code halts or the requested number + * of instructions is executed. + * + * Parameters: + * num = Number of instructions to execute. + */ + +void scsi_run(INT num) +{ + LOG("model3.log", "SCSI exec %08X\n", REG32(0x2c)); + if (!scripts_exec) + return; + + if ((REG8(0x3B) & 0x10)) // single step mode + num = 1; + + while (num-- && scripts_exec) + { + UINT32 save_addr = REG32(0x2c); // for debugging + + FETCH(REG32(0x24)); // first double word into DCMD and DBC + FETCH(DSPS); // second double word into DSPS + + if ((*op_table[REG32(0x24) >> 24])()) + error("SCSI: invalid instruction @ %08X", save_addr); + } + + scripts_exec = 0; + + if ((REG8(0x3B) & 0x10)) // single step mode, trigger interrupt + { + REG8(0x0c) |= 0x08; // SSI=1 + REG8(0x14) |= 0x01; // DIP=1 + ppc_set_irq_line(1); // what about Model 3 IRQ status? + } +} + +/* + * insert(): + * + * Inserts an instruction into the appropriate elements of the opcode table + * under the control of a mask. + */ + +static void insert(UINT8 match, UINT8 mask, BOOL (*handler)()) +{ + UINT32 i; + + for (i = 0; i < 256; i++) + { + if ((i & mask) == match) + op_table[i] = handler; + } +} + +/* + * build_opcode_table(): + * + * Installs instruction handlers. + */ + +static void build_opcode_table(void) +{ + insert(0, 0, &invalid); + insert(0xc0, 0xfe, &move_memory); + insert(0x98, 0xf8, &int_and_intfly); +} + +#endif // INCLUDED_SCSIOP_H diff --git a/core/scsp.c b/core/scsp.c new file mode 100644 index 0000000..3eaab83 --- /dev/null +++ b/core/scsp.c @@ -0,0 +1,2494 @@ +/******************************************************************/ +/* Custom Sound Processor */ +/******************************************************************/ + +/* +// Common Control Register (CCR) +// +// $+00 $+01 +// $400 ---- --12 3333 4444 1:MEM4MB memory size 2:DAC18B dac for digital output 3:VER version number 4:MVOL +// $402 ---- ---1 1222 2222 1:RBL ring buffer length 2:RBP lead address +// $404 ---1 2345 6666 6666 1:MOFULL out fifo full 2:MOEMP empty 3:MIOVF overflow 4:MIFULL in 5:MIEMP 6:MIBUF +// $406 ---- ---- 1111 1111 1:MOBUF midi output data buffer +// $408 1111 1222 2--- ---- 1:MSLC monitor slot 2:CA call address +// $40a ---- ---- ---- ---- +// $40c ---- ---- ---- ---- +// $40e ---- ---- ---- ---- +// $410 ---- ---- ---- ---- +// $412 1111 1111 1111 111- 1:DMEAL transfer start address (sound) +// $414 1111 2222 2222 222- 1:DMEAH transfer start address hi2:DRGA start register address (dsp) +// $416 -123 4444 4444 444- 1:DGATE transfer gate 0 clear 2:DDIR direction 3:DEXE start 4:DTLG data count +// $418 ---- -111 2222 2222 1:TACTL timer a prescalar control 2:TIMA timer a count data +// $41a ---- -111 2222 2222 1:TBCTL timer b prescalar control 2:TIMB timer b count data +// $41c ---- -111 2222 2222 2:TCCTL timer c prescalar control 2:TIMC timer c count data +// $41e ---- -111 1111 1111 1:SCIEB allow sound cpu interrupt +// $420 ---- -111 1111 1111 1:SCIPD request sound cpu interrupt +// $422 ---- -111 1111 1111 1:SCIRE reset sound cpu interrupt +// $424 ---- ---- 1111 1111 1:SCILV0 sound cpu interrupt level bit0 +// $426 ---- ---- 1111 1111 1:SCILV1 sound cpu interrupt level bit1 +// $428 ---- ---- 1111 1111 1:SCILV2 sound cpu interrupt level bit2 +// $42a ---- -111 1111 1111 1:MCIEB allow main cpu interrupt +// $42c ---- -111 1111 1111 1:MCIPD request main cpu interrupt +// $42e ---- -111 1111 1111 1:MCIRE reset main cpu interrupt +*/ + +/* +// Individual Slot Register (ISR) +// +// $+00 $+01 +// $00 ---1 2334 4556 7777 1:KYONEX 2:KYONB 3:SBCTL 4:SSCTL 5:LPCTL 6:PCM8B 7:SA start address +// $02 1111 1111 1111 1111 1:SA start address +// $04 1111 1111 1111 1111 1:LSA loop start address +// $06 1111 1111 1111 1111 1:LEA loop end address +// $08 1111 1222 2234 4444 1:D2R decay 2 rate 2:D1R decay 1 rate 3:EGHOLD eg hold mode 4:AR attack rate +// $0a -122 2233 3334 4444 1:LPSLNK loop start link 2:KRS key rate scaling 3:DL decay level 4:RR release rate +// $0c ---- --12 3333 3333 1:STWINH stack write inhibit 2:SDIR sound direct 3:TL total level +// $0e 1111 2222 2233 3333 1:MDL modulation level 2:MDXSL modulation input x 3:MDYSL modulation input y +// $10 -111 1-22 2222 2222 1:OCT octave 2:FNS frequency number switch +// $12 1222 2233 4445 5666 1:LFORE 2:LFOF 3:PLFOWS 4:PLFOS 5:ALFOWS 6:ALFOS +// $14 ---- ---- -111 1222 1:ISEL input select 2:OMXL input mix level +// $16 1112 2222 3334 4444 1:DISDL 2:DIPAN 3:EFSDL 4:EFPAN +*/ + +#include "MODEL3.H" + +//////////////////////////////////////////////////////////////// + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +//#define SCSP_LOG + +#define SCSP_FREQ 44100 // SCSP frequency + +#define SCSP_RAM_SIZE 0x080000 // SCSP RAM size +#define SCSP_RAM_MASK (SCSP_RAM_SIZE - 1) + +#define SCSP_MIDI_IN_EMP 0x01 // MIDI flags +#define SCSP_MIDI_IN_FUL 0x02 +#define SCSP_MIDI_IN_OVF 0x04 +#define SCSP_MIDI_OUT_EMP 0x08 +#define SCSP_MIDI_OUT_FUL 0x10 + +#define SCSP_ENV_RELEASE 0 // Enveloppe phase +#define SCSP_ENV_SUBSTAIN 1 +#define SCSP_ENV_DECAY 2 +#define SCSP_ENV_ATTACK 3 + +#define SCSP_FREQ_HB 19 // Freq counter int part +#define SCSP_FREQ_LB 10 // Freq counter float part + +#define SCSP_ENV_HB 10 // Env counter int part +#define SCSP_ENV_LB 10 // Env counter float part + +#define SCSP_LFO_HB 10 // LFO counter int part +#define SCSP_LFO_LB 10 // LFO counter float part + +#define SCSP_ENV_LEN (1 << SCSP_ENV_HB) // Env table len +#define SCSP_ENV_MASK (SCSP_ENV_LEN - 1) // Env table mask + +#define SCSP_FREQ_LEN (1 << SCSP_FREQ_HB) // Freq table len +#define SCSP_FREQ_MASK (SCSP_FREQ_LEN - 1) // Freq table mask + +#define SCSP_LFO_LEN (1 << SCSP_LFO_HB) // LFO table len +#define SCSP_LFO_MASK (SCSP_LFO_LEN - 1) // LFO table mask + +#define SCSP_ENV_AS 0 // Env Attack Start +#define SCSP_ENV_DS (SCSP_ENV_LEN << SCSP_ENV_LB) // Env Decay Start +#define SCSP_ENV_AE (SCSP_ENV_DS - 1) // Env Attack End +#define SCSP_ENV_DE (((2 * SCSP_ENV_LEN) << SCSP_ENV_LB) - 1) // Env Decay End + +#define SCSP_ATTACK_R (u32) (8 * 44100) +#define SCSP_DECAY_R (u32) (12 * SCSP_ATTACK_R) + +//////////////////////////////////////////////////////////////// + +typedef struct slot_t +{ + u8 swe; // stack write enable + u8 sdir; // sound direct + u8 pcm8b; // PCM sound format + + u8 sbctl; // source bit control + u8 ssctl; // sound source control + u8 lpctl; // loop control + + u8 key; // KEY_ state + u8 keyx; // still playing regardless the KEY_ state (hold, decay) + + s8 *buf8; // sample buffer 8 bits + s16 *buf16; // sample buffer 16 bits + + u32 fcnt; // phase counter + u32 finc; // phase step adder + u32 finct; // non ajusted phase step + + s32 ecnt; // enveloppe counter + s32 einc; // enveloppe current step adder + s32 einca; // enveloppe step adder for attack + s32 eincd; // enveloppe step adder for decay 1 + s32 eincs; // enveloppe step adder for decay 2 + s32 eincr; // enveloppe step adder for release + s32 ecmp; // enveloppe compare to raise next phase + u32 ecurp; // enveloppe current phase (attack / decay / release ...) + + void (*enxt)(struct slot_t *); // enveloppe function pointer for next phase event + + u32 lfocnt; // lfo counter + u32 lfoinc; // lfo step adder + + u32 sa; // start address + u32 lsa; // loop start address + u32 lea; // loop end address + + s32 tl; // total level + s32 sl; // substain level + + s32 ar; // attack rate + s32 dr; // decay rate + s32 sr; // substain rate + s32 rr; // release rate + + s32 *arp; // attack rate table pointer + s32 *drp; // decay rate table pointer + s32 *srp; // substain rate table pointer + s32 *rrp; // release rate table pointer + + u32 krs; // key rate scale + + s32 *lfofmw; // lfo frequency modulation waveform pointer + s32 *lfoemw; // lfo enveloppe modulation waveform pointer + u8 lfofms; // lfo frequency modulation sensitivity + u8 lfoems; // lfo enveloppe modulation sensitivity + u8 fsft; // frequency shift (used for freq lfo) + + u8 mdl; // modulation level + u8 mdx; // modulation source X + u8 mdy; // modulation source Y + + u8 imxl; // input sound level + u8 disll; // direct sound level left + u8 dislr; // direct sound level right + u8 efsll; // effect sound level left + u8 efslr; // effect sound level right + + u8 eghold; // eg type enveloppe hold + u8 lslnk; // loop start link (start D1R when start loop adr is reached) + + u8 dirt14; // 4 bytes alignement... + u8 dirt15; // 4 bytes alignement... + u8 dirt16; // 4 bytes alignement... +} slot_t; + +typedef struct scsp_t +{ + u32 mvol; // master volume + + u32 rbl; // ring buffer lenght + u32 rbp; // ring buffer address (pointer) + + u32 mslc; // monitor slot + u32 ca; // call address + + u32 dmea; // dma memory address start + u32 drga; // dma register address start + u32 dmfl; // dma flags (direction / gate 0 ...) + u32 dmlen; // dma transfert len + + u8 midinbuf[4]; // midi in buffer + u8 midoutbuf[4]; // midi out buffer + u8 midincnt; // midi in buffer size + u8 midoutcnt; // midi out buffer size + u8 midflag; // midi flag (empty, full, overflow ...) + u8 midflag2; // midi flag 2 (here only for alignement) + + s32 timacnt; // timer A counter + u32 timasd; // timer A step diviser + s32 timbcnt; // timer B counter + u32 timbsd; // timer B step diviser + s32 timccnt; // timer C counter + u32 timcsd; // timer C step diviser + + u32 scieb; // allow sound cpu interrupt + u32 scipd; // pending sound cpu interrupt + + u32 scilv0; // IL0 M68000 interrupt pin state + u32 scilv1; // IL1 M68000 interrupt pin state + u32 scilv2; // IL2 M68000 interrupt pin state + + u32 mcieb; // allow main cpu interrupt + u32 mcipd; // pending main cpu interrupt + + u8 *scsp_ram; // scsp ram pointer + void (*mintf)(void); // main cpu interupt function pointer + void (*sintf)(u32); // sound cpu interrupt function pointer + + s32 stack[32 * 2]; // two last generation slot output (SCSP STACK) + slot_t slot[32]; // 32 slots +} scsp_t; + +//////////////////////////////////////////////////////////////// + +static s32 scsp_env_table[SCSP_ENV_LEN * 2]; // enveloppe curve table (attack & decay) + +static s32 scsp_lfo_sawt_e[SCSP_LFO_LEN]; // lfo sawtooth waveform for enveloppe +static s32 scsp_lfo_squa_e[SCSP_LFO_LEN]; // lfo square waveform for enveloppe +static s32 scsp_lfo_tri_e[SCSP_LFO_LEN]; // lfo triangle waveform for enveloppe +static s32 scsp_lfo_noi_e[SCSP_LFO_LEN]; // lfo noise waveform for enveloppe + +static s32 scsp_lfo_sawt_f[SCSP_LFO_LEN]; // lfo sawtooth waveform for frequency +static s32 scsp_lfo_squa_f[SCSP_LFO_LEN]; // lfo square waveform for frequency +static s32 scsp_lfo_tri_f[SCSP_LFO_LEN]; // lfo triangle waveform for frequency +static s32 scsp_lfo_noi_f[SCSP_LFO_LEN]; // lfo noise waveform frequency + +static s32 scsp_attack_rate[0x40 + 0x20]; // enveloppe step for attack +static s32 scsp_decay_rate[0x40 + 0x20]; // enveloppe step for decay +static s32 scsp_null_rate[0x20]; // null enveloppe step + +static s32 scsp_lfo_step[32]; // directly give the lfo counter step + +static scsp_t scsp; + +static u8 * scsp_reg; +static u8 * scsp_isr; +static u8 * scsp_ccr; +static u8 * scsp_dcr; + +static s32 * scsp_bufL; +static s32 * scsp_bufR; +static u32 scsp_buf_len; +static u32 scsp_buf_pos; + +#ifdef SCSP_LOG + +static const char * scsp_ssctl_id[4] = { "scsp_ram", "noise", "zero", "-", }; +static const char * scsp_lpctl_id[4] = { "none", "normal", "reverse", "alternate", }; +static const char * scsp_xlfows_id[4] = { "saw", "rect", "tri", "noise", }; + +#endif + +//////////////////////////////////////////////////////////////// + +static void scsp_env_null_next(slot_t *slot); +static void scsp_release_next(slot_t *slot); +static void scsp_substain_next(slot_t *slot); +static void scsp_decay_next(slot_t *slot); +static void scsp_attack_next(slot_t *slot); + +//////////////////////////////////////////////////////////////// +// Debug + +char * scsp_debug_slist_on(void){ + + static char string[33]; + int i; + + for(i = 0; i < 32; i++){ + string[i] = + (scsp.slot[i].key) ? 'X' : + ' '; + } + + string[32] = '\0'; + + return(string); +} + +char * scsp_debug_ilist(int s_m, char * out){ + + int t; + + if(s_m == 0){ t = *(u16 *)&scsp_ccr[0x1e ^ 2]; } // sound cpu interrupts + else{ t = *(u16 *)&scsp_ccr[0x2a ^ 2]; } // main cpu interrupts + + sprintf(out, + "%c=%c%c%c%c%c%c%c%c%c%c%c", + ((s_m == 0) ? 'S' : 'M'), + ((t & 0x0001) ? '0' : ' '), + ((t & 0x0002) ? '1' : ' '), + ((t & 0x0004) ? '2' : ' '), + ((t & 0x0008) ? 'I' : ' '), + ((t & 0x0010) ? 'D' : ' '), + ((t & 0x0020) ? 'U' : ' '), + ((t & 0x0040) ? 'A' : ' '), + ((t & 0x0080) ? 'B' : ' '), + ((t & 0x0100) ? 'C' : ' '), + ((t & 0x0200) ? 'O' : ' '), + ((t & 0x0400) ? 'S' : ' ') + ); + + return(out); +} + +static void slog(char * out, ...){ + + // GCC doesn't like slog as a macro + + #ifdef SCSP_LOG + + va_list list; + char temp[1024]; + FILE * f; + + f = fopen("scsp.log", "ab"); + if (f) + { + va_start(list, out); + vsprintf(temp, out, list); + va_end(list); + + fprintf(f, temp); + fclose(f); + } + + #endif +} + +//////////////////////////////////////////////////////////////// +// Misc + +static int scsp_round(double val) +{ + if ((val - ((double) (int) val)) > 0.5) return (int) (val + 1); + else return (int) val; +} + + +//////////////////////////////////////////////////////////////// +// Interrupts + +static void scsp_main_interrupt(u32 id) +{ +// if (scsp.mcipd & id) return; + +// if (id != 0x400) slog("scsp main interrupt %.4X\n", id); + + scsp.mcipd |= id; + + if (scsp.mcieb & id) + { + slog("scsp main interrupt accepted %.4X\n", id); + + if (scsp.mintf != NULL) scsp.mintf(); + } +} + +static void scsp_sound_interrupt(u32 id) +{ + u32 level; + +// if (scsp.scipd & id) return; + +// slog("scsp sound interrupt %.4X\n", id); + + scsp.scipd |= id; + + if (scsp.scieb & id) + { + level = 0; + if (id > 0x80) id = 0x80; + + if (scsp.scilv0 & id) level |= 1; + if (scsp.scilv1 & id) level |= 2; + if (scsp.scilv2 & id) level |= 4; + + if (id == 0x8) slog("scsp sound interrupt accepted %.2X lev=%d\n", id, level); + + if (scsp.sintf != NULL) scsp.sintf(level); + } +} + +//////////////////////////////////////////////////////////////// +// Direct Memory Access + +static void scsp_dma(void) +{ + if (scsp.dmfl & 0x20) + { + // dsp -> scsp_ram + slog("scsp dma: scsp_ram(%08lx) <- reg(%08lx) * %08lx\n", scsp.dmea, scsp.drga, scsp.dmlen); + } + else + { + // scsp_ram -> dsp + slog("scsp dma: scsp_ram(%08lx) -> reg(%08lx) * %08lx\n", scsp.dmea, scsp.drga, scsp.dmlen); + } + + scsp_ccr[0x16 ^ 3] &= 0xE0; + + scsp_sound_interrupt(0x10); + scsp_main_interrupt(0x10); +} + +//////////////////////////////////////////////////////////////// +// Key ON/OFF event handler + +static void scsp_slot_keyon(slot_t *slot) +{ + // key need to be released before being pressed ;) + if (slot->ecurp == SCSP_ENV_RELEASE) + { + slog("key on slot %d\n", slot - &(scsp.slot[0])); + + // set buffer, loop start/end address of the slot + if (slot->pcm8b) + { + slot->buf8 = (s8*) &(scsp.scsp_ram[slot->sa]); + if ((slot->sa + (slot->lea >> SCSP_FREQ_LB)) > SCSP_RAM_MASK) + { + slot->lea = (SCSP_RAM_MASK - slot->sa) << SCSP_FREQ_LB; + } + } + else + { + slot->buf16 = (s16*) &(scsp.scsp_ram[slot->sa & ~1]); + if ((slot->sa + (slot->lea >> (SCSP_FREQ_LB - 1))) > SCSP_RAM_MASK) + { + slot->lea = (SCSP_RAM_MASK - slot->sa) << (SCSP_FREQ_LB - 1); + } + } + + slot->fcnt = 0; // we reset frequency counter + slot->ecnt = SCSP_ENV_AS; // we reset enveloppe counter (probably wrong ... convert decay to attack) + slot->einc = slot->einca; // enveloppe counter step is attack step + slot->ecmp = SCSP_ENV_AE; // limit to reach for next event (Attack End) + slot->ecurp = SCSP_ENV_ATTACK; // current enveloppe phase is attack + slot->enxt = scsp_attack_next; // function pointer to next event + } +} + +static void scsp_slot_keyoff(slot_t *slot) +{ + // key need to be pressed before being released ;) + if (slot->ecurp != SCSP_ENV_RELEASE) + { + slog("key off slot %d\n", slot - &(scsp.slot[0])); + + // if we still are in attack phase at release time, convert attack to decay + if (slot->ecurp == SCSP_ENV_ATTACK) slot->ecnt = SCSP_ENV_DE - slot->ecnt; + slot->einc = slot->eincr; + slot->ecmp = SCSP_ENV_DE; + slot->ecurp = SCSP_ENV_RELEASE; + slot->enxt = scsp_release_next; + } +} + +static void scsp_slot_keyonoff(void) +{ + slot_t *slot; + + for(slot = &(scsp.slot[0]); slot < &(scsp.slot[32]); slot++) + { + if (slot->key) scsp_slot_keyon(slot); + else scsp_slot_keyoff(slot); + } +} + +//////////////////////////////////////////////////////////////// +// Enveloppe Events Handler + +#if 0 + + Max EG level = 0x3FF /|\ + / | \ + / | \_____ + Min EG level = 0x000 __/ | | |\___ + A D1 D2 R + +#endif + +static void scsp_env_null_next(slot_t *slot) +{ + // only to prevent null call pointer... +} + +static void scsp_release_next(slot_t *slot) +{ + // end of release happened, update to process the next phase... + + slot->ecnt = SCSP_ENV_DE; + slot->einc = 0; + slot->ecmp = SCSP_ENV_DE + 1; + slot->enxt = scsp_env_null_next; +} + +static void scsp_substain_next(slot_t *slot) +{ + // end of subtain happened, update to process the next phase... + + slot->ecnt = SCSP_ENV_DE; + slot->einc = 0; + slot->ecmp = SCSP_ENV_DE + 1; + slot->enxt = scsp_env_null_next; +} + +static void scsp_decay_next(slot_t *slot) +{ + // end of decay happened, update to process the next phase... + + slot->ecnt = slot->sl; + slot->einc = slot->eincs; + slot->ecmp = SCSP_ENV_DE; + slot->ecurp = SCSP_ENV_SUBSTAIN; + slot->enxt = scsp_substain_next; +} + +static void scsp_attack_next(slot_t *slot) +{ + // end of attack happened, update to process the next phase... + + slot->ecnt = SCSP_ENV_DS; + slot->einc = slot->eincd; + slot->ecmp = slot->sl; + slot->ecurp = SCSP_ENV_DECAY; + slot->enxt = scsp_decay_next; +} + +//////////////////////////////////////////////////////////////// +// Slot Access + +void scsp_slot_set_b(u32 s, u32 a, u8 d) +{ + slot_t *slot = &(scsp.slot[s]); + + slog("slot %d : reg %.2X = %.2X\n", s, a & 0x1F, d); + + scsp_isr[a ^ 3] = d; + + switch(a & 0x1F){ + + case 0x00: + slot->key = (d >> 3) & 1; + slot->sbctl = (d >> 1) & 3; + slot->ssctl = (slot->ssctl & 1) + ((d & 1) << 1); + + if (d & 0x10) scsp_slot_keyonoff(); + return; + + case 0x01: + slot->ssctl = (slot->ssctl & 2) + ((d >> 7) & 1); + slot->lpctl = (d >> 5) & 3; + slot->pcm8b = d & 0x10; + slot->sa = (slot->sa & 0x0FFFF) + ((d & 0xF) << 16); + slot->sa &= SCSP_RAM_MASK; + return; + + case 0x02: + slot->sa = (slot->sa & 0xF00FF) + (d << 8); + slot->sa &= SCSP_RAM_MASK; + return; + + case 0x03: + slot->sa = (slot->sa & 0xFFF00) + d; + slot->sa &= SCSP_RAM_MASK; + return; + + case 0x04: + slot->lsa = (slot->lsa & (0x00FF << SCSP_FREQ_LB)) + (d << (8 + SCSP_FREQ_LB)); + return; + + case 0x05: + slot->lsa = (slot->lsa & (0xFF00 << SCSP_FREQ_LB)) + (d << SCSP_FREQ_LB); + return; + + case 0x06: + slot->lea = (slot->lea & (0x00FF << SCSP_FREQ_LB)) + (d << (8 + SCSP_FREQ_LB)); + return; + + case 0x07: + slot->lea = (slot->lea & (0xFF00 << SCSP_FREQ_LB)) + (d << SCSP_FREQ_LB); + return; + + case 0x08: + slot->sr = (d >> 3) & 0x1F; + slot->dr = (slot->dr & 0x03) + ((d & 7) << 2); + + if (slot->sr) slot->srp = &scsp_decay_rate[slot->sr << 1]; + else slot->srp = &scsp_null_rate[0]; + if (slot->dr) slot->drp = &scsp_decay_rate[slot->dr << 1]; + else slot->drp = &scsp_null_rate[0]; + + slot->eincs = slot->srp[(14 - slot->fsft) >> slot->krs]; + slot->eincd = slot->drp[(14 - slot->fsft) >> slot->krs]; + return; + + case 0x09: + slot->dr = (slot->dr & 0x1C) + ((d >> 6) & 3); + slot->eghold = d & 0x20; + slot->ar = d & 0x1F; + + if (slot->dr) slot->drp = &scsp_decay_rate[slot->dr << 1]; + else slot->drp = &scsp_null_rate[0]; + if (slot->ar) slot->arp = &scsp_attack_rate[slot->ar << 1]; + else slot->arp = &scsp_null_rate[0]; + + slot->eincd = slot->drp[(14 - slot->fsft) >> slot->krs]; + slot->einca = slot->arp[(14 - slot->fsft) >> slot->krs]; + return; + + case 0x0A: + slot->lslnk = d & 0x40; + slot->krs = (d >> 2) & 0xF; + if (slot->krs == 0xF) slot->krs = 4; + else slot->krs >>= 2; + slot->sl &= 0xE0 << SCSP_ENV_LB; + slot->sl += (d & 3) << (8 + SCSP_ENV_LB); + slot->sl += SCSP_ENV_DS; // adjusted for enveloppe compare (ecmp) + return; + + case 0x0B: + slot->sl &= 0x300 << SCSP_ENV_LB; + slot->sl += (d & 0xE0) << SCSP_ENV_LB; + slot->sl += SCSP_ENV_DS; // adjusted for enveloppe compare (ecmp) + slot->rr = d & 0x1F; + + if (slot->rr) slot->rrp = &scsp_decay_rate[slot->rr << 1]; + else slot->rrp = &scsp_null_rate[0]; + + slot->eincr = slot->rrp[(14 - slot->fsft) >> slot->krs]; + return; + + case 0x0C: + slot->sdir = d & 2; + slot->swe = d & 1; + return; + + case 0x0D: + slot->tl = (d & 0xFF) << 2; // adjusted for enveloppe substract + return; + + case 0x0E: + slot->mdl = (d >> 4) & 0xF; // need to adjust for correct shift + slot->mdx = (slot->mdx & 3) + ((d & 0xF) << 2); + return; + + case 0x0F: + slot->mdx = (slot->mdx & 0x3C) + ((d >> 6) & 3); + slot->mdy = d & 0x3F; + return; + + case 0x10: + if (d & 0x40) slot->fsft = 7 + ((-(d >> 3)) & 7); + else slot->fsft = ((d >> 3) & 7) ^ 7; + slot->finct = (slot->finct & 0x7F80) + ((d & 3) << (8 + 7)); + slot->finc = (0x20000 + slot->finct) >> slot->fsft; + return; + + case 0x11: + slot->finct = (slot->finct & 0x18000) + (d << 7); + slot->finc = (0x20000 + slot->finct) >> slot->fsft; + return; + + case 0x12: + if (d & 0x80) + { + slot->lfoinc = -1; + return; + } + else if (slot->lfoinc == -1) slot->lfocnt = 0; + + slot->lfoinc = scsp_lfo_step[(d >> 2) & 0x1F]; + + switch(d & 3){ + case 0: + slot->lfofmw = scsp_lfo_sawt_f; + return; + + case 1: + slot->lfofmw = scsp_lfo_squa_f; + return; + + case 2: + slot->lfofmw = scsp_lfo_tri_f; + return; + + case 3: + slot->lfofmw = scsp_lfo_noi_f; + return; + } + + case 0x13: + if ((d >> 5) & 7) slot->lfofms = ((d >> 5) & 7) + 7; + else slot->lfofms = 31; + if (d & 7) slot->lfoems = ((d & 7) ^ 7) + 4; + else slot->lfoems = 31; + + switch((d >> 3) & 3){ + case 0: + slot->lfoemw = scsp_lfo_sawt_e; + return; + + case 1: + slot->lfoemw = scsp_lfo_squa_e; + return; + + case 2: + slot->lfoemw = scsp_lfo_tri_e; + return; + + case 3: + slot->lfoemw = scsp_lfo_noi_e; + return; + } + + case 0x15: + if (d & 7) slot->imxl = ((d & 7) ^ 7) + SCSP_ENV_HB; + else slot->imxl = 31; + return; + + case 0x16: + if (d & 0xE0) + { + // adjusted for enveloppe calculation + // some inaccuracy in panning though... + slot->dislr = slot->disll = (((d >> 5) & 7) ^ 7) + SCSP_ENV_HB; + if (d & 0x10) + { + if ((d & 0xF) == 0xF) slot->disll = 31; + else slot->disll += (d >> 1) & 7; + } + else + { + if ((d & 0xF) == 0xF) slot->dislr = 31; + else slot->dislr += (d >> 1) & 7; + } + } + else slot->dislr = slot->disll = 31; + return; + + case 0x17: + if (d & 0xE0) + { + slot->efslr = slot->efsll = (((d >> 5) & 7) ^ 7) + SCSP_ENV_HB; + if (d & 0x10) + { + if ((d & 0xF) == 0xF) slot->efsll = 31; + else slot->efsll += (d >> 1) & 7; + } + else + { + if ((d & 0xF) == 0xF) slot->efslr = 31; + else slot->efslr += (d >> 1) & 7; + } + } + else slot->efslr = slot->efsll = 31; + return; + } +} + +void scsp_slot_set_w(u32 s, s32 a, u16 d) +{ + slot_t *slot = &(scsp.slot[s]); + + slog("slot %d : reg %.2X = %.4X\n", s, a & 0x1E, d); + + *(u16 *)&scsp_isr[a ^ 2] = d; + + switch((a >> 1) & 0xF){ + + case 0x0: + slot->key = (d >> 11) & 1; + slot->sbctl = (d >> 9) & 3; + slot->ssctl = (d >> 7) & 3; + slot->lpctl = (d >> 5) & 3; + slot->pcm8b = d & 0x10; + slot->sa = (slot->sa & 0x0FFFF) | ((d & 0xF) << 16); + slot->sa &= SCSP_RAM_MASK; + + if (d & 0x1000) scsp_slot_keyonoff(); + return; + + case 0x1: + slot->sa = (slot->sa & 0xF0000) | d; + slot->sa &= SCSP_RAM_MASK; + return; + + case 0x2: + slot->lsa = d << SCSP_FREQ_LB; + return; + + case 0x3: + slot->lea = d << SCSP_FREQ_LB; + return; + + case 0x4: + slot->sr = (d >> 11) & 0x1F; + slot->dr = (d >> 6) & 0x1F; + slot->eghold = d & 0x20; + slot->ar = d & 0x1F; + + if (slot->sr) slot->srp = &scsp_decay_rate[slot->sr << 1]; + else slot->srp = &scsp_null_rate[0]; + if (slot->dr) slot->drp = &scsp_decay_rate[slot->dr << 1]; + else slot->drp = &scsp_null_rate[0]; + if (slot->ar) slot->arp = &scsp_attack_rate[slot->ar << 1]; + else slot->arp = &scsp_null_rate[0]; + + slot->einca = slot->arp[(14 - slot->fsft) >> slot->krs]; + slot->eincd = slot->drp[(14 - slot->fsft) >> slot->krs]; + slot->eincs = slot->srp[(14 - slot->fsft) >> slot->krs]; + return; + + case 0x5: + slot->lslnk = (d >> 8) & 0x40; + slot->krs = (d >> 10) & 0xF; + if (slot->krs == 0xF) slot->krs = 4; + else slot->krs >>= 2; + slot->sl = ((d & 0x3E0) << SCSP_ENV_LB) + SCSP_ENV_DS; // adjusted for enveloppe compare (ecmp) + slot->rr = d & 0x1F; + + if (slot->rr) slot->rrp = &scsp_decay_rate[slot->rr << 1]; + else slot->rrp = &scsp_null_rate[0]; + + slot->eincr = slot->rrp[(14 - slot->fsft) >> slot->krs]; + return; + + case 0x6: + slot->sdir = (d >> 8) & 2; + slot->swe = (d >> 8) & 1; + slot->tl = (d & 0xFF) << 2; // adjusted for enveloppe substract + return; + + case 0x7: + slot->mdl = (d >> 12) & 0xF; // need to adjust for correct shift + slot->mdx = (d >> 6) & 0x3F; + slot->mdy = d & 0x3F; + return; + + case 0x8: + if (d & 0x4000) slot->fsft = 7 + ((-(d >> 11)) & 7); + else slot->fsft = (((d >> 11) & 7) ^ 7); + slot->finc = ((0x400 + (d & 0x3FF)) << 7) >> slot->fsft; + return; + + case 0x9: + if (d & 0x8000) + { + slot->lfoinc = -1; + return; + } + else if (slot->lfoinc == -1) slot->lfocnt = 0; + + slot->lfoinc = scsp_lfo_step[(d >> 10) & 0x1F]; + if ((d >> 5) & 7) slot->lfofms = ((d >> 5) & 7) + 7; + else slot->lfofms = 31; + if (d & 7) slot->lfoems = ((d & 7) ^ 7) + 4; + else slot->lfoems = 31; + + switch((d >> 8) & 3){ + case 0: + slot->lfofmw = scsp_lfo_sawt_f; + break; + + case 1: + slot->lfofmw = scsp_lfo_squa_f; + break; + + case 2: + slot->lfofmw = scsp_lfo_tri_f; + break; + + case 3: + slot->lfofmw = scsp_lfo_noi_f; + break; + } + + switch((d >> 3) & 3){ + case 0: + slot->lfoemw = scsp_lfo_sawt_e; + return; + + case 1: + slot->lfoemw = scsp_lfo_squa_e; + return; + + case 2: + slot->lfoemw = scsp_lfo_tri_e; + return; + + case 3: + slot->lfoemw = scsp_lfo_noi_e; + return; + } + + case 0xA: + if (d & 7) slot->imxl = ((d & 7) ^ 7) + SCSP_ENV_HB; + else slot->imxl = 31; + return; + + case 0xB: + if (d & 0xE000) + { + // adjusted fr enveloppe calculation + // some accuracy lose for panning here... + slot->dislr = slot->disll = (((d >> 13) & 7) ^ 7) + SCSP_ENV_HB; + if (d & 0x1000) + { + if ((d & 0xF00) == 0xF00) slot->disll = 31; + else slot->disll += (d >> 9) & 7; + } + else + { + if ((d & 0xF00) == 0xF00) slot->dislr = 31; + else slot->dislr += (d >> 9) & 7; + } + } + else slot->dislr = slot->disll = 31; + + if (d & 0xE0) + { + slot->efslr = slot->efsll = (((d >> 5) & 7) ^ 7) + SCSP_ENV_HB; + if (d & 0x10) + { + if ((d & 0xF) == 0xF) slot->efsll = 31; + else slot->efsll += (d >> 1) & 7; + } + else + { + if ((d & 0xF) == 0xF) slot->efslr = 31; + else slot->efslr += (d >> 1) & 7; + } + } + else slot->efslr = slot->efsll = 31; + return; + } +} + +u8 scsp_slot_get_b(u32 s, u32 a) +{ + slot_t *slot = &(scsp.slot[s]); + + a &= 0x1F; + + slog("r_b slot %d : reg %.2X\n", s, a); + + if (a == 0x00) return scsp_isr[a ^ 3] & 0xEF; + + return scsp_isr[a ^ 3]; +} + +u16 scsp_slot_get_w(u32 s, u32 a) +{ + slot_t *slot = &(scsp.slot[s]); + + a = (a >> 1) & 0xF; + + slog("r_w slot %d : reg %.2X\n", s, a * 2); + + if (a == 0x00) return *(u16 *)&scsp_isr[a ^ 2] & 0xEFFF; + + return *(u16 *)&scsp_isr[a ^ 2]; +} + +//////////////////////////////////////////////////////////////// +// SCSP Access + +void scsp_set_b(u32 a, u8 d) +{ +// if (a != 0x41D) slog("scsp : reg %.2X = %.2X\n", a & 0x3F, d); + if ((a != 0x408) && (a != 0x41D)) slog("scsp : reg %.2X = %.2X\n", a & 0x3F, d); +// slog("scsp : reg %.2X = %.2X\n", a & 0x3F, d); + + scsp_ccr[a ^ 3] = d; + + switch(a & 0x3F){ + + case 0x01: + scsp.mvol = d & 0xF; + return; + + case 0x02: + scsp.rbl = (scsp.rbl & 1) + ((d & 1) << 1); + return; + + case 0x03: + scsp.rbl = (scsp.rbl & 2) + ((d >> 7) & 1); + scsp.rbp = (d & 0x7F) * (4 * 1024 * 2); + return; + + case 0x07: + scsp_midi_out_send(d); + return; + + case 0x08: + scsp.mslc = (d >> 3) & 0x1F; + return; + + case 0x12: + scsp.dmea = (scsp.dmea & 0x700FE) + (d << 8); + return; + + case 0x13: + scsp.dmea = (scsp.dmea & 0x7FF00) + (d & 0xFE); + return; + + case 0x14: + scsp.dmea = (scsp.dmea & 0xFFFE) + ((d & 0x70) << 12); + scsp.drga = (scsp.drga & 0xFE) + ((d & 0xF) << 8); + return; + + case 0x15: + scsp.drga = (scsp.drga & 0xF00) + (d & 0xFE); + return; + + case 0x16: + scsp.dmlen = (scsp.dmlen & 0xFE) + ((d & 0xF) << 8); + if ((scsp.dmfl = d & 0xF0) & 0x10) scsp_dma(); + return; + + case 0x17: + scsp.dmlen = (scsp.dmlen & 0xF00) + (d & 0xFE); + return; + + case 0x18: + scsp.timasd = d & 7; + return; + + case 0x19: + scsp.timacnt = d << 8; + return; + + case 0x1A: + scsp.timbsd = d & 7; + return; + + case 0x1B: + scsp.timbcnt = d << 8; + return; + + case 0x1C: + scsp.timcsd = d & 7; + return; + + case 0x1D: + scsp.timccnt = d << 8; + return; + + case 0x1E: + scsp.scieb = (scsp.scieb & 0xFF) + (d << 8); + return; + + case 0x1F: + scsp.scieb = (scsp.scieb & 0x700) + d; + return; + + case 0x21: + if (d & 0x20) scsp_sound_interrupt(0x20); + return; + + case 0x22: + scsp.scipd &= ~(d << 8); + return; + + case 0x23: + scsp.scipd &= ~(u32)d; + return; + + case 0x25: + scsp.scilv0 = d; + return; + + case 0x27: + scsp.scilv1 = d; + return; + + case 0x29: + scsp.scilv2 = d; + return; + + case 0x2A: + scsp.mcieb = (scsp.mcieb & 0xFF) + (d << 8); + return; + + case 0x2B: + scsp.mcieb = (scsp.mcieb & 0x700) + d; + return; + + case 0x2D: + if (d & 0x20) scsp_main_interrupt(0x20); + return; + + case 0x2E: + scsp.mcipd &= ~(d << 8); + return; + + case 0x2F: + scsp.mcipd &= ~(u32)d; + return; + } +} + +void scsp_set_w(u32 a, u16 d) +{ + if ((a != 0x418) && (a != 0x41A) && (a != 0x422)) slog("scsp : reg %.2X = %.4X\n", a & 0x3E, d); +// slog("scsp : reg %.2X = %.4X\n", a & 0x3E, d); + + *(u16 *)&scsp_ccr[a ^ 2] = d; + + switch((a >> 1) & 0x1F){ + + case 0x00: + scsp.mvol = d & 0xF; + return; + + case 0x01: + scsp.rbl = (d >> 7) & 3; + scsp.rbp = (d & 0x7F) * (4 * 1024 * 2); + return; + + case 0x03: + scsp_midi_out_send(d & 0xFF); + return; + + case 0x04: + scsp.mslc = (d >> 11) & 0x1F; + scsp.ca = (d >> 7) & 0xF; + return; + + case 0x09: + scsp.dmea = (scsp.dmea & 0x70000) + (d & 0xFFFE); + return; + + case 0x0A: + scsp.dmea = (scsp.dmea & 0xFFFE) + ((d & 0x7000) << 4); + scsp.drga = d & 0xFFE; + return; + + case 0x0B: + scsp.dmlen = d & 0xFFE; + if ((scsp.dmfl = ((d >> 8) & 0xF0)) & 0x10) scsp_dma(); + return; + + case 0x0C: + scsp.timasd = (d >> 8) & 7; + scsp.timacnt = (d & 0xFF) << 8; + return; + + case 0x0D: + scsp.timbsd = (d >> 8) & 7; + scsp.timbcnt = (d & 0xFF) << 8; + return; + + case 0x0E: + scsp.timcsd = (d >> 8) & 7; + scsp.timccnt = (d & 0xFF) << 8; + return; + + case 0x0F: + scsp.scieb = d; + return; + + case 0x10: + if (d & 0x20) scsp_sound_interrupt(0x20); + return; + + case 0x11: + scsp.scipd &= ~d; + return; + + case 0x12: + scsp.scilv0 = d; + return; + + case 0x13: + scsp.scilv1 = d; + return; + + case 0x14: + scsp.scilv2 = d; + return; + + case 0x15: + scsp.mcieb = d; + return; + + case 0x16: + if (d & 0x20) scsp_main_interrupt(0x20); + return; + + case 0x18: + scsp.mcipd &= ~d; + return; + } +} + +u8 scsp_get_b(u32 a) +{ + a &= 0x3F; + +// if (a != 0x21) slog("r_b scsp : reg %.2X\n", a); + if ((a != 0x09) && (a != 0x21)) slog("r_b scsp : reg %.2X\n", a); +// if (a == 0x09) slog("r_b scsp 09 = %.2X\n", ((scsp.slot[scsp.mslc].fcnt >> (SCSP_FREQ_LB + 12)) & 0x1) << 7); +// slog("r_b scsp : reg %.2X\n", a); + + switch(a){ + + case 0x01: + scsp_ccr[a ^ 3] &= 0x0F; + break; + + case 0x04: + return scsp.midflag; + + case 0x05: + return scsp_midi_in_read(); + + case 0x07: + return scsp_midi_out_read(); + + case 0x08: + return ((scsp.slot[scsp.mslc].fcnt >> (SCSP_FREQ_LB + 12)) & 0xE) >> 1; + + case 0x09: + return ((scsp.slot[scsp.mslc].fcnt >> (SCSP_FREQ_LB + 12)) & 0x1) << 7; + } + + return scsp_ccr[a ^ 3]; +} + +u16 scsp_get_w(u32 a) +{ + a = (a >> 1) & 0x1F; + + if (a != 0x10) slog("r_w scsp : reg %.2X\n", a * 2); + + switch(a){ + + case 0x00: + *(u16 *)&scsp_ccr[a ^ 2] &= 0xFF0F; + break; + + case 0x02: + return (scsp.midflag << 8) | scsp_midi_in_read(); + + case 0x03: + return scsp_midi_out_read(); + + case 0x04: + return (scsp.slot[scsp.mslc].fcnt >> (SCSP_FREQ_LB + 12)) & 0xF; + } + + return *(u16 *)&scsp_ccr[a ^ 2]; +} + +//////////////////////////////////////////////////////////////// +// Synth Slot +// +// slog("outL=%.8X bufL=%.8X disll=%d\n", outL, scsp_bufL[scsp_buf_pos], slot->disll); + +//////////////////////////////////////////////////////////////// + +#define SCSP_GET_OUT_8B \ + out = (s32) slot->buf8[(slot->fcnt >> SCSP_FREQ_LB) ^ 1]; + +#define SCSP_GET_OUT_16B \ + out = (s32) slot->buf16[slot->fcnt >> SCSP_FREQ_LB]; + +#define SCSP_GET_ENV \ + env = scsp_env_table[slot->ecnt >> SCSP_ENV_LB] - slot->tl; + +#define SCSP_GET_ENV_LFO \ + env = (scsp_env_table[slot->ecnt >> SCSP_ENV_LB] - slot->tl) - (slot->lfoemw[(slot->lfocnt >> SCSP_LFO_LB) & SCSP_LFO_MASK] >> slot->lfoems); + +#define SCSP_OUT_8B_L \ + if ((out) && (env > 0)) \ + { \ + out *= env; \ + scsp_bufL[scsp_buf_pos] += out >> (slot->disll - 8); \ + } + +#define SCSP_OUT_8B_R \ + if ((out) && (env > 0)) \ + { \ + out *= env; \ + scsp_bufR[scsp_buf_pos] += out >> (slot->dislr - 8); \ + } + +#define SCSP_OUT_8B_LR \ + if ((out) && (env > 0)) \ + { \ + out *= env; \ + scsp_bufL[scsp_buf_pos] += out >> (slot->disll - 8); \ + scsp_bufR[scsp_buf_pos] += out >> (slot->dislr - 8); \ + } + +#define SCSP_OUT_16B_L \ + if ((out) && (env > 0)) \ + { \ + out *= env; \ + scsp_bufL[scsp_buf_pos] += out >> slot->disll; \ + } + +#define SCSP_OUT_16B_R \ + if ((out) && (env > 0)) \ + { \ + out *= env; \ + scsp_bufR[scsp_buf_pos] += out >> slot->dislr; \ + } + +#define SCSP_OUT_16B_LR \ + if ((out) && (env > 0)) \ + { \ + out *= env; \ + scsp_bufL[scsp_buf_pos] += out >> slot->disll; \ + scsp_bufR[scsp_buf_pos] += out >> slot->dislr; \ + } + +#define SCSP_UPDATE_PHASE \ + if ((slot->fcnt += slot->finc) > slot->lea) \ + { \ + if (slot->lpctl) slot->fcnt = slot->lsa; \ + else \ + { \ + slot->ecnt = SCSP_ENV_DE; \ + return; \ + } \ + } + +#define SCSP_UPDATE_PHASE_LFO \ + slot->fcnt += slot->finc + ((slot->lfofmw[(slot->lfocnt >> SCSP_LFO_LB) & SCSP_LFO_MASK] << slot->lfofms) >> slot->fsft); \ + if ((slot->fcnt += slot->finc) > slot->lea) \ + { \ + if (slot->lpctl) slot->fcnt = slot->lsa; \ + else \ + { \ + slot->ecnt = SCSP_ENV_DE; \ + return; \ + } \ + } + +#define SCSP_UPDATE_ENV \ + if ((slot->ecnt += slot->einc) >= slot->ecmp) \ + { \ + slot->enxt(slot); \ + if (slot->ecnt >= SCSP_ENV_DE) return; \ + } + +#define SCSP_UPDATE_LFO \ + slot->lfoinc += slot->lfocnt; + +//////////////////////////////////////////////////////////////// + +static void scsp_slot_update_null(slot_t *slot) +{ + +} + +//////////////////////////////////////////////////////////////// +// Normal 8 bits + +static void scsp_slot_update_8B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + // env = [0..0x3FF] - slot->tl + SCSP_GET_OUT_8B + SCSP_GET_ENV + + // don't waste time if no sound... + SCSP_OUT_8B_L + + // calculate new frequency (phase) counter and enveloppe counter + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + } +} + +static void scsp_slot_update_8B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV + + SCSP_OUT_8B_R + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + } +} + +static void scsp_slot_update_8B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV + + SCSP_OUT_8B_LR + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + } +} + +//////////////////////////////////////////////////////////////// +// Enveloppe LFO modulation 8 bits + +static void scsp_slot_update_E_8B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV_LFO + + SCSP_OUT_8B_L + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_E_8B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV_LFO + + SCSP_OUT_8B_R + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_E_8B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV_LFO + + SCSP_OUT_8B_LR + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +//////////////////////////////////////////////////////////////// +// Frequency LFO modulation 8 bits + +static void scsp_slot_update_F_8B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV + + SCSP_OUT_8B_L + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_8B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV + + SCSP_OUT_8B_R + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_8B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV + + SCSP_OUT_8B_LR + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +//////////////////////////////////////////////////////////////// +// Enveloppe & Frequency LFO modulation 8 bits + +static void scsp_slot_update_F_E_8B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV_LFO + + SCSP_OUT_8B_L + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_E_8B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV_LFO + + SCSP_OUT_8B_R + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_E_8B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_8B + SCSP_GET_ENV_LFO + + SCSP_OUT_8B_LR + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +//////////////////////////////////////////////////////////////// +// Normal 16 bits + +static void scsp_slot_update_16B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV + + SCSP_OUT_16B_L + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + } +} + +static void scsp_slot_update_16B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV + + SCSP_OUT_16B_R + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + } +} + +static void scsp_slot_update_16B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV + + SCSP_OUT_16B_LR + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + } +} + +//////////////////////////////////////////////////////////////// +// Enveloppe LFO modulation 16 bits + +static void scsp_slot_update_E_16B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV_LFO + + SCSP_OUT_16B_L + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_E_16B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV_LFO + + SCSP_OUT_16B_R + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_E_16B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV_LFO + + SCSP_OUT_16B_LR + + SCSP_UPDATE_PHASE + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +//////////////////////////////////////////////////////////////// +// Frequency LFO modulation 16 bits + +static void scsp_slot_update_F_16B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV + + SCSP_OUT_16B_L + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_16B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV + + SCSP_OUT_16B_R + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_16B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV + + SCSP_OUT_16B_LR + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +//////////////////////////////////////////////////////////////// +// Enveloppe & Frequency LFO modulation 16 bits + +static void scsp_slot_update_F_E_16B_L(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV_LFO + + SCSP_OUT_16B_L + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_E_16B_R(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV_LFO + + SCSP_OUT_16B_R + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +static void scsp_slot_update_F_E_16B_LR(slot_t *slot) +{ + s32 out, env; + + for(; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) + { + SCSP_GET_OUT_16B + SCSP_GET_ENV_LFO + + SCSP_OUT_16B_LR + + SCSP_UPDATE_PHASE_LFO + SCSP_UPDATE_ENV + SCSP_UPDATE_LFO + } +} + +//////////////////////////////////////////////////////////////// +// Update functions + +static void (*scsp_slot_update_p[2][2][2][2][2])(slot_t *slot) = +{ + // NO FMS + { // NO EMS + { // 8 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_8B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_8B_L, + // RIGHT + scsp_slot_update_8B_LR + }, + }, + // 16 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_16B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_16B_L, + // RIGHT + scsp_slot_update_16B_LR + }, + } + }, + // EMS + { // 8 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_E_8B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_E_8B_L, + // RIGHT + scsp_slot_update_E_8B_LR + }, + }, + // 16 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_E_16B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_E_16B_L, + // RIGHT + scsp_slot_update_E_16B_LR + }, + } + } + }, + // FMS + { // NO EMS + { // 8 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_F_8B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_F_8B_L, + // RIGHT + scsp_slot_update_F_8B_LR + }, + }, + // 16 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_F_16B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_F_16B_L, + // RIGHT + scsp_slot_update_F_16B_LR + }, + } + }, + // EMS + { // 8 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_F_E_8B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_F_E_8B_L, + // RIGHT + scsp_slot_update_F_E_8B_LR + }, + }, + // 16 BITS + { // NO LEFT + { // NO RIGHT + scsp_slot_update_null, + // RIGHT + scsp_slot_update_F_E_16B_R + }, + // LEFT + { // NO RIGHT + scsp_slot_update_F_E_16B_L, + // RIGHT + scsp_slot_update_F_E_16B_LR + }, + } + } + } +}; + +void scsp_update(s32 *bufL, s32 *bufR, u32 len) +{ + slot_t *slot; + + scsp_bufL = bufL; + scsp_bufR = bufR; + + for(slot = &(scsp.slot[0]); slot < &(scsp.slot[32]); slot++) + { + if (slot->ecnt >= SCSP_ENV_DE) continue; // enveloppe null... + + if (slot->ssctl) continue; // not yet supported ! + + scsp_buf_len = len; + scsp_buf_pos = 0; + + // take effect sound volume if no direct sound volume... + if ((slot->disll == 31) && (slot->dislr == 31)) + { + slot->disll = slot->efsll; + slot->dislr = slot->efslr; + } + +// slog("update : VL=%d VR=%d CNT=%.8X STEP=%.8X\n", slot->disll, slot->dislr, slot->fcnt, slot->finc); + + scsp_slot_update_p[(slot->lfofms == 31)?0:1][(slot->lfoems == 31)?0:1][(slot->pcm8b == 0)?1:0][(slot->disll == 31)?0:1][(slot->dislr == 31)?0:1](slot); + } +} + +void scsp_update_timer(u32 len) +{ + if (scsp.timacnt != 0xFF00) + { + scsp.timacnt += len << (8 - scsp.timasd); + if (scsp.timacnt >= 0xFF00) + { + scsp_sound_interrupt(0x40); + scsp_main_interrupt(0x40); + scsp.timacnt = 0xFF00; + } + } + + if (scsp.timbcnt != 0xFF00) + { + scsp.timbcnt += len << (8 - scsp.timbsd); + if (scsp.timbcnt >= 0xFF00) + { + scsp_sound_interrupt(0x80); + scsp_main_interrupt(0x80); + scsp.timbcnt = 0xFF00; + } + } + + if (scsp.timccnt != 0xFF00) + { + scsp.timccnt += len << (8 - scsp.timcsd); + if (scsp.timccnt >= 0xFF00) + { + scsp_sound_interrupt(0x100); + scsp_main_interrupt(0x100); + scsp.timccnt = 0xFF00; + } + } + + // 1F interrupt can't be accurate here... + if (len) + { + scsp_sound_interrupt(0x400); + scsp_main_interrupt(0x400); + } +} + +//////////////////////////////////////////////////////////////// +// MIDI + +void scsp_midi_in_send(u8 data) +{ + if (scsp.midflag & SCSP_MIDI_IN_EMP) + { + scsp_sound_interrupt(0x8); + scsp_main_interrupt(0x8); + } + + scsp.midflag &= ~SCSP_MIDI_IN_EMP; + + if (scsp.midincnt > 3) + { + scsp.midflag |= SCSP_MIDI_IN_OVF; + return; + } + + scsp.midinbuf[scsp.midincnt++] = data; + + if (scsp.midincnt > 3) scsp.midflag |= SCSP_MIDI_IN_FUL; +} + +void scsp_midi_out_send(u8 data) +{ + scsp.midflag &= ~SCSP_MIDI_OUT_EMP; + + if (scsp.midoutcnt > 3) return; + + scsp.midoutbuf[scsp.midoutcnt++] = data; + + if (scsp.midoutcnt > 3) scsp.midflag |= SCSP_MIDI_OUT_FUL; +} + +u8 scsp_midi_in_read(void) +{ + u8 data; + + scsp.midflag &= ~(SCSP_MIDI_IN_OVF | SCSP_MIDI_IN_FUL); + + if (scsp.midincnt > 0) + { + if (scsp.midincnt > 1) + { + scsp_sound_interrupt(0x8); + scsp_main_interrupt(0x8); + } + else scsp.midflag |= SCSP_MIDI_IN_EMP; + + data = scsp.midinbuf[0]; + + switch((--scsp.midincnt) & 3) + { + case 1: + scsp.midinbuf[0] = scsp.midinbuf[1]; + break; + + case 2: + scsp.midinbuf[0] = scsp.midinbuf[1]; + scsp.midinbuf[1] = scsp.midinbuf[2]; + break; + + case 3: + scsp.midinbuf[0] = scsp.midinbuf[1]; + scsp.midinbuf[1] = scsp.midinbuf[2]; + scsp.midinbuf[2] = scsp.midinbuf[3]; + break; + } + + return data; + } + + return 0xFF; +} + +u8 scsp_midi_out_read(void) +{ + u8 data; + + scsp.midflag &= ~SCSP_MIDI_OUT_FUL; + + if (scsp.midoutcnt > 0) + { + if (scsp.midoutcnt == 1) + { + scsp.midflag |= SCSP_MIDI_OUT_EMP; + scsp_sound_interrupt(0x200); + scsp_main_interrupt(0x200); + } + + data = scsp.midoutbuf[0]; + + switch(--scsp.midoutcnt & 3) + { + case 1: + scsp.midoutbuf[0] = scsp.midoutbuf[1]; + break; + + case 2: + scsp.midoutbuf[0] = scsp.midoutbuf[1]; + scsp.midoutbuf[1] = scsp.midoutbuf[2]; + break; + + case 3: + scsp.midoutbuf[0] = scsp.midoutbuf[1]; + scsp.midoutbuf[1] = scsp.midoutbuf[2]; + scsp.midoutbuf[2] = scsp.midoutbuf[3]; + break; + } + + return data; + } + + return 0xFF; +} + +//////////////////////////////////////////////////////////////// +// Access + +void FASTCALL scsp_w_b(u32 a, u8 d) +{ + a &= 0xFFF; + + if (a < 0x400) + { + scsp_slot_set_b(a >> 5, a, d); + return; + } + else if (a < 0x600) + { + if (a < 0x440) scsp_set_b(a, d); + return; + } + else if (a < 0x700) + { + return; + } + else if (a < 0xee4) + { + a &= 0x3ff; + scsp_dcr[a ^ 3] = d; + return; + } + + slog("ERROR: scsp w_b to %08lx w/ %02x\n", a, d); +} + +//////////////////////////////////////////////////////////////// + +void FASTCALL scsp_w_w(u32 a, u16 d) +{ + if (a & 1) + { + slog("ERROR: scsp w_w misaligned : %.8X\n", a); + } + + a &= 0xFFE; + + if (a < 0x400) + { + scsp_slot_set_w(a >> 5, a, d); + return; + } + else if (a < 0x600) + { + if (a < 0x440) scsp_set_w(a, d); + return; + } + else if (a < 0x700) + { + return; + } + else if (a < 0xee4) + { + a &= 0x3ff; + *(u16 *)&scsp_dcr[a ^ 2] = d; + return; + } + + slog("ERROR: scsp w_w to %08lx w/ %04x\n", a, d); +} + +//////////////////////////////////////////////////////////////// + +void FASTCALL scsp_w_d(u32 a, u32 d) +{ + if (a & 3) + { + slog("ERROR: scsp w_d misaligned : %.8X\n", a); + } + + a &= 0xFFC; + + if (a < 0x400) + { + scsp_slot_set_w(a >> 5, a + 0, d >> 16); + scsp_slot_set_w(a >> 5, a + 2, d & 0xFFFF); + return; + } + else if (a < 0x600) + { + if (a < 0x440) + { + scsp_set_w(a + 0, d >> 16); + scsp_set_w(a + 2, d & 0xFFFF); + } + return; + } + else if (a < 0x700) + { + return; + } + else if (a < 0xee4) + { + a &= 0x3ff; + *(u32 *)&scsp_dcr[a] = d; + return; + } + + slog("ERROR: scsp w_d to %08lx w/ %08lx\n", a, d); +} + +//////////////////////////////////////////////////////////////// + +u8 FASTCALL scsp_r_b(u32 a) +{ + a &= 0xFFF; + + LOG("error.log", "SCSP : r_b %08lx\n", a); + + if (a < 0x400) + { + return scsp_slot_get_b(a >> 5, a); + } + else if (a < 0x600) + { + if (a < 0x440) return scsp_get_b(a); + return 0; + } + else if (a < 0x700) + { + return 0; + } + else if (a < 0xee4) + { + return 0; + } + + slog("ERROR: scsp r_b to %08lx\n", a); + + return 0; +} + +//////////////////////////////////////////////////////////////// + +u16 FASTCALL scsp_r_w(u32 a) +{ + if (a & 1) + { + slog("ERROR: scsp r_w misaligned : %.8X\n", a); + } + + if(a != 0x00100420) + LOG("error.log", "SCSP : r_w %08lx\n", a); + + a &= 0xFFE; + + if (a < 0x400) + { + return scsp_slot_get_w(a >> 5, a); + } + else if (a < 0x600) + { + if (a < 0x440) return scsp_get_w(a); + return 0; + } + else if (a < 0x700) + { + return 0; + } + else if (a < 0xee4) + { + return 0; + } + + slog("ERROR: scsp r_w to %08lx\n", a); + + return 0; +} + +//////////////////////////////////////////////////////////////// + +u32 FASTCALL scsp_r_d(u32 a) +{ + if (a & 3) + { + slog("ERROR: scsp r_d misaligned : %.8X\n", a); + } + + LOG("error.log", "SCSP : r_d %08lx\n", a); + + a &= 0xFFC; + + if (a < 0x400) + { + return (scsp_slot_get_w(a >> 5, a + 0) << 16) + scsp_slot_get_w(a >> 5, a + 1); + } + else if (a < 0x600) + { + if (a < 0x440) return (scsp_get_w(a + 0) << 16) + scsp_get_w(a + 1); + return 0; + } + else if (a < 0x700) + { + return(0); + } + else if (a < 0xee4) + { + return(0); + } + + slog("ERROR: scsp r_d to %08lx\n", a); + + return 0; +} + +//////////////////////////////////////////////////////////////// +// Interface + +void scsp_shutdown(void) +{ + + if (scsp_reg) + { + free(scsp_reg); + } + + scsp_reg = NULL; +} + +void scsp_reset(void) +{ + slot_t *slot; + + memset(scsp.scsp_ram, 0, SCSP_RAM_SIZE); + memset(scsp_reg, 0, 0x1000); + memset(scsp_isr, 0, 0x400); + memset(scsp_ccr, 0, 0x30); + memset(scsp_dcr, 0, 0x800); + + scsp.mvol = 0; + scsp.rbl = 0; + scsp.rbp = 0; + scsp.mslc = 0; + scsp.ca = 0; + + scsp.dmea = 0; + scsp.drga = 0; + scsp.dmfl = 0; + scsp.dmlen = 0; + + scsp.midincnt = 0; + scsp.midoutcnt = 0; + scsp.midflag = SCSP_MIDI_IN_EMP | SCSP_MIDI_OUT_EMP; + scsp.midflag2 = 0; + + scsp.timacnt = 0xFF00; + scsp.timbcnt = 0xFF00; + scsp.timccnt = 0xFF00; + scsp.timasd = 0; + scsp.timbsd = 0; + scsp.timcsd = 0; + + scsp.mcieb = 0; + scsp.mcipd = 0; + scsp.scieb = 0; + scsp.scipd = 0; + scsp.scilv0 = 0; + scsp.scilv1 = 0; + scsp.scilv2 = 0; + + for(slot = &(scsp.slot[0]); slot < &(scsp.slot[32]); slot++) + { + memset(slot, 0, sizeof(slot_t)); + slot->ecnt = SCSP_ENV_DE; // slot off + slot->dislr = slot->disll = 31; // direct level sound off + slot->efslr = slot->efsll = 31; // effect level sound off + } +} + +void scsp_init(u8 *scsp_ram, void *sint_hand, void *mint_hand) +{ + u32 i, j; + double x; + + scsp_shutdown(); + + scsp_reg = (u8 *)malloc(0x1000); + scsp_isr = &scsp_reg[0x0000]; + scsp_ccr = &scsp_reg[0x0400]; + scsp_dcr = &scsp_reg[0x0700]; + + scsp.scsp_ram = scsp_ram; + scsp.sintf = sint_hand; + scsp.mintf = mint_hand; + + for(i = 0; i < SCSP_ENV_LEN; i++) + { + // Attack Curve (x^4 ?) + x = pow(((double) (SCSP_ENV_MASK - i) / (double) (SCSP_ENV_LEN)), 4); + x *= (double) SCSP_ENV_LEN; + scsp_env_table[i] = SCSP_ENV_MASK - (s32) x; + + // Decay curve (x = linear) + x = pow(((double) (i) / (double) (SCSP_ENV_LEN)), 1); + x *= (double) SCSP_ENV_LEN; + scsp_env_table[i + SCSP_ENV_LEN] = SCSP_ENV_MASK - (s32) x; + } + + for(i = 0, j = 0; i < 32; i++) + { + j += 1 << (i >> 2); + // lfo freq + x = 172.3 / (double) (j); + // converting lfo freq in lfo step + scsp_lfo_step[31 - i] = scsp_round(x * ((double) (SCSP_LFO_LEN) / (double) (SCSP_FREQ)) * (double) (1 << SCSP_LFO_LB)); + } + + for(i = 0; i < SCSP_LFO_LEN; i++) + { + scsp_lfo_sawt_e[i] = SCSP_LFO_MASK - i; + if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_squa_e[i] = SCSP_LFO_MASK; + else scsp_lfo_squa_e[i] = 0; + if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_tri_e[i] = SCSP_LFO_MASK - (i * 2); + else scsp_lfo_tri_e[i] = (i - (SCSP_LFO_LEN / 2)) * 2; + scsp_lfo_noi_e[i] = rand() & SCSP_LFO_MASK; + + scsp_lfo_sawt_f[i] = i - (SCSP_LFO_LEN / 2); + if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_squa_f[i] = 0 - (SCSP_LFO_LEN / 2); + else scsp_lfo_squa_f[i] = SCSP_LFO_MASK - (SCSP_LFO_LEN / 2); + if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_tri_f[i] = (i * 2) - (SCSP_LFO_LEN / 2); + else scsp_lfo_tri_f[i] = (SCSP_LFO_MASK - ((i - (SCSP_LFO_LEN / 2)) * 2)) - (SCSP_LFO_LEN / 2); + scsp_lfo_noi_f[i] = scsp_lfo_noi_e[i] - (SCSP_LFO_LEN / 2); + } + + for(i = 0; i < 4; i++) + { + scsp_attack_rate[i] = 0; + scsp_decay_rate[i] = 0; + } + + for(i = 0; i < 60; i++) + { + x = 1.0 + ((i & 3) * 0.25); // bits 0-1 : x1.00, x1.25, x1.50, x1.75 + x *= (double) (1 << ((i >> 2))); // bits 2-5 : shift bits (x2^0 - x2^15) + x *= (double) (SCSP_ENV_LEN << SCSP_ENV_LB); // on ajuste pour le tableau scsp_env_table + + scsp_attack_rate[i + 4] = scsp_round(x / (double) SCSP_ATTACK_R); + scsp_decay_rate[i + 4] = scsp_round(x / (double) SCSP_DECAY_R); + + if (scsp_attack_rate[i + 4] == 0) scsp_attack_rate[i + 4] = 1; + if (scsp_decay_rate[i + 4] == 0) scsp_decay_rate[i + 4] = 1; + } + + scsp_attack_rate[63] = SCSP_ENV_AE; + scsp_decay_rate[61] = scsp_decay_rate[60]; + scsp_decay_rate[62] = scsp_decay_rate[60]; + scsp_decay_rate[63] = scsp_decay_rate[60]; + + for(i = 64; i < 96; i++) + { + scsp_attack_rate[i] = scsp_attack_rate[63]; + scsp_decay_rate[i] = scsp_decay_rate[63]; + scsp_null_rate[i - 64] = 0; + } + + for(i = 0; i < 96; i++) + { + slog("attack rate[%d] = %.8X -> %.8X\n", i, scsp_attack_rate[i], scsp_attack_rate[i] >> SCSP_ENV_LB); + slog("decay rate[%d] = %.8X -> %.8X\n", i, scsp_decay_rate[i], scsp_decay_rate[i] >> SCSP_ENV_LB); + } + + scsp_reset(); +} diff --git a/core/scsp.h b/core/scsp.h new file mode 100644 index 0000000..53f37cb --- /dev/null +++ b/core/scsp.h @@ -0,0 +1,29 @@ + +#ifndef _SCSP_H_ +#define _SCSP_H_ + +extern void scsp_shutdown(void); +extern void scsp_init(UINT8 *scsp_ram, void *sint_hand, void *mint_hand); +extern void scsp_reset(void); + +extern void scsp_update(INT32 *bufL, INT32 *bufR, UINT32 len); +extern void scsp_update_timer(UINT32 len); + +extern UINT32 scsp_read_8(UINT32 a); +extern UINT32 scsp_read_16(UINT32 a); +extern UINT32 scsp_read_32(UINT32 a); + +extern void scsp_write_8(UINT32 a, UINT32 d); +extern void scsp_write_16(UINT32 a, UINT32 d); +extern void scsp_write_32(UINT32 a, UINT32 d); + +extern void scsp_midi_in_send(UINT8 data); +extern void scsp_midi_out_send(UINT8 data); +extern UINT8 scsp_midi_in_read(void); +extern UINT8 scsp_midi_out_read(void); + +extern char * scsp_debug_slist_on(void); +extern char * scsp_debug_ilist(INT s_m, char * out); + +#endif /* _SCSP_H_ */ + diff --git a/core/tilegen.c b/core/tilegen.c new file mode 100644 index 0000000..e20a59d --- /dev/null +++ b/core/tilegen.c @@ -0,0 +1,823 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * tilegen.c + * + * Tilemap generator. + * + * Palette Notes: + * - Each palette entry occupies 32 bits. Only the second 16 bits are + * actually used. + * - The format of a 16-bit palette entry is: AGGGGGBBBBBRRRRR + * + * Register Notes: + * + * 0x20 -- Layer Colors: + * + * 31 23 20 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |-|-|-|-|-|-|-|-|D|C|B|A|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * D = Layer 0xFE000 color control (0 = 8-bit, 1 = 4-bit) + * C = Layer 0xFC000 color control (0 = 8-bit, 1 = 4-bit) + * B = Layer 0xFA000 color control (0 = 8-bit, 1 = 4-bit) + * A = Layer 0xF8000 color control (0 = 8-bit, 1 = 4-bit) + */ + +#include "model3.h" + +/******************************************************************/ +/* Privates */ +/******************************************************************/ + +/* + * NOTE: It is critical that vram be set to NULL if it has not yet been + * allocated because tilegen_set_layer_format() will try to use it to + * recache the palette. + */ + +static UINT8 *vram = NULL; // 2D VRAM (passed to tilegen_init()) +static UINT8 reg[0x100]; // tilemap generator registers + +/* + * Register Macros + */ + +#define REG_LAYER_COLORS 0x20 + +/* + * Pre-Decoded Palette Data + * + * Depending on the renderer color depth, the data is either 32-bit RGBA8 or + * 16-bit RGB5A1. The actual order of the fields is obtained from the renderer + * but it is guaranteed that for 16-bit modes, the color components will each + * be 5 bits and the alpha will be 1 and for the 32-bit modes, all components + * will be 8 bits. + * + * For alpha channel: All bits set means the color is opaque, all bits clear + * means the color is transparent. No other bit combinations should be used. + */ + +static UINT32 *pal; + +/* + * Layer Format + * + * Information that is passed by the renderer on the format of layers. Bit + * position 0 is the LSB (none of that backwards IBM junk ;)) RGBA bit + * positions give the position of the LSB of the field. + */ + +static UINT pitch; // layer pitch (in pixels) +static UINT rpos, gpos, bpos, apos; // R, G, B, A bit positions +static INT bpp; // 15 or 32 only + +static int tilemap_is_dirty[4]; +static int tilemap_dirty[4][64*64]; +static int tilemap_depth[4][64*64]; +static int tilemap_redraw[4]; + +/******************************************************************/ +/* Rendering */ +/******************************************************************/ + +/* + * PUTPIXELx_xx(): + * + * A handy macro used within the draw_tile_xbit_xx() macros to plot a pixel + * and advance the buffer pointer. + */ + +/*#define PUTPIXEL8_32(bp) \ + do { \ + pixel = pal[((pattern >> bp) & 0xFF) | pal_bits]; \ + *buf++ = pixel; \ + } while (0) + +#define PUTPIXEL4_32(bp) \ + do { \ + pixel = pal[((pattern >> bp) & 0xF) | pal_bits]; \ + *buf++ = pixel; \ + } while (0) +*/ + +#define PUTPIXEL8(bp) \ + do \ + { \ + *buf++ = ((pattern >> bp) & 0xff) | pal_bits; \ + } while(0) + +#define PUTPIXEL4(bp) \ + do \ + { \ + *buf++ = ((pattern >> bp) & 0xf) | pal_bits; \ + } while(0) + +/* + * draw_tile_8bit_32(): + * + * Draws an 8-bit tile to a 32-bit layer buffer. + */ + +static void draw_tile_8bit(UINT tile, UINT16 *buf) +{ + UINT tile_offs; // offset of tile within VRAM + UINT pal_bits; // color palette bits obtained from tile + UINT y; + UINT32 pattern; // 4 pattern pixels fetched at once + + /* + * Calculate tile offset; each tile occupies 64 bytes when using 8-bit + * pixels + */ + + //tile_offs = tile & 0x3fff; + //tile_offs *= 64; + tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1); + tile_offs *= 32; + + /* + * Obtain upper color bits; the lower 8 bits come from the tile pattern + */ + + pal_bits = tile & 0x7F00; + + /* + * Draw! + */ + + for (y = 0; y < 8; y++) + { + /* + * Fetch first 4 pixels and draw them + */ + + pattern = *((UINT32 *) &vram[tile_offs]); + tile_offs += 4; + PUTPIXEL8(24); + PUTPIXEL8(16); + PUTPIXEL8(8); + PUTPIXEL8(0); + + /* + * Next 4 + */ + + pattern = *((UINT32 *) &vram[tile_offs]); + tile_offs += 4; + PUTPIXEL8(24); + PUTPIXEL8(16); + PUTPIXEL8(8); + PUTPIXEL8(0); + + /* + * Move to the next line + */ + + buf += (pitch - 8); // next line in layer buffer + } +} + +/* + * draw_tile_4bit_32(): + * + * Draws a 4-bit tile to a 32-bit layer buffer. + */ + +static void draw_tile_4bit(UINT tile, UINT16 *buf) +{ + UINT tile_offs; // offset of tile within VRAM + UINT pal_bits; // color palette bits obtained from tile + UINT y; + UINT32 pattern; // 8 pattern pixels fetched at once + + /* + * Calculate tile offset; each tile occupies 32 bytes when using 4-bit + * pixels + */ + + tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1); + tile_offs *= 32; + + /* + * Obtain upper color bits; the lower 4 bits come from the tile pattern + */ + + pal_bits = tile & 0x7FF0; + + /* + * Draw! + */ + + for (y = 0; y < 8; y++) + { + pattern = *((UINT32 *) &vram[tile_offs]); + + /* + * Draw the 8 pixels we've fetched + */ + + PUTPIXEL4(28); + PUTPIXEL4(24); + PUTPIXEL4(20); + PUTPIXEL4(16); + PUTPIXEL4(12); + PUTPIXEL4(8); + PUTPIXEL4(4); + PUTPIXEL4(0); + + /* + * Move to the next line + */ + + tile_offs += 4; // next tile pattern line + buf += (pitch - 8); // next line in layer buffer + } +} + +/* + * draw_layer_8bit_32(): + * + * Draws an entire layer of 8-bit tiles to a 32-bit layer buffer. + */ + +static void draw_layer_8bit(UINT16 *layer, int layer_num) +{ + int ty, tx; + int tilenum; + UINT32 tile; + UINT32 addr = 0xf8000 + (layer_num * 0x2000); + + if (tilemap_is_dirty[layer_num] == 0) + { + return; + } + + tilemap_is_dirty[layer_num] = 0; + + tilenum = 0; + for (ty = 0; ty < 64; ty++) + { + for (tx = 0; tx < 64; tx+=2) + { + if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0]) + { + tilemap_depth[layer_num][tilenum+0] = 0; + tilemap_dirty[layer_num][tilenum+0] = 0; + tile = *((UINT32 *) &vram[addr]) >> 16; + + draw_tile_8bit(tile & 0xffff, layer); + } + if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1]) + { + tilemap_depth[layer_num][tilenum+1] = 0; + tilemap_dirty[layer_num][tilenum+1] = 0; + tile = *((UINT32 *) &vram[addr]) >> 0; + + draw_tile_8bit(tile & 0xffff, layer+8); + } + + addr += 4; + layer += 16; + tilenum+=2; + } + + //addr += (64 - 62) * 2; + layer += (7 * pitch) + (pitch - 512); // next tile row + } + + tilemap_redraw[layer_num] = 0; +} + +/* + * draw_layer_4bit_32(): + * + * Draws an entire layer of 4-bit tiles to a 32-bit layer buffer. + */ + +static void draw_layer_4bit(UINT16 *layer, int layer_num) +{ + int ty, tx; + int tilenum; + UINT32 tile; + UINT32 addr = 0xf8000 + (layer_num * 0x2000); + + if (tilemap_is_dirty[layer_num] == 0) + { + return; + } + + tilemap_is_dirty[layer_num] = 0; + + tilenum = 0; + for (ty = 0; ty < 64; ty++) + { + for (tx = 0; tx < 64; tx+=2) + { + if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0]) + { + tilemap_depth[layer_num][tilenum+0] = 1; + tilemap_dirty[layer_num][tilenum+0] = 0; + tile = *((UINT32 *) &vram[addr]) >> 16; + + draw_tile_4bit(tile & 0xffff, layer); + } + if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1]) + { + tilemap_depth[layer_num][tilenum+0] = 1; + tilemap_dirty[layer_num][tilenum+1] = 0; + tile = *((UINT32 *) &vram[addr]) >> 0; + + draw_tile_4bit(tile & 0xffff, layer+8); + } + + addr += 4; + layer += 16; + tilenum+=2; + } + + //addr += (64 - 62) * 2; + layer += (7 * pitch) + (pitch - 512); // next tile row + } + + tilemap_redraw[layer_num] = 0; +} + +/* + * void tilegen_update(void); + * + * Renders up to 4 layers for the current frame. + */ + +void tilegen_update(void) +{ + UINT8 *layer; + UINT layer_colors, layer_color_mask; + FLAGS layer_enable_mask; + int i, j; + + /* + * Render layers + */ + + PROFILE_SECT_ENTRY("tilegen"); + + layer_colors = BSWAP32(*(UINT32 *) ®[REG_LAYER_COLORS]); + layer_color_mask = 0x00100000; // first layer color bit (moves left) + layer_enable_mask = 1; + +// layer_colors = 0; // enable this to force 8-bit mode for VF3 + + { + UINT32 *palette; + int pwidth; + int ppitch; + int pheight; + int p = 0; + + osd_renderer_get_palette_buffer(&palette, &pwidth, &ppitch); + + pheight = 0x10000 / pwidth; + for (j=0; j < 128; j++) + { + int pindex = j * ppitch; + p = j * 256; + for (i=0; i < 256; i++) + { + int a,r,g,b; + UINT32 rgba; + UINT16 pix; + + pix = pal[p]; + + a = (pix & 0x8000) ? 0x00 : 0xff; + b = (pix >> 10) & 0x1f; + g = (pix >> 5) & 0x1f; + r = (pix & 0x1f); + b = (b << 3) | (b >> 2); + g = (g << 3) | (g >> 2); + r = (r << 3) | (r >> 2); + + rgba = (a << 24) | (r << 16) | (g << 8) | (b << 0); + palette[pindex + i] = rgba; + p++; + + // a very hackish way to counter the effect of using colours as texture coords + if (i == 239) + p--; + } + } + + osd_renderer_free_palette_buffer(); + } + + for (i = 0; i < 4; i++) + { + if ((m3_config.layer_enable & layer_enable_mask)) + { + osd_renderer_get_layer_buffer(i, &layer, &pitch); + + if ((layer_colors & layer_color_mask)) + { + draw_layer_4bit((UINT16 *) layer, i); + } + else + { + draw_layer_8bit((UINT16 *) layer, i); + } + + osd_renderer_free_layer_buffer(i); + } + layer_color_mask <<= 1; + layer_enable_mask <<= 1; + } + + PROFILE_SECT_EXIT("tilegen"); +} + +/******************************************************************/ +/* VRAM Access */ +/******************************************************************/ + +static void mark_tilemap_dirty(int layer) +{ + tilemap_is_dirty[layer] = 1; + tilemap_redraw[layer] = 1; +} + +/* + * UINT16 tilegen_vram_read_16(UINT32 addr); + * + * Reads a 16-bit word from VRAM. + * + * Parameters: + * addr = Address. + * + * Returns: + * Data read. + */ + +UINT16 tilegen_vram_read_16(UINT32 addr) +{ + return(BSWAP16(*(UINT16 *)&vram[addr & 0x1FFFFF])); +} + +/* + * UINT32 tilegen_vram_read_32(UINT32 addr); + * + * Reads a 32-bit word from VRAM. + * + * Parameters: + * addr = Address. + * + * Returns: + * Data read. + */ + +UINT32 tilegen_vram_read_32(UINT32 addr) +{ + return(BSWAP32(*(UINT32 *)&vram[addr & 0x1FFFFF])); +} + +/* + * void tilegen_vram_write_32(UINT32 addr, UINT32 data); + * + * Writes a 32-bit word to VRAM. Palette decoding is handled here. + * + * Parameters: + * addr = Address. + * data = Data. + */ + +void tilegen_vram_write_32(UINT32 addr, UINT32 data) +{ + UINT color; + + addr &= 0x1FFFFF; + data = BSWAP32(data); // return to its natural order (as on PPC) + + if (addr < 0xf8000) + { + *(UINT32 *)&vram[addr] = data; + } + else if (addr >= 0x0f8000 && addr < 0x100000) + { + UINT32 old_data; + int ad, layer, layer_depth, old_depth; + + ad = addr - 0xf8000; + layer = ad / 0x2000; + + old_data = *(UINT32 *)&vram[addr]; + layer_depth = (BSWAP32(*(UINT32 *) ®[REG_LAYER_COLORS]) >> (20+layer)) & 1; + old_depth = tilemap_depth[layer][((ad & 0x1fff) / 2)]; + + if (data != old_data || layer_depth != old_depth) + { + *(UINT32 *)&vram[addr] = data; + + //ad = addr - 0xf8000; + //layer = ad / 0x2000; + tilemap_dirty[layer][((ad & 0x1fff) / 2) + 0] = 1; + tilemap_dirty[layer][((ad & 0x1fff) / 2) + 1] = 1; + tilemap_is_dirty[layer] = 1; + } + } + else if (addr >= 0x100000 && addr < 0x120000) // palette + { + *(UINT32 *)&vram[addr] = data; + color = (addr - 0x100000) / 4; // color number + + pal[color] = data; + } +} + +static void recache_palette(void) +{ + UINT32 i; + + for (i = 0x100000; i < 0x11FFFF; i += 4) + tilegen_vram_write_32(i, BSWAP32(*(UINT32 *) &vram[i])); +} + +/******************************************************************/ +/* Tilegen I/O Port Access */ +/******************************************************************/ + +/* + * UINT32 tilegen_read_32(UINT32 a); + * + * Reads a 32-bit word from the tilemap generator register area. + * + * Parameters: + * a = Address. + * + * Returns: + * Data read. + */ + +UINT32 tilegen_read_32(UINT32 a) +{ +// LOG("MODEL3.LOG", "TILEGEN: %08X: read 32 %08X\n", PPC_PC, a); + //message(0, "tilegen: %08X: read 32 %08X", PPC_PC, a); + + a &= 0xFF; + + switch(a) + { + + case 0x00: // Status/Control + // 0x20 (latch) controls layer pairing + return(0 << 24); + } + + return(BSWAP32(*(UINT32 *)®[a])); +} + +/* + * void tilegen_write_32(UINT32 a, UINT32 d); + * + * Writes a 32-bit word to the tilemap generator register area. + * + * Parameters: + * a = Address. + * d = Data. + */ + +void tilegen_write_32(UINT32 a, UINT32 d) +{ + /* data is written as 32-bit, but only higher byte is used */ + +// LOG("MODEL3.LOG", "TILEGEN: %08X: write 32 %08X = %08X\n", PPC_PC, a, d); + + a &= 0xFF; + + //if (a != 0x60 && a != 0x64 && a != 0x68 && a != 0x6c && + // a != 0x10 && a != 0x0c && a != 0x40 && a != 0x44) + //printf("tilegen: %08X, %08X\n", a, d); + + switch(a) + { + case 0x00: + case 0x04: + case 0x08: + case 0x0C: + break; + case 0x10: + model3_remove_irq((UINT8) (d >> 24)); + break; + case 0x14: + case 0x18: + case 0x1C: + break; + case 0x20: + { + UINT32 olddata = *(UINT32 *)®[a]; + UINT32 newdata = BSWAP32(d); + + if ((olddata & 0x100000) != (newdata & 0x100000)) + mark_tilemap_dirty(0); + if ((olddata & 0x200000) != (newdata & 0x200000)) + mark_tilemap_dirty(1); + if ((olddata & 0x400000) != (newdata & 0x400000)) + mark_tilemap_dirty(2); + if ((olddata & 0x800000) != (newdata & 0x800000)) + mark_tilemap_dirty(3); + + /**(UINT32 *)®[0x60] &= ~0x80000000; + *(UINT32 *)®[0x64] &= ~0x80000000; + *(UINT32 *)®[0x68] &= ~0x80000000; + *(UINT32 *)®[0x6c] &= ~0x80000000;*/ + break; + } + case 0x24: + case 0x40: + case 0x44: + break; + case 0x60: + case 0x64: + case 0x68: + case 0x6C: + break; + } + + *(UINT32 *)®[a] = BSWAP32(d); +} + +/******************************************************************/ +/* Set Up, Shut Down, and State Management */ +/******************************************************************/ + +/* + * void tilegen_save_state(FILE *fp); + * + * Saves the state of the tile generator to a file. + * + * Parameters: + * fp = File to save to. + */ + +void tilegen_save_state(FILE *fp) +{ + fwrite(vram, sizeof(UINT8), 1*1024*1024+2*65536, fp); + fwrite(reg, sizeof(UINT8), 0x100, fp); +} + +/* + * void tilegen_load_state(FILE *fp); + * + * Loads the state of the tile generator from a file. + * + * Parameters: + * fp = File to load from. + */ + +void tilegen_load_state(FILE *fp) +{ + fread(vram, sizeof(UINT8), 1*1024*1024+2*65536, fp); + fread(reg, sizeof(UINT8), 0x100, fp); + recache_palette(); + + mark_tilemap_dirty(0); + mark_tilemap_dirty(1); + mark_tilemap_dirty(2); + mark_tilemap_dirty(3); +} + +/* + * void tilegen_shutdown(void); + * + * Shuts down the tilemap generator. + */ + +void tilegen_shutdown(void) +{ + vram = NULL; + SAFE_FREE(pal); + } + +/* + * void tilegen_init(UINT8 *vramptr); + * + * Initializes the tilemap generator. + * + * Parameters: + * vramptr = Pointer to 2D VRAM. + */ + +void tilegen_init(UINT8 *vramptr) +{ + vram = vramptr; + + mark_tilemap_dirty(0); + mark_tilemap_dirty(1); + mark_tilemap_dirty(2); + mark_tilemap_dirty(3); + + pal = malloc(sizeof(UINT32) * 65536); + + atexit(tilegen_shutdown); +} + +BOOL tilegen_is_layer_enabled(int layer) +{ + if (layer == 1 && stricmp(m3_config.game_id, "lostwsga") == 0) + return FALSE; + + switch (layer) + { + case 0: + return *(UINT32 *)®[0x60] & 0x80000000 ? 1 : 0; + case 1: + return *(UINT32 *)®[0x64] & 0x80000000 ? 1 : 0; + case 2: + return *(UINT32 *)®[0x68] & 0x80000000 ? 1 : 0; + case 3: + return *(UINT32 *)®[0x6c] & 0x80000000 ? 1 : 0; + } + + return 0; +} + +UINT32 tilegen_get_layer_color_offset(int layer) +{ + switch (layer) + { + case 0: + case 1: + { + INT8 r = (*(UINT32 *)®[0x40] >> 16) & 0xff; + INT8 g = (*(UINT32 *)®[0x40] >> 8) & 0xff; + INT8 b = (*(UINT32 *)®[0x40] >> 0) & 0xff; + + r += 127; + g += 127; + b += 127; + + return (r << 16) | (g << 8) | (b); + } + + case 2: + case 3: + { + UINT8 r = (*(UINT32 *)®[0x44] >> 16) & 0xff; + UINT8 g = (*(UINT32 *)®[0x44] >> 8) & 0xff; + UINT8 b = (*(UINT32 *)®[0x44] >> 0) & 0xff; + + r ^= 0x80; + g ^= 0x80; + b ^= 0x80; + + return (r << 16) | (g << 8) | (b); + } + } + + return 0; +} + +UINT32 *tilegen_get_priority_buffer(void) +{ + return (UINT32 *)&vram[0xf7000]; +} + +BOOL tilegen_is_priority_enabled(void) +{ + UINT32 v = *(UINT32 *)®[0x20]; + return (v & 0x80) ? TRUE : FALSE; +} + +UINT32 tilegen_get_layer_scroll_pos(int layer) +{ + UINT32 s = *(UINT32 *)®[0x60 + (layer*4)]; + return s & 0x7fff7fff; +} + +/* + * void tilegen_reset(void); + * + * Resets the tilemap generator. The registers are put into a reset state and + * the palette is zeroed out. + */ + +void tilegen_reset(void) +{ + memset(reg, 0xFF, 0x100); + memset(pal, 0x00, 65536 * sizeof(UINT32)); +} diff --git a/core/tilegen.h b/core/tilegen.h new file mode 100644 index 0000000..225a361 --- /dev/null +++ b/core/tilegen.h @@ -0,0 +1,49 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * tilegen.h + * + * Tilemap generator header. + */ + +#ifndef INCLUDED_TILEGEN_H +#define INCLUDED_TILEGEN_H + +extern void tilegen_update(void); + +extern UINT16 tilegen_vram_read_16(UINT32 addr); +extern UINT32 tilegen_vram_read_32(UINT32); +extern void tilegen_vram_write_32(UINT32, UINT32); + +extern UINT16 tilegen_read_16(UINT32); +extern UINT32 tilegen_read_32(UINT32); +extern void tilegen_write_32(UINT32, UINT32); + +extern BOOL tilegen_is_layer_enabled(int); +extern UINT32 tilegen_get_layer_color_offset(int layer); + +extern void tilegen_save_state(FILE *); +extern void tilegen_load_state(FILE *); + +extern void tilegen_reset(void); +extern void tilegen_init(UINT8 *); +extern void tilegen_shutdown(void); + +#endif // INCLUDED_TILEGEN_H + diff --git a/expat/expat.h b/expat/expat.h new file mode 100644 index 0000000..c6a4b3b --- /dev/null +++ b/expat/expat.h @@ -0,0 +1,1013 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_INCLUDED +#define Expat_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include +#include "expat_external.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2 +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + /* Added in 1.95.7. */ + XML_ERROR_UNBOUND_PREFIX, + /* Added in 1.95.8. */ + XML_ERROR_UNDECLARING_PREFIX, + XML_ERROR_INCOMPLETE_PE, + XML_ERROR_XML_DECL, + XML_ERROR_TEXT_DECL, + XML_ERROR_PUBLICID, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE, + /* Added in 2.0. */ + XML_ERROR_RESERVED_PREFIX_XML, + XML_ERROR_RESERVED_PREFIX_XMLNS, + XML_ERROR_RESERVED_NAMESPACE_URI +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + It is a programming error to use the separator '\0' with namespace + triplets (see XML_SetReturnNSTriplet). +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, + void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: For the purpose of checking WFC: Entity Declared, passing + useDTD == XML_TRUE will make the parser behave as if the document + had a DTD with an external subset. + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR, + XML_FEATURE_NS + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 2 +#define XML_MINOR_VERSION 0 +#define XML_MICRO_VERSION 0 + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_INCLUDED */ diff --git a/expat/expat_external.h b/expat/expat_external.h new file mode 100644 index 0000000..4cd1692 --- /dev/null +++ b/expat/expat_external.h @@ -0,0 +1,115 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_External_INCLUDED +#define Expat_External_INCLUDED 1 + +/* External API definitions */ + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +typedef __int64 XML_Index; +typedef unsigned __int64 XML_Size; +#else +typedef long long XML_Index; +typedef unsigned long long XML_Size; +#endif +#else +typedef long XML_Index; +typedef unsigned long XML_Size; +#endif /* XML_LARGE_SIZE */ + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_External_INCLUDED */ diff --git a/expat/libexpat.lib b/expat/libexpat.lib new file mode 100644 index 0000000..baed2b1 Binary files /dev/null and b/expat/libexpat.lib differ diff --git a/file.c b/file.c new file mode 100644 index 0000000..70d55c6 --- /dev/null +++ b/file.c @@ -0,0 +1,499 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * file.c + * + * File access and ZIP file support + * + */ + +#include "model3.h" +#include "file.h" +#include "unzip/unzip.h" /* ZLIB */ + +static unzFile zip_file; + +/* zip_get_file_size + * + * Gets the uncompressed size of a file in the ZIP file + * Returns the file size or 0 if the file is not found (or the file size is 0) + */ + +static UINT32 zip_get_file_size(const char* file) +{ + unz_file_info file_info; + + if( unzLocateFile(zip_file, file, 2) != UNZ_OK ) + return 0; + + if( unzGetCurrentFileInfo(zip_file, &file_info, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK ) + return 0; + + return file_info.uncompressed_size; +} + +/* zip_read_file + * + * Reads the specified file to a buffer + * Returns TRUE if successful otherwise FALSE + */ + +static BOOL zip_read_file(const char* file, UINT8* buffer, UINT32 size) +{ + if( unzLocateFile(zip_file, file, 2) != UNZ_OK ) + return FALSE; + + if( unzOpenCurrentFile(zip_file) != UNZ_OK ) + return FALSE; + + if( unzReadCurrentFile(zip_file, buffer, size) < 0 ) { + unzCloseCurrentFile(zip_file); + return FALSE; + } + + unzCloseCurrentFile(zip_file); + return TRUE; +} + +/* zip_find_name_for_crc + * + * Finds a matching file name for a crc + * Returns TRUE if crc was found. The file name is copied to the supplied string pointer. + * + */ + +static BOOL zip_find_name_for_crc(UINT32 crc, char* file) +{ + unz_file_info file_info; + char filename[4096]; + + if( unzGoToFirstFile(zip_file) != UNZ_OK ) + return FALSE; + + do + { + if( unzGetCurrentFileInfo(zip_file, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK ) + return FALSE; + + if( file_info.crc == crc ) { + strcpy( file, filename ); + return TRUE; + } + + } while( unzGoToNextFile(zip_file) == UNZ_OK ); + + return FALSE; +} + +/* zip_open + * + * Opens a zip file. Must be called before any of the above functions ! + */ + +static BOOL zip_open(const char* file) +{ + zip_file = unzOpen(file); + if( zip_file == NULL ) + return FALSE; + + return TRUE; +} + +/* zip_close + * + * Closes the zip file + */ + +static void zip_close(void) +{ + unzClose(zip_file); +} + + + +/* File access functions */ + +static BOOL zip_directory = FALSE; +static char directory_path[4096]; + +/* TODO: set_directory and set_directory_zip could be merged together */ + +/* set_directory + * + * Sets the current directory + * + */ + +BOOL set_directory(char* path, ...) +{ + char string[4096]; + va_list l; + + va_start(l, path); + vsprintf(string, path, l); + va_end(l); + + zip_directory = FALSE; + strcpy( directory_path, string ); + return TRUE; +} + +/* set_directory_zip + * + * Sets a zip file as current directory + * + */ + +BOOL set_directory_zip(char* file, ...) +{ + char string[4096]; + va_list l; + + va_start(l, file); + vsprintf(string, file, l); + va_end(l); + + /* Close the old zip file */ + zip_close(); + + if( !zip_open(string) ) + return FALSE; + + zip_directory = TRUE; + strcpy( directory_path, string ); + return TRUE; +} + +/* get_file_size + * + * Returns the file size + * + */ + +size_t get_file_size(const char* file) +{ + FILE* f; + size_t length = 0; + char path[4096]; + + if( zip_directory ) { + length = zip_get_file_size(file); + } + else { + sprintf( path, "%s/%s", directory_path, file ); + f = fopen( path, "rb" ); + if( f == NULL ) + return 0; + + fseek( f, 0, SEEK_END ); + length = ftell(f); + fclose(f); + } + + return length; +} + +/* read_file + * + * Reads the content of the file to a buffer + * + */ + +BOOL read_file(const char* file, UINT8* buffer, UINT32 size) +{ + FILE* f; + char path[4096]; + + if( zip_directory ) { + return zip_read_file( file, buffer, size ); + } + else { + /* Build a full path to file */ + strcpy( path, directory_path ); + strcat( path, "/" ); + strcat( path, file ); + + f = fopen( path, "rb" ); + if( f == NULL ) + return FALSE; + + fseek( f, 0, SEEK_SET ); + if( fread(buffer, sizeof(UINT8), size, f) != (size_t)size ) { + fclose(f); + return FALSE; + } + + fclose(f); + } + return TRUE; +} + +/* write_file + * + * Writes the contents of a buffer to a file + * + */ + +BOOL write_file(const char* file, UINT8* buffer, UINT32 size) +{ + FILE* f; + char path[4096]; + + /* Whoops. No saving to a zip file :) */ + if( zip_directory ) + return FALSE; + + /* Build a full path to file */ + strcpy( path, directory_path ); + strcat( path, "/" ); + strcat( path, file ); + + f = fopen( path, "wb" ); + + fseek( f, 0, SEEK_SET ); + if( fwrite(buffer, sizeof(UINT8), size, f) != (size_t)size ) { + fclose(f); + return FALSE; + } + + fclose(f); + + return TRUE; +} + + +/* get_file_size_crc + * + * Returns the file size of a file specified by crc + * + */ + +size_t get_file_size_crc(UINT32 crc) +{ + char file[4096]; + + /* only zip files supported */ + if( !zip_directory ) + return 0; + + if( !zip_find_name_for_crc(crc, file) ) + return 0; + + return zip_get_file_size(file); +} + +/* read_file_crc + * + * Reads the contents of a file specified by crc + * + */ + +BOOL read_file_crc(UINT32 crc, UINT8* buffer, UINT32 size) +{ + char file[4096]; + + /* only zip files supported */ + if( !zip_directory ) + return FALSE; + + if( !zip_find_name_for_crc(crc, file) ) + return FALSE; + + return zip_read_file(file, buffer, size); +} + + + +/* open_file + * + * Opens a file + * + */ + +FILE* open_file(UINT32 flags, char* file, ...) +{ + char string[4096]; + char path[4096]; + char mode[3]; + char* m = mode; + va_list l; + + /* zip files are not supported this way */ + if( zip_directory ) + return 0; + + va_start(l, file); + vsprintf(string, file, l); + va_end(l); + + /* Build full path */ + if (strlen(directory_path) <= 0) + { + sprintf(path, "%s", string); + } + else + { + sprintf(path, "%s/%s", directory_path, string); + } + + /* Set file access mode */ + if( flags & FILE_READ ) + sprintf(&m[0], "r"); + else + sprintf(&m[0], "w"); + + if( flags & FILE_BINARY ) + sprintf(&m[1], "b" ); + else + sprintf(&m[1], "t" ); + + m[2] = '\0'; + return fopen(path, m); +} + +/* close_file + * + * Closes the file + * + */ + +void close_file(FILE* file) +{ + fclose(file); +} + +/* read_from_file + * + * Reads n bytes from file to a buffer + * + */ + +BOOL read_from_file(FILE* file, UINT8* buffer, UINT32 size) +{ + if( file == NULL ) + return FALSE; + + if( fread(buffer, sizeof(UINT8), size, file) != (size_t)size ) + return FALSE; + + return TRUE; +} + +/* write_to_file + * + * Writes n bytes to file + * + */ + +BOOL write_to_file(FILE* file, UINT8* buffer, UINT32 size) +{ + if( file == NULL ) + return FALSE; + + if( fwrite(buffer, sizeof(UINT8), size, file) != (size_t)size ) + return FALSE; + + return TRUE; +} + + +/* get_file_size + * + * Gets the file size + * + */ +size_t get_open_file_size(FILE *file) +{ + size_t length; + int current_pos = ftell(file); + fseek(file, 0, SEEK_END); + length = ftell(file); + fseek(file, current_pos, SEEK_SET); + + return length; +} + + +/* + * Load a file to a buffer. + */ + +int load_file(char *path, UINT8 * dest, int size) +{ + FILE * fp; + int length; + + if(path == NULL || dest == NULL) + return(-1); + + if((fp = fopen(path, "rb")) == NULL) + return(-1); + + fseek(fp, 0, SEEK_END); + length = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if (length <= 0) + return -1; + + if (fread(dest, 1, size, fp) != (size_t)length) // file size mismatch + return -1; + + return length; +} + +static void word_swap(UINT8 *src, int size) +{ + while (size -= 4) + { + *((UINT32 *) src) = BSWAP32(*((UINT32 *) src)); + src += sizeof(UINT32); + } +} + +/* + * Save a buffer to a file. + */ + +void save_file(char *path, UINT8 *src, int size, BOOL byte_reversed) +{ + FILE * fp; + + if (byte_reversed) + { + word_swap(src, size); + } + + fp = fopen(path, "wb"); + if(fp != NULL) + { + fwrite(src, 1, size, fp); + fclose(fp); + message(0, "Wrote %s", path); + } + else + { + message(0, "Failed to write %s", path); + } + + if (byte_reversed) + { + word_swap(src, size); + } +} \ No newline at end of file diff --git a/file.h b/file.h new file mode 100644 index 0000000..2af6598 --- /dev/null +++ b/file.h @@ -0,0 +1,50 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef INCLUDED_FILE_H +#define INCLUDED_FILE_H + +#include "model3.h" + +#define FILE_READ 0x1 +#define FILE_WRITE 0x2 +#define FILE_BINARY 0x4 +#define FILE_TEXT 0x8 + +/* Functions */ + +FILE* open_file(UINT32, char*, ...); +void close_file(FILE*); +BOOL read_from_file(FILE*, UINT8*, UINT32); +BOOL write_to_file(FILE*, UINT8*, UINT32); +size_t get_open_file_size(FILE *); + +size_t get_file_size(const char*); +BOOL read_file(const char*, UINT8*, UINT32); +BOOL write_file(const char*, UINT8*, UINT32); + +size_t get_file_size_crc(UINT32); +BOOL read_file_crc(UINT32, UINT8*, UINT32); + +BOOL set_directory(char*, ...); +BOOL set_directory_zip(char*, ...); + +int load_file(char *path, UINT8 * dest, int size); +void save_file(char *path, UINT8 *src, int size, BOOL byte_reversed); + +#endif /* INCLUDED_FILE_H */ diff --git a/games.xml b/games.xml new file mode 100644 index 0000000..8e00bcb --- /dev/null +++ b/games.xml @@ -0,0 +1,1655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + Virtua Fighter 3 + 1996 + Sega + 1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Fighter 3 Team Battle + 1996 + Sega + 1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sega Bass Fishing + 1997 + Sega + 1.0 + mpc106 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get Bass + 1997 + Sega + 1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Scud Race (Australia) + 1996 + Sega + 1.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Scud Race (Export) + 1996 + Sega + 1.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Scud Race Plus + 1997 + Sega + 1.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Lost World + 1997 + Sega + 1.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Striker 2 (Step 1.5) + 1997 + Sega + 1.5 + mpc106 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LeMans 24 + 1997 + Sega + 1.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Striker 2 '98 (Step 1.5) + 1998 + Sega + 1.5 + mpc106 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Striker 2 (Step 2.0) + 1997 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Harley-Davidson and L.A. Riders + 1997 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sega Rally 2 + 1998 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtual On 2: Oratorio Tangram + 1998 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtual On 2: Oratorio Tangram (ver 5.4g) + 1998 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fighting Vipers 2 + 1998 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Striker 2 '98 (Step 2.0) + 1998 + Sega + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Striker 2 '99.1 + 1999 + Sega + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Virtua Striker 2 '99 + 1999 + Sega + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Daytona USA 2 + 1998 + Sega + 2.1 + 64M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Daytona USA 2 Power Edition + 1998 + Sega + 2.1 + 64M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dirt Devils + 1998 + Sega + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dirt Devils (alt) + 1998 + Sega + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Star Wars Trilogy (ver A) + 1998 + Sega/LucasArts + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Star Wars Trilogy + 1998 + Sega/LucasArts + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Spikeout + 1998 + Sega + 2.1 + 64M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Spikeout Final Edition + 1998 + Sega + 2.1 + 64M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Emergency Call Ambulance + 1999 + Sega + 2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/osd_common/disasm.c b/osd_common/disasm.c new file mode 100644 index 0000000..54dcfc9 --- /dev/null +++ b/osd_common/disasm.c @@ -0,0 +1,1256 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * disasm.c + * + * PowerPC 603e disassembler. + * + * When possible, invalid forms of instructions are checked for. To the best + * of my knowledge, all appropriate load/store instructions are checked. I'm + * not sure whether any other kinds of instructions need checking. + */ + +#include +#include +#ifdef STANDALONE +#include +#endif +#include "model3.h" + +#define DISASM_VERSION "1.0" + +/* + * Masks + * + * These masks isolate fields in an instruction word. + */ + +#define M_LI 0x03fffffc +#define M_AA 0x00000002 +#define M_LK 0x00000001 +#define M_BO 0x03e00000 +#define M_BI 0x001f0000 +#define M_BD 0x0000fffc +#define M_RT 0x03e00000 +#define M_RA 0x001f0000 +#define M_RB 0x0000f800 +#define M_CRFD 0x03800000 +#define M_L 0x00200000 +#define M_TO 0x03e00000 +#define M_D 0x0000ffff +#define M_SIMM 0x0000ffff +#define M_UIMM 0x0000ffff +#define M_NB 0x0000f800 +#define M_SR 0x000f0000 +#define M_SH 0x0000f800 +#define M_CRFS 0x001c0000 +#define M_IMM 0x0000f000 +#define M_CRBD 0x03e00000 +#define M_RC 0x00000001 +#define M_CRBA 0x001f0000 +#define M_CRBB 0x0000f800 +#define M_SPR 0x001FF800 +#define M_TBR 0x001FF800 +#define M_CRM 0x000FF000 +#define M_FM 0x01FE0000 +#define M_OE 0x00000400 +#define M_REGC 0x000007c0 +#define M_MB 0x000007c0 +#define M_ME 0x0000003e +#define M_XO 0x000007fe + +/* + * Field Defining Macros + * + * These macros generate instruction words with their associated fields filled + * in with the passed value. + */ + +#define D_OP(op) ((op & 0x3f) << 26) +#define D_XO(xo) ((xo & 0x3ff) << 1) +#define D_RT(r) ((r & 0x1f) << (31 - 10)) +#define D_RA(r) ((r & 0x1f) << (31 - 15)) +#define D_UIMM(u) (u & 0xffff) + +/* + * Macros to Get Field Values + * + * These macros return the values of fields in an opcode. They all return + * unsigned values and do not perform any sign extensions. + */ + +#define G_RT(op) ((op & M_RT) >> (31 - 10)) +#define G_RA(op) ((op & M_RA) >> (31 - 15)) +#define G_RB(op) ((op & M_RB) >> (31 - 20)) +#define G_SIMM(op) (op & M_SIMM) +#define G_UIMM(op) (op & M_UIMM) +#define G_LI(op) ((op & M_LI) >> 2) +#define G_BO(op) ((op & M_BO) >> (31 - 10)) +#define G_BI(op) ((op & M_BI) >> (31 - 15)) +#define G_BD(op) ((op & M_BD) >> 2) +#define G_CRFD(op) ((op & M_CRFD) >> (31 - 8)) +#define G_L(op) ((op & M_L) >> (31 - 10)) +#define G_CRBD(op) ((op & M_CRBD) >> (31 - 10)) +#define G_CRBA(op) ((op & M_CRBA) >> (31 - 15)) +#define G_CRBB(op) ((op & M_CRBB) >> (31 - 20)) +#define G_REGC(op) ((op & M_REGC) >> (31 - 25)) +#define G_D(op) (op & M_D) +#define G_NB(op) ((op & M_NB) >> (31 - 20)) +#define G_CRFS(op) ((op & M_CRFS) >> (31 - 13)) +#define G_SPR(op) ((op & M_SPR) >> (31 - 20)) +#define G_SR(op) ((op & M_SR) >> (31 - 15)) +#define G_CRM(op) ((op & M_CRM) >> (31 - 19)) +#define G_FM(op) ((op & M_FM) >> (31 - 14)) +#define G_IMM(op) ((op & M_IMM) >> (31 - 19)) +#define G_SH(op) ((op & M_SH) >> (31 - 20)) +#define G_MB(op) ((op & M_MB) >> (31 - 25)) +#define G_ME(op) ((op & M_ME) >> 1) +#define G_TO(op) ((op & M_TO) >> (31 - 10)) + +/* + * Operand Formats + * + * These convey information on what operand fields are present and how they + * ought to be printed. + * + * I'm fairly certain all of these are used, but that is not guaranteed. + */ + +enum +{ + F_NONE, // + F_LI, // LI*4+PC if AA=0 else LI*4 + F_BCx, // BO, BI, target_addr used only by BCx + F_RT_RA_0_SIMM, // rT, rA|0, SIMM rA|0 means if rA == 0, print 0 + F_ADDIS, // rT, rA, SIMM (printed as unsigned) only used by ADDIS + F_RT_RA_SIMM, // rT, rA, SIMM + F_RA_RT_UIMM, // rA, rT, UIMM + F_CMP_SIMM, // crfD, L, A, SIMM + F_CMP_UIMM, // crfD, L, A, UIMM + F_RT_RA_0_RB, // rT, rA|0, rB + F_RT_RA_RB, // rT, rA, rB + F_RT_D_RA_0, // rT, d(rA|0) + F_RT_D_RA, // rT, d(rA) + F_RA_RT_RB, // rA, rT, rB + F_FRT_D_RA_0, // frT, d(RA|0) + F_FRT_D_RA, // frT, d(RA) + F_FRT_RA_0_RB, // frT, rA|0, rB + F_FRT_RA_RB, // frT, rA, rB + F_TWI, // TO, rA, SIMM only used by TWI instruction + F_CMP, // crfD, L, rA, rB + F_RA_RT, // rA, rT + F_RA_0_RB, // rA|0, rB + F_FRT_FRB, // frT, frB + F_FCMP, // crfD, frA, frB + F_CRFD_CRFS, // crfD, crfS + F_MCRXR, // crfD only used by MCRXR + F_RT, // rT + F_MFSR, // rT, SR only used by MFSR + F_MTSR, // SR, rT only used by MTSR + F_MFFSx, // frT only used by MFFSx + F_FCRBD, // crbD FPSCR[crbD] + F_MTFSFIx, // crfD, IMM only used by MTFSFIx + F_RB, // rB + F_TW, // TO, rA, rB only used by TW + F_RT_RA_0_NB, // rT, rA|0, NB print 32 if NB == 0 + F_SRAWIx, // rA, rT, SH only used by SRAWIx + F_BO_BI, // BO, BI + F_CRBD_CRBA_CRBB, // crbD, crbA, crbB + F_RT_SPR, // rT, SPR and TBR + F_MTSPR, // SPR, rT only used by MTSPR + F_MTCRF, // CRM, rT only used by MTCRF + F_MTFSFx, // FM, frB only used by MTFSFx + F_RT_RA, // rT, rA + F_FRT_FRA_FRC_FRB, // frT, frA, frC, frB + F_FRT_FRA_FRB, // frT, frA, frB + F_FRT_FRA_FRC, // frT, frA, frC + F_RA_RT_SH_MB_ME, // rA, rT, SH, MB, ME + F_RLWNMx, // rT, rA, rB, MB, ME only used by RLWNMx + F_RT_RB, // rT, rB +}; + +/* + * Flags + */ + +#define FL_OE (1 << 0) // if there is an OE field +#define FL_RC (1 << 1) // if there is an RC field +#define FL_LK (1 << 2) // if there is an LK field +#define FL_AA (1 << 3) // if there is an AA field +#define FL_CHECK_RA_RT (1 << 4) // assert rA!=0 and rA!=rT +#define FL_CHECK_RA (1 << 5) // assert rA!=0 +#define FL_CHECK_LSWI (1 << 6) // specific check for LSWI validity +#define FL_CHECK_LSWX (1 << 7) // specific check for LSWX validity + + +/* + * Instruction Descriptor + * + * Describes the layout of an instruction. + */ + +typedef struct +{ + CHAR *mnem; // mnemonic + UINT32 match; // bit pattern of instruction after it has been masked + UINT32 mask; // mask of variable fields (AND with ~mask to compare w/ + // bit pattern to determine a match) + INT format; // operand format + FLAGS flags; // flags +} IDESCR; + +/* + * Instruction Table + * + * Table of instruction descriptors which allows the disassembler to decode + * and print instructions. + */ + +static IDESCR itab[] = +{ + { "add", D_OP(31)|D_XO(266), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "addc", D_OP(31)|D_XO(10), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "adde", D_OP(31)|D_XO(138), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "addi", D_OP(14), M_RT|M_RA|M_SIMM, F_RT_RA_0_SIMM, 0 }, + { "addic", D_OP(12), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "addic.", D_OP(13), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "addis", D_OP(15), M_RT|M_RA|M_SIMM, F_ADDIS, 0 }, + { "addme", D_OP(31)|D_XO(234), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "addze", D_OP(31)|D_XO(202), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "and", D_OP(31)|D_XO(28), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "andc", D_OP(31)|D_XO(60), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "andi.", D_OP(28), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "andis.", D_OP(29), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "b", D_OP(18), M_LI|M_AA|M_LK, F_LI, FL_AA|FL_LK }, + { "bc", D_OP(16), M_BO|M_BI|M_BD|M_AA|M_LK, F_BCx, FL_AA|FL_LK }, + { "bcctr", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK }, + { "bclr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK }, + { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_L|M_RA|M_RB, F_CMP, 0 }, + { "cmpi", D_OP(11), M_CRFD|M_L|M_RA|M_SIMM, F_CMP_SIMM, 0 }, + { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_L|M_RA|M_RB, F_CMP, 0 }, + { "cmpli", D_OP(10), M_CRFD|M_L|M_RA|M_UIMM, F_CMP_UIMM, 0 }, + { "cntlzw", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, + { "crand", D_OP(19)|D_XO(257), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crandc", D_OP(19)|D_XO(129), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "creqv", D_OP(19)|D_XO(289), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crnand", D_OP(19)|D_XO(225), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crnor", D_OP(19)|D_XO(33), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "cror", D_OP(19)|D_XO(449), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crorc", D_OP(19)|D_XO(417), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crxor", D_OP(19)|D_XO(193), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "dcba", D_OP(31)|D_XO(758), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbf", D_OP(31)|D_XO(86), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbi", D_OP(31)|D_XO(470), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbst", D_OP(31)|D_XO(54), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbt", D_OP(31)|D_XO(278), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbtst", D_OP(31)|D_XO(246), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbz", D_OP(31)|D_XO(1014),M_RA|M_RB, F_RA_0_RB, 0 }, + { "divw", D_OP(31)|D_XO(491), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "divwu", D_OP(31)|D_XO(459), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "eciwx", D_OP(31)|D_XO(310), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "ecowx", D_OP(31)|D_XO(438), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "eieio", D_OP(31)|D_XO(854), 0, F_NONE, 0 }, + { "eqv", D_OP(31)|D_XO(284), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "extsb", D_OP(31)|D_XO(954), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, + { "extsh", D_OP(31)|D_XO(922), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, + { "fabs", D_OP(63)|D_XO(264), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fadd", D_OP(63)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fadds", D_OP(59)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fcmpo", D_OP(63)|D_XO(32), M_CRFD|M_RA|M_RB, F_FCMP, 0 }, + { "fcmpu", D_OP(63)|D_XO(0), M_CRFD|M_RA|M_RB, F_FCMP, 0 }, + { "fctiw", D_OP(63)|D_XO(14), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fctiwz", D_OP(63)|D_XO(15), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fdiv", D_OP(63)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fdivs", D_OP(59)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fmadd", D_OP(63)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmadds", D_OP(59)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmr", D_OP(63)|D_XO(72), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fmsub", D_OP(63)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmsubs", D_OP(59)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmul", D_OP(63)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC }, + { "fmuls", D_OP(59)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC }, + { "fnabs", D_OP(63)|D_XO(136), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fneg", D_OP(63)|D_XO(40), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fnmadd", D_OP(63)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fnmadds",D_OP(59)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fnmsub", D_OP(63)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fnmsubs",D_OP(59)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fres", D_OP(59)|D_XO(24), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "frsp", D_OP(63)|D_XO(12), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "frsqrte",D_OP(63)|D_XO(26), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fsel", D_OP(63)|D_XO(23), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fsqrt", D_OP(63)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fsqrts", D_OP(59)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fsub", D_OP(63)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fsubs", D_OP(59)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "icbi", D_OP(31)|D_XO(982), M_RA|M_RB, F_RA_0_RB, 0 }, + { "isync", D_OP(19)|D_XO(150), 0, F_NONE, 0 }, + { "lbz", D_OP(34), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lbzu", D_OP(35), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lbzux", D_OP(31)|D_XO(119), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lbzx", D_OP(31)|D_XO(87), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lfd", D_OP(50), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "lfdu", D_OP(51), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "lfdux", D_OP(31)|D_XO(631), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "lfdx", D_OP(31)|D_XO(599), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "lfs", D_OP(48), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "lfsu", D_OP(49), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "lfsux", D_OP(31)|D_XO(567), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "lfsx", D_OP(31)|D_XO(535), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "lha", D_OP(42), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lhau", D_OP(43), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lhaux", D_OP(31)|D_XO(375), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lhax", D_OP(31)|D_XO(343), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lhbrx", D_OP(31)|D_XO(790), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lhz", D_OP(40), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lhzu", D_OP(41), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lhzux", D_OP(31)|D_XO(311), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lhzx", D_OP(31)|D_XO(279), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lmw", D_OP(46), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lswi", D_OP(31)|D_XO(597), M_RT|M_RA|M_NB, F_RT_RA_0_NB, FL_CHECK_LSWI }, + { "lswx", D_OP(31)|D_XO(533), M_RT|M_RA|M_RB, F_RT_RA_0_RB, FL_CHECK_LSWX }, + { "lwarx", D_OP(31)|D_XO(20), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lwbrx", D_OP(31)|D_XO(534), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lwz", D_OP(32), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lwzu", D_OP(33), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lwzux", D_OP(31)|D_XO(55), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lwzx", D_OP(31)|D_XO(23), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "mcrf", D_OP(19)|D_XO(0), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 }, + { "mcrfs", D_OP(63)|D_XO(64), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 }, + { "mcrxr", D_OP(31)|D_XO(512), M_CRFD, F_MCRXR, 0 }, + { "mfcr", D_OP(31)|D_XO(19), M_RT, F_RT, 0 }, + { "mffs", D_OP(63)|D_XO(583), M_RT|M_RC, F_MFFSx, FL_RC }, + { "mfmsr", D_OP(31)|D_XO(83), M_RT, F_RT, 0 }, + { "mfspr", D_OP(31)|D_XO(339), M_RT|M_SPR, F_RT_SPR, 0 }, + { "mfsr", D_OP(31)|D_XO(595), M_RT|M_SR, F_MFSR, 0 }, + { "mfsrin", D_OP(31)|D_XO(659), M_RT|M_RB, F_RT_RB, 0 }, + { "mftb", D_OP(31)|D_XO(371), M_RT|M_TBR, F_RT_SPR, 0 }, + { "mtcrf", D_OP(31)|D_XO(144), M_RT|M_CRM, F_MTCRF, 0 }, + { "mtfsb0", D_OP(63)|D_XO(70), M_CRBD|M_RC, F_FCRBD, FL_RC }, + { "mtfsb1", D_OP(63)|D_XO(38), M_CRBD|M_RC, F_FCRBD, FL_RC }, + { "mtfsf", D_OP(63)|D_XO(711), M_FM|M_RB|M_RC, F_MTFSFx, FL_RC }, + { "mtfsfi", D_OP(63)|D_XO(134), M_CRFD|M_IMM|M_RC, F_MTFSFIx, FL_RC }, + { "mtmsr", D_OP(31)|D_XO(146), M_RT, F_RT, 0 }, + { "mtspr", D_OP(31)|D_XO(467), M_RT|M_SPR, F_MTSPR, 0 }, + { "mtsr", D_OP(31)|D_XO(210), M_RT|M_SR, F_MTSR, 0 }, + { "mtsrin", D_OP(31)|D_XO(242), M_RT|M_RB, F_RT_RB, 0 }, + { "mulhw", D_OP(31)|D_XO(75), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC }, + { "mulhwu", D_OP(31)|D_XO(11), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC }, + { "mulli", D_OP(7), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "mullw", D_OP(31)|D_XO(235), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "nand", D_OP(31)|D_XO(476), M_RA|M_RT|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "neg", D_OP(31)|D_XO(104), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "nor", D_OP(31)|D_XO(124), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "or", D_OP(31)|D_XO(444), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "orc", D_OP(31)|D_XO(412), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "ori", D_OP(24), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "oris", D_OP(25), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "rfi", D_OP(19)|D_XO(50), 0, F_NONE, 0 }, + { "rlwimi", D_OP(20), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC }, + { "rlwinm", D_OP(21), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC }, + { "rlwnm", D_OP(23), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RLWNMx, FL_RC }, + { "sc", D_OP(17)|2, 0, F_NONE, 0 }, + { "slw", D_OP(31)|D_XO(24), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "sraw", D_OP(31)|D_XO(792), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "srawi", D_OP(31)|D_XO(824), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC }, + { "srw", D_OP(31)|D_XO(536), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "stb", D_OP(38), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "stbu", D_OP(39), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, + { "stbux", D_OP(31)|D_XO(247), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, + { "stbx", D_OP(31)|D_XO(215), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stfd", D_OP(54), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "stfdu", D_OP(55), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "stfdux", D_OP(31)|D_XO(759), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "stfdx", D_OP(31)|D_XO(727), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "stfiwx", D_OP(31)|D_XO(983), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "stfs", D_OP(52), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "stfsu", D_OP(53), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "stfsux", D_OP(31)|D_XO(695), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "stfsx", D_OP(31)|D_XO(663), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "sth", D_OP(44), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "sthbrx", D_OP(31)|D_XO(918), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "sthu", D_OP(45), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, + { "sthux", D_OP(31)|D_XO(439), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, + { "sthx", D_OP(31)|D_XO(407), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stmw", D_OP(47), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "stswi", D_OP(31)|D_XO(725), M_RT|M_RA|M_NB, F_RT_RA_0_NB, 0 }, + { "stswx", D_OP(31)|D_XO(661), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stw", D_OP(36), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "stwbrx", D_OP(31)|D_XO(662), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stwcx.", D_OP(31)|D_XO(150)|1, M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stwu", D_OP(37), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, + { "stwux", D_OP(31)|D_XO(183), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, + { "stwx", D_OP(31)|D_XO(151), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "subf", D_OP(31)|D_XO(40), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "subfc", D_OP(31)|D_XO(8), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "subfe", D_OP(31)|D_XO(136), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "subfic", D_OP(8), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "subfme", D_OP(31)|D_XO(232), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "subfze", D_OP(31)|D_XO(200), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "sync", D_OP(31)|D_XO(598), 0, F_NONE, 0 }, + { "tlbia", D_OP(31)|D_XO(370), 0, F_NONE, 0 }, + { "tlbie", D_OP(31)|D_XO(306), M_RB, F_RB, 0 }, + { "tlbsync",D_OP(31)|D_XO(566), 0, F_NONE, 0 }, + { "tw", D_OP(31)|D_XO(4), M_TO|M_RA|M_RB, F_TW, 0 }, + { "twi", D_OP(3), M_TO|M_RA|M_SIMM, F_TWI, 0 }, + { "xor", D_OP(31)|D_XO(316), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "xori", D_OP(26), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "xoris", D_OP(27), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + + /* + * PowerPC 603e/EC603e-specific instructions + */ + + { "tlbld", D_OP(31)|D_XO(978), M_RB, F_RB, 0 }, + { "tlbli", D_OP(31)|D_XO(1010),M_RB, F_RB, 0 } +}; + +/* + * CR Bits + * + * Use an index of BI&3 into this table to obtain the CR field bit name. + */ + +static CHAR *crbit[] = { "lt", "gt", "eq", "so" }; + + +/* + * SPR(): + * + * Decode the SPR (or TBR) field and append the register name to dest. If + * no name is associated with the field value, the value itself is printed. + */ + +static void SPR(CHAR *dest, UINT spr_field) +{ + UINT spr; + + /* + * Construct the SPR number -- SPR field is 2 5-bit fields + */ + + spr = (spr_field >> 5) & 0x1f; + spr |= (spr_field & 0x1f) << 5; + + /* + * Append the SPR name to the destination string using strcat() + */ + + switch (spr) + { + case 1: strcat(dest, "xer"); break; + case 8: strcat(dest, "lr"); break; + case 9: strcat(dest, "ctr"); break; + case 18: strcat(dest, "dsisr"); break; + case 19: strcat(dest, "dar"); break; + case 22: strcat(dest, "dec"); break; + case 25: strcat(dest, "sdr1"); break; + case 26: strcat(dest, "srr0"); break; + case 27: strcat(dest, "srr1"); break; + case 272: strcat(dest, "sprg0"); break; + case 273: strcat(dest, "sprg1"); break; + case 274: strcat(dest, "sprg2"); break; + case 275: strcat(dest, "sprg3"); break; + case 282: strcat(dest, "ear"); break; + case 287: strcat(dest, "pvr"); break; + case 528: strcat(dest, "ibat0u"); break; + case 529: strcat(dest, "ibat0l"); break; + case 530: strcat(dest, "ibat1u"); break; + case 531: strcat(dest, "ibat1l"); break; + case 532: strcat(dest, "ibat2u"); break; + case 533: strcat(dest, "ibat2l"); break; + case 534: strcat(dest, "ibat3u"); break; + case 535: strcat(dest, "ibat3l"); break; + case 536: strcat(dest, "dbat0u"); break; + case 537: strcat(dest, "dbat0l"); break; + case 538: strcat(dest, "dbat1u"); break; + case 539: strcat(dest, "dbat1l"); break; + case 540: strcat(dest, "dbat2u"); break; + case 541: strcat(dest, "dbat2l"); break; + case 542: strcat(dest, "dbat3u"); break; + case 543: strcat(dest, "dbat3l"); break; + case 1013: strcat(dest, "dabr"); break; // unsupported on 603e/EC603e + + /* + * Some PowerPC implementations may implement MFTB and MFSPR identically, + * therefore TBR registers are also decoded here + */ + + case 268: strcat(dest, "tbl"); break; + case 269: strcat(dest, "tbu"); break; + + /* + * PowerPC 603e/EC603e-specific registers + */ + + case 1008: strcat(dest, "hid0"); break; + case 1009: strcat(dest, "hid1"); break; + case 976: strcat(dest, "dmiss"); break; + case 977: strcat(dest, "dcmp"); break; + case 978: strcat(dest, "hash2"); break; + case 979: strcat(dest, "hash2"); break; + case 980: strcat(dest, "imiss"); break; + case 981: strcat(dest, "icmp"); break; + case 982: strcat(dest, "rpa"); break; + case 1010: strcat(dest, "iabr"); break; + + default: sprintf(dest, "%s%d", dest, spr); + break; + } +} + +/* + * DecodeSigned16(): + * + * Predecodes the SIMM field for us. If do_unsigned, it is printed as an + * unsigned 16-bit integer. + */ + +static void DecodeSigned16(CHAR *outbuf, UINT32 op, BOOL do_unsigned) +{ + INT16 s; + + s = G_SIMM(op); + if (do_unsigned) // sign extend to unsigned 32-bits + sprintf(outbuf, "0x%04X", (UINT32) s); + else // print as signed 16 bits + { + if (s < 0) + { + s *= -1; + sprintf(outbuf, "-0x%04X", s); + } + else + sprintf(outbuf, "0x%04X",s); + } +} + +/* + * Mask(): + * + * Generate a mask from bit MB through ME (PPC-style backwards bit numbering.) + */ + +static UINT32 Mask(UINT mb, UINT me) +{ + UINT32 i, mask; + + mb &= 31; + me &= 31; + + i = mb; + mask = 0; + while (1) + { + mask |= (1 << (31 - i)); + if (i == me) + break; + i = (i + 1) & 31; + } + + return mask; +} + +/* + * Check(): + * + * Perform checks on the instruction as required by the flags. Returns 1 if + * the instruction failed. + */ + +static BOOL Check(UINT32 op, FLAGS flags) +{ + UINT nb, rt, ra; + + if (!flags) return 0; // nothing to check for! + + rt = G_RT(op); + ra = G_RA(op); + + if (flags & FL_CHECK_RA_RT) // invalid if rA==0 or rA==rT + { + if ((G_RA(op) == 0) || (G_RA(op) == G_RT(op))) + return 1; + } + + if (flags & FL_CHECK_RA) // invalid if rA==0 + { + if (G_RA(op) == 0) + return 1; + } + + if (flags & FL_CHECK_LSWI) + { + /* + * Check that rA is not in the range of registers to be loaded (even + * if rA == 0) + */ + + nb = G_NB(op); + + if (ra >= rt && ra <= (rt + nb - 1)) return 1; + if ((rt + nb - 1) > 31) // register wrap-around! + { + if (ra < ((rt + nb - 1) - 31)) + return 1; + } + } + + if (flags & FL_CHECK_LSWX) + { + /* + * Check that rT != rA, rT != rB, and rD and rA both do not specify + * R0. + * + * We cannot check fully whether rA or rB are in the range of + * registers specified to be loaded because that depends on XER. + */ + + if (rt == ra || rt == G_RB(op) || ((rt == 0) && (ra == 0))) + return 1; + } + + return 0; // passed checks +} + +/* + * Simplified(): + * + * Handles all simplified instruction forms. Returns 1 if one was decoded, + * otherwise 0 to indicate disassembly should carry on as normal. + */ + +static BOOL Simplified(UINT32 op, UINT32 vpc, CHAR *signed16, CHAR *mnem, CHAR *oprs) +{ + UINT32 value, disp; + + value = G_SIMM(op); // value is fully sign-extended SIMM field + if (value & 0x8000) + value |= 0xffff0000; + + if (op == (D_OP(24)|D_RT(0)|D_RA(0)|D_UIMM(0))) + strcat(mnem, "nop"); // ori r0,r0,0 -> nop + else if ((op & ~(M_RT|M_RA|M_RB|M_RC)) == (D_OP(31)|D_XO(444))) + { + if (G_RT(op) == G_RB(op)) + { + strcat(mnem, "mr"); // orx rA,rT,rT -> mrx rA,rT + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op)); + } + else + return 0; + } + else if ((op & ~(M_RT|M_RA|M_RB|M_RC)) == (D_OP(31)|D_XO(124))) + { + if (G_RT(op) == G_RB(op)) + { + strcat(mnem, "not"); // nor rA,rT,rT -> not rA,rT + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op)); + } + else + return 0; + } + else if ((op & ~(M_RT|M_RA|M_SIMM)) == D_OP(14)) + { + if (G_RA(op) == 0) + { + strcat(mnem, "li"); // addi rT,0,value -> li rT,value + sprintf(oprs, "r%d,0x%08X", G_RT(op), value); + } + else + return 0; + } + else if ((op & ~(M_RT|M_RA|M_SIMM)) == D_OP(15)) + { + if (G_RA(op) == 0) + { + strcat(mnem, "li"); // addis rT,0,value -> li rT,(value<<16) + sprintf(oprs, "r%d,0x%08X", G_RT(op), value << 16); + } + else + { + strcat(mnem, "addi"); // addis rT,rA,SIMM -> addi rT,rA,SIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RT(op), G_RA(op), value << 16); + } + } + else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(29)) + { + strcat(mnem, "andi."); // andis. rA,rT,UIMM -> andi. rA,rT,UIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); + } + else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(25)) + { + strcat(mnem, "ori"); // oris rA,rT,UIMM -> ori rA,rT,UIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); + } + else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(27)) + { + strcat(mnem, "xori"); // xoris rA,rT,UIMM -> xori rA,rT,UIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); + } + else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(20)) + { + value = Mask(G_MB(op), G_ME(op)); + strcat(mnem, "rlwimi"); // rlwimi[.] rA,rT,SH,MB,ME -> rlwimi[.] rA,rT,SH,MASK + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value); + } + else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(21)) + { + value = Mask(G_MB(op), G_ME(op)); + if (G_SH(op) == 0) // rlwinm[.] rA,rT,0,MB,ME -> and[.] rA,rT,MASK + { + strcat(mnem, "and"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), value); + } + else // rlwinm[.] rA,rT,SH,MASK + { + strcat(mnem, "rlwinm"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value); + } + } + else if ((op & ~(M_RT|M_RA|M_RB|M_MB|M_ME|M_RC)) == D_OP(23)) + { + value = Mask(G_MB(op), G_ME(op)); + strcat(mnem, "rlwnm"); // rlwnm[.] rA,rT,SH,MB,ME -> rlwnm[.] rA,rT,SH,MASK + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_RB(op), value); + } + else if ((op & ~(M_BO|M_BI|M_BD|M_AA|M_LK)) == D_OP(16)) + { + disp = G_BD(op) * 4; + if (disp & 0x00008000) + disp |= 0xffff0000; + + switch (G_BO(op)) + { + case 0x04: // branch if condition is false + case 0x05: + case 0x06: + case 0x07: + strcat(mnem, "bf"); + break; + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + strcat(mnem, "bt"); + break; + default: + return 0; + } + + if (op & M_LK) strcat(mnem, "l"); + if (op & M_AA) strcat(mnem, "a"); + + sprintf(oprs, "cr%d[%s],0x%08X", G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : vpc)); + } + else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(40))) + { + strcat(mnem, "sub"); + if (op & M_OE) strcat(mnem, "o"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RB(op), G_RA(op)); + } + else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(8))) + { + strcat(mnem, "subc"); + if (op & M_OE) strcat(mnem, "o"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RB(op), G_RA(op)); + } + else + return 0; // no match + return 1; +} + +/* + * BOOL DisassemblePowerPC(UINT32 op, UINT32 vpc, CHAR *mnem, CHAR *oprs, + * BOOL use_simple); + * + * Disassembles one PowerPC 603e instruction. + * + * A non-zero return code indicates that the instruction could not be + * recognized or that the operands to an instruction were invalid. To + * determine which case occured, check if mnem[0] == '\0'. If it does not, + * then the latter case happened. + * + * Arguments: + * op = Instruction word to disassemble. + * vpc = Current instruction address. + * mnem = Buffer to write instruction mnemonic to. If no + * instruction was decoded, mnem[0] and oprs[0] will be set + * to '\0'. + * oprs = Buffer to write any operands to. + * use_simple = If non-zero, simplified forms of instructions will be + * printed in certain cases. + * + * Returns: + * Zero if successful, non-zero if the instruction was unrecognized or + * had an invalid form (see note above in function description.) + */ + +BOOL DisassemblePowerPC(UINT32 op, UINT32 vpc, CHAR *mnem, CHAR *oprs, + BOOL use_simple) +{ + CHAR signed16[12]; + UINT32 disp; + INT i; + + mnem[0] = '\0'; // so we can use strcat() + oprs[0] = '\0'; + + /* + * Decode signed 16-bit fields (SIMM and d) to spare us the work later + */ + + DecodeSigned16(signed16, op, 0); + + /* + * Try simplified forms first, then real instructions + */ + + if (use_simple) + { + if (Simplified(op, vpc, signed16, mnem, oprs)) + return 0; + } + + /* + * Search for the instruction in the list and print it if there's a match + */ + + for (i = 0; i < sizeof(itab) / sizeof(IDESCR); i++) + { + if ((op & ~itab[i].mask) == itab[i].match) // check for match + { + /* + * Base mnemonic followed be O, ., L, A + */ + + strcat(mnem, itab[i].mnem); + if (itab[i].flags & FL_OE) if (op & M_OE) strcat(mnem, "o"); + if (itab[i].flags & FL_RC) if (op & M_RC) strcat(mnem, "."); + if (itab[i].flags & FL_LK) if (op & M_LK) strcat(mnem, "l"); + if (itab[i].flags & FL_AA) if (op & M_AA) strcat(mnem, "a"); + + /* + * Print operands + */ + + switch (itab[i].format) + { + case F_RT_RA_RB: + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + break; + + case F_RT_RA_0_SIMM: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,%s", G_RT(op), G_RA(op), signed16); + else + sprintf(oprs, "r%d,0,%s", G_RT(op), signed16); + break; + + case F_ADDIS: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,0x%04X", G_RT(op), G_RA(op), G_SIMM(op)); + else + sprintf(oprs, "r%d,0,0x%04X", G_RT(op), G_SIMM(op)); + break; + + case F_RT_RA_SIMM: + sprintf(oprs, "r%d,r%d,%s", G_RT(op), G_RA(op), signed16); + break; + + case F_RT_RA: + sprintf(oprs, "r%d,r%d", G_RT(op), G_RA(op)); + break; + + case F_RA_RT_RB: + sprintf(oprs, "r%d,r%d,r%d", G_RA(op), G_RT(op), G_RB(op)); + break; + + case F_RA_RT_UIMM: + sprintf(oprs, "r%d,r%d,0x%04X", G_RA(op), G_RT(op), G_UIMM(op)); + break; + + case F_LI: + disp = G_LI(op) * 4; + if (disp & 0x02000000) // sign extend + disp |= 0xfc000000; + sprintf(oprs, "0x%08X", disp + ((op & M_AA) ? 0 : vpc)); + break; + + case F_BCx: + disp = G_BD(op) * 4; + if (disp & 0x00008000) + disp |= 0xffff0000; + + if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit) + sprintf(oprs, "0x%02X,%d,0x%08X", G_BO(op), G_BI(op), disp + ((op & M_AA) ? 0 : vpc)); + else // BI gives us the condition bit + sprintf(oprs, "0x%02X,cr%d[%s],0x%08X", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : vpc)); + break; + + case F_BO_BI: + if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit) + sprintf(oprs, "0x%02X,%d", G_BO(op), G_BI(op)); + else + sprintf(oprs, "0x%02X,cr%d[%s]", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3]); + break; + + case F_CMP: + sprintf(oprs, "cr%d,%d,r%d,r%d", G_CRFD(op), G_L(op), G_RA(op), G_RB(op)); + break; + + case F_CMP_SIMM: + sprintf(oprs, "cr%d,%d,r%d,%s", G_CRFD(op), G_L(op), G_RA(op), signed16); + break; + + case F_CMP_UIMM: + sprintf(oprs, "cr%d,%d,r%d,0x%04X", G_CRFD(op), G_L(op), G_RA(op), G_UIMM(op)); + break; + + case F_RA_RT: + sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op)); + break; + + case F_CRBD_CRBA_CRBB: + sprintf(oprs, "cr%d[%s],cr%d[%s],cr%d[%s]", G_CRBD(op) / 4, crbit[G_CRBD(op) & 3], G_CRBA(op) / 4, crbit[G_CRBA(op) & 3], G_CRBB(op) / 4, crbit[G_CRBB(op) & 3]); + break; + + case F_RA_0_RB: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d", G_RA(op), G_RB(op)); + else + sprintf(oprs, "0,r%d", G_RB(op)); + break; + + case F_RT_RA_0_RB: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + else + sprintf(oprs, "r%d,0,r%d", G_RT(op), G_RB(op)); + break; + + case F_FRT_FRB: + sprintf(oprs, "f%d,f%d", G_RT(op), G_RB(op)); + break; + + case F_FRT_FRA_FRB: + sprintf(oprs, "f%d,f%d,f%d", G_RT(op), G_RA(op), G_RB(op)); + break; + + case F_FCMP: + sprintf(oprs, "cr%d,f%d,f%d", G_CRFD(op), G_RA(op), G_RB(op)); + break; + + case F_FRT_FRA_FRC_FRB: + sprintf(oprs, "f%d,f%d,f%d,f%d", G_RT(op), G_RA(op), G_REGC(op), G_RB(op)); + break; + + case F_FRT_FRA_FRC: + sprintf(oprs, "f%d,f%d,f%d", G_RT(op), G_RA(op), G_REGC(op)); + break; + + case F_RT_D_RA_0: + if (G_RA(op)) + sprintf(oprs, "r%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + else + sprintf(oprs, "r%d,0x%08X", G_RT(op), (UINT32) ((INT16) G_D(op))); + break; + + case F_RT_D_RA: + sprintf(oprs, "r%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + break; + + case F_FRT_D_RA_0: + if (G_RA(op)) + sprintf(oprs, "f%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + else + sprintf(oprs, "f%d,0x%08X", G_RT(op), (UINT32) ((INT16) G_D(op))); + break; + + case F_FRT_D_RA: + sprintf(oprs, "f%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + break; + + case F_FRT_RA_RB: + sprintf(oprs, "f%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + break; + + case F_FRT_RA_0_RB: + if (G_RA(op)) + sprintf(oprs, "f%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + else + sprintf(oprs, "f%d,0,r%d", G_RT(op), G_RB(op)); + break; + + case F_RT_RA_0_NB: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,%d", G_RT(op), G_RA(op), G_NB(op) ? G_NB(op) : 32); + else + sprintf(oprs, "r%d,0,%d", G_RT(op), G_NB(op) ? G_NB(op) : 32); + break; + + case F_CRFD_CRFS: + sprintf(oprs, "cr%d,cr%d", G_CRFD(op), G_CRFS(op)); + break; + + case F_MCRXR: + sprintf(oprs, "cr%d", G_CRFD(op)); + break; + + case F_RT: + sprintf(oprs, "r%d", G_RT(op)); + break; + + case F_MFFSx: + sprintf(oprs, "f%d", G_RT(op)); + break; + + case F_FCRBD: + sprintf(oprs, "fpscr[%d]", G_CRBD(op)); + break; + + case F_RT_SPR: + sprintf(oprs, "r%d,", G_RT(op)); + SPR(oprs, G_SPR(op)); + break; + + case F_MFSR: + sprintf(oprs, "r%d,sr%d", G_RT(op), G_SR(op)); + break; + + case F_MTCRF: + sprintf(oprs, "0x%02X,r%d", G_CRM(op), G_RT(op)); + break; + + case F_MTFSFx: + sprintf(oprs, "0x%02X,f%d", G_FM(op), G_RB(op)); + break; + + case F_MTFSFIx: + sprintf(oprs, "cr%d,0x%X", G_CRFD(op), G_IMM(op)); + break; + + case F_MTSPR: + SPR(oprs, G_SPR(op)); + sprintf(oprs, "%s,r%d", oprs, G_RT(op)); + break; + + case F_MTSR: + sprintf(oprs, "sr%d,r%d", G_SR(op), G_RT(op)); + break; + + case F_RT_RB: + sprintf(oprs, "r%d,r%d", G_RT(op), G_RB(op)); + break; + + case F_RA_RT_SH_MB_ME: + sprintf(oprs, "r%d,r%d,%d,%d,%d", G_RA(op), G_RT(op), G_SH(op), G_MB(op), G_ME(op)); + break; + + case F_RLWNMx: + sprintf(oprs, "r%d,r%d,r%d,%d,%d", G_RA(op), G_RT(op), G_RB(op), G_MB(op), G_ME(op)); + break; + + case F_SRAWIx: + sprintf(oprs, "r%d,r%d,%d", G_RA(op), G_RT(op), G_SH(op)); + break; + + case F_RB: + sprintf(oprs, "r%d", G_RB(op)); + break; + + case F_TW: + sprintf(oprs, "%d,r%d,r%d", G_TO(op), G_RA(op), G_RB(op)); + break; + + case F_TWI: + sprintf(oprs, "%d,r%d,%s", G_TO(op), G_RA(op), signed16); + break; + + case F_NONE: + default: + break; + } + + return Check(op, itab[i].flags); + } + } + + return 1; // no match found +} + + +#ifdef STANDALONE + +static void PrintUsage(void) +{ + puts("ppcd Version "DISASM_VERSION" by Bart Trzynadlowski: PowerPC 603e Disassembler"); + puts("Usage: ppcd [options]"); + puts("Options: -?,-h Show this help text"); + puts(" -s Start offset (hexadecimal)"); + puts(" -l Number of instructions"); + puts(" -o Set origin (hexadecimal)"); + puts(" -big Big endian [Default]"); + puts(" -little Little endian"); + puts(" -simple Use simplified instruction forms [Default]"); + puts(" -nosimple Do not use simplified forms"); + exit(0); +} + +/* + * int main(int argc, char **argv); + * + * Can you guess what this function is for? ;) + */ + +int main(int argc, char **argv) +{ + CHAR mnem[16], oprs[48]; + FILE *fp; + UINT8 *buffer; + UINT i, fsize, start = 0, len, org, file = 0; + UINT32 op; + BOOL len_specified = 0, org_specified = 0, little = 0, simple = 1; + CHAR *c; + + + if (argc <= 1) + PrintUsage(); + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?")) + PrintUsage(); + else if (!strcmp(argv[i], "-s")) + { + ++i; + if (i >= argc) + fprintf(stderr, "ppcd: warning: no argument to %s\n", "-s"); + else + start = strtoul(argv[i], &c, 16); + } + else if (!strcmp(argv[i], "-l")) + { + ++i; + if (i >= argc) + fprintf(stderr, "ppcd: warning: no argument to %s\n", "-l"); + else + { + len = atoi(argv[i]); + len_specified = 1; + } + } + else if (!strcmp(argv[i], "-o")) + { + ++i; + if (i >= argc) + fprintf(stderr, "ppcd: warning: no argument to %s\n", "-o"); + else + { + org = strtoul(argv[i], &c, 16); + org_specified = 1; + } + } + else if (!strcmp(argv[i], "-big")) + little = 0; + else if (!strcmp(argv[i], "-little")) + little = 1; + else if (!strcmp(argv[i], "-simple")) + simple = 1; + else if (!strcmp(argv[i], "-nosimple")) + simple = 0; + else + file = i; + } + + if (!file) + { + fprintf(stderr, "ppcd: no input file specified\n"); + exit(1); + } + + /* + * Load file + */ + + if ((fp = fopen(argv[file], "rb")) == NULL) + { + fprintf(stderr, "ppcd: failed to open file: %s\n", argv[file]); + exit(1); + } + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + rewind(fp); + + if ((buffer = (UINT8 *) calloc(fsize, sizeof(UINT8))) == NULL) + { + fprintf(stderr, "ppcd: not enough memory to load input file: %s, %lu bytes\n", argv[file], (unsigned long) fsize); + fclose(fp); + exit(1); + } + fread(buffer, sizeof(UINT8), fsize, fp); + fclose(fp); + + if (!len_specified) + len = fsize - start; + else + len *= 4; // each instruction == 4 bytes + + if (!org_specified) + org = start; + + /* + * Disassemble! + */ + + for (i = start; i < fsize && i < (start + len); i += 4, org += 4) + { + if (!little) + op = (buffer[i] << 24) | (buffer[i + 1] << 16) | + (buffer[i + 2] << 8) | buffer[i + 3]; + else + op = (buffer[i + 3] << 24) | (buffer[i + 2] << 16) | + (buffer[i + 1] << 8) | buffer[i + 0]; + + if (DisassemblePowerPC(op, org, mnem, oprs, simple)) + { + if (mnem[0] != '\0') // invalid form + printf("0x%08X: 0x%08X\t%s*\t%s\n", org, op, mnem, oprs); + else + printf("0x%08X: 0x%08X\t?\n", org, op); + } + else + printf("0x%08X: 0x%08X\t%s\t%s\n", org, op, mnem, oprs); + } + + free(buffer); + + return 0; +} + +#endif + diff --git a/osd_common/disasm.h b/osd_common/disasm.h new file mode 100644 index 0000000..b3c0d85 --- /dev/null +++ b/osd_common/disasm.h @@ -0,0 +1,31 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * osd_common/disasm.h + * + * PowerPC disassembler header. + */ + +#ifndef INCLUDED_OSD_COMMON_DISASM_H +#define INCLUDED_OSD_COMMON_DISASM_H + +extern BOOL DisassemblePowerPC(UINT32, UINT32, CHAR *, CHAR *, BOOL); + +#endif // INCLUDED_OSD_COMMON_DISASM_H + diff --git a/osd_common/glrender.c b/osd_common/glrender.c new file mode 100644 index 0000000..b23e598 --- /dev/null +++ b/osd_common/glrender.c @@ -0,0 +1,1571 @@ + +//#define WIREFRAME +// TODO: measure stats in VROM models (size of changing models, size of chunks, etc.) +// TODO: eventually use VBOs for model cache (update glext.h to OpenGL 1.5) +// TODO: cache dlists for per-model state changes +// TODO: align model cache structures to 4 bytes (use stride param) and profile +// TODO: move all config (i.e. USE_MODEL_CACHE, etc.) to makefile +// TODO: add specular lighting +// TODO: add light emission +// TODO: glFlush() ? + +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * osd_common/glrender.c + * + * OpenGL renderer backend. All OS-independent GL code is located here. + * osd_renderer_blit() is the only function not defined here. + */ + +#include "model3.h" +#include +#include +#include // this one can be obtained freely from SGI + + +/******************************************************************/ +/* Configuration */ +/******************************************************************/ + +// debug +//#define ANALYZE_VROM_MODELS + +//#define USE_MODEL_CACHE // controls VROM model cache +#define CACHE_POLYS_AS_QUADS // QUADS should be a little faster + +#define ENABLE_LIGHTING + +/******************************************************************/ +/* Private Data */ +/******************************************************************/ + +/* + * Memory Regions + * + * These will be passed to us before rendering begins. + */ + +static UINT8 *culling_ram_8e; // pointer to Real3D culling RAM +static UINT8 *culling_ram_8c; // pointer to Real3D culling RAM +static UINT8 *polygon_ram; // pointer to Real3D polygon RAM +static UINT8 *texture_ram; // pointer to Real3D texture RAM +static UINT8 *vrom; // pointer to VROM + +/* + * Texture Mapping + * + * The smallest Model 3 textures are 32x32 and the total VRAM texture sheet + * is 2048x2048. Dividings this by 32 gives us 64x64. Each element contains an + * OpenGL ID for a texture. Because of 4bpp textures, 4 entries per texture + * must be maintained. + */ + +static GLint texture_grid[64*64*4]; // 0 indicates unused +static GLbyte texture_buffer[512*512*4]; // for 1 texture + +/* + * Mipmapping + * + * The bottom right of each 2048x1024 texture page contains the smallest + * mipmaps and the top-left has full-sized textures. These tables are used + * to determine where in a texture page a given mipmap is. + */ + +static UINT mip_x[12] = { 0, 1024, 1536, 1792, 1920, 1984, + 2016, 2032, 2040, 2044, 2046, 2047 + }; +static UINT mip_y[12] = { 0, 512, 768, 896, 960, 992, + 1008, 1016, 1020, 1022, 1023, 0 + }; +static UINT mip_scale[7] = { 1, 2, 4, 8, 16, 32, 64 }; + +/* + * Layers + * + * Each layer is a 512x512 RGBA texture. + */ + +static GLubyte * layer[4]; +static GLuint layer_texture[4]; // IDs for the 4 layer textures + +/* + * Resolution and Ratios + * + * The ratio of the OpenGL physical resolution to the Model 3 resolution is + * pre-calculated and passed to us via osd_gl_set_mode(). + */ + +static UINT xres, yres; +static float xres_ratio, yres_ratio; + +/* + * Vertex and Texture Coordinate Configuration + * + * Vertices are in a 17.15 format on Step 1.0 and 13.19 on everything else. + * Texture coordinates can be configured on a per-polygon basis (13.3, 16.0.) + */ + +static float vertex_divisor, texcoord_divisor; + +typedef struct +{ + GLfloat x, y, z; // vertices + GLfloat nx, ny, nz; // normals + GLfloat r, g, b, a; // colors + UINT32 uv; // texture coordinates + GLfloat u, v; + +} VERTEX; + +/* + * Model Cache + */ + +#ifdef USE_MODEL_CACHE + +typedef struct { GLfloat _0, _1; } VEC2; +typedef struct { GLfloat _0, _1, _2; } VEC3; +typedef struct { GLfloat _0, _1, _2, _3; } VEC4; + +typedef struct +{ + UINT ref_count; // number of references + UINT32 addr; // original address + UINT vbo_id; // vertex buffer object ID + UINT index; // index in the vertex array + UINT num_verts; // number of vertices + +} HASH_ENTRY; + +#define MODEL_CACHE_SIZE (256*1024) // ~150K seems to be enough +#define HASH_SIZE (2048*1024) // must be a power of two +#define HASH_FUNC(addr) ((addr >> 2) & (HASH_SIZE - 1)) + +static HASH_ENTRY * model_cache; +static UINT cur_model_index; + +static VEC3 * model_vertex_array; +static VEC3 * model_normal_array; +static VEC4 * model_color_array; +static VEC2 * model_texcoord_array; + +PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; +PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; +PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; +PFNGLISBUFFERARBPROC glIsBufferARB = NULL; +PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; +PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB = NULL; +PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL; +PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL; +PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL; +PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL; + +#endif + +/******************************************************************/ +/* Texture Management */ +/******************************************************************/ + +/* + * void osd_renderer_invalidate_textures(UINT x, UINT y, UINT w, UINT h); + * + * Invalidates all textures that are within the rectangle in texture memory + * defined by the parameters. + * + * Parameters: + * x = Texture pixel X coordinate in texture memory. + * y = Y coordinate. + * w = Width of rectangle in pixels. + * h = Height. + */ + +void osd_renderer_invalidate_textures(UINT x, UINT y, UINT w, UINT h) +{ + UINT yi; + + x /= 32; + y /= 32; + w /= 32; + h /= 32; + +//TODO: do we need to use w*4 here to take care of planes? + for (yi = 0; yi < h; yi++) + { + glDeleteTextures(w, &texture_grid[(yi + y) * (64*4) + x]); + memset((UINT8 *) &texture_grid[(yi + y) * (64*4) + x], 0, w * sizeof(GLint)); + } +} + +/* + * decode_texture(): + * + * Decodes a single texture into texture_buffer[]. + */ + +static void decode_texture(UINT x, UINT y, UINT w, UINT h, UINT format) +{ + UINT xi, yi; + UINT16 rgb16; + UINT8 gray8; + + /* + * Formats: + * + * 0 = 16-bit A1RGB5 + * 1 = 4-bit grayscale, field 0x000F + * 2 = 4-bit grayscale, field 0x00F0 + * 3 = 4-bit grayscale, field 0x0F00 + * 4 = 8-bit A4L4 + * 5 = 8-bit grayscale + * 6 = 4-bit grayscale, field 0xF000 (?) + * 7 = RGBA4 + */ + + switch (format) + { + case 0: // 16-bit, A1RGB5 + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2]; + texture_buffer[((yi * w) + xi) * 4 + 0] = ((rgb16 >> 10) & 0x1F) << 3; + texture_buffer[((yi * w) + xi) * 4 + 1] = ((rgb16 >> 5) & 0x1F) << 3; + texture_buffer[((yi * w) + xi) * 4 + 2] = ((rgb16 >> 0) & 0x1F) << 3; + texture_buffer[((yi * w) + xi) * 4 + 3] = (rgb16 & 0x8000) ? 0 : 0xFF; + } + } + break; + case 1: // 4-bit grayscale + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2]; + texture_buffer[((yi * w) + xi) * 4 + 0] = ((rgb16 >> 0) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 1] = ((rgb16 >> 0) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 2] = ((rgb16 >> 0) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 3] = (GLbyte) 0xFF; + } + } + break; + case 2: // 4-bit grayscale + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2]; + texture_buffer[((yi * w) + xi) * 4 + 0] = ((rgb16 >> 4) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 1] = ((rgb16 >> 4) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 2] = ((rgb16 >> 4) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 3] = (GLbyte) 0xFF; + } + } + break; + case 3: // 4-bit grayscale + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2]; + texture_buffer[((yi * w) + xi) * 4 + 0] = ((rgb16 >> 8) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 1] = ((rgb16 >> 8) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 2] = ((rgb16 >> 8) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 3] = (GLbyte) 0xFF; + } + } + break; + case 4: // 8-bit, A4L4 + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi / 2)) * 2]; + gray8 = (rgb16 >> (!(xi & 1) * 8)) & 0xFF; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 0] = ~(gray8 & 0x0F) << 4; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 1] = ~(gray8 & 0x0F) << 4; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 2] = ~(gray8 & 0x0F) << 4; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 3] = (GLbyte) (gray8 & 0xF0); // fixme + } + } + break; + case 5: // 8-bit grayscale + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi / 2)) * 2]; + gray8 = (rgb16 >> (!(xi & 1) * 8)) & 0xFF; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 0] = gray8; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 1] = gray8; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 2] = gray8; + texture_buffer[((yi * w) + (xi ^ 1)) * 4 + 3] = (GLbyte) 0xFF; + } + } + break; + case 6: // 4-bit grayscale + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2]; + texture_buffer[((yi * w) + xi) * 4 + 0] = ((rgb16 >> 12) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 1] = ((rgb16 >> 12) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 2] = ((rgb16 >> 12) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 3] = (GLbyte) 0xFF; + } + } + break; + case 7: // 16-bit, RGBA4 + for (yi = 0; yi < h; yi++) + { + for (xi = 0; xi < w; xi++) + { + rgb16 = *(UINT16 *) &texture_ram[((y + yi) * 2048 + (x + xi)) * 2]; + texture_buffer[((yi * w) + xi) * 4 + 0] = ((rgb16 >> 12) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 1] = ((rgb16 >> 8) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 2] = ((rgb16 >> 4) & 0xF) << 4; + texture_buffer[((yi * w) + xi) * 4 + 3] = ((rgb16 >> 0) & 0xF) << 4; + } + } + break; + } +} + +/* + * bind_texture(): + * + * Given the coordinates of a texture and its size within the texture sheet, + * an OpenGL texture is created (along with its mipmaps) and uploaded. The + * texture will also be selected so that the caller may use it. + * + * The format is just bits 9 and 8 of polygon header word 7. The repeat mode + * is bits 0 and 1 of word 2. The texture Y coordinate includes the page. + */ + +static void bind_texture(UINT x, UINT y, UINT w, UINT h, UINT format, UINT rep_mode) +{ + UINT plane, page, num_mips, i, mx, my, mwidth, mheight; + GLint tex_id; + + if (w > 512 || h > 512) // error! + { + LOG("texture.log", "%d,%d %dx%d\n", x, y, w, h); + return; + } + + /* + * Although we treat texture memory as a 2048x2048 buffer, it's actually + * split into 2 2048x1024 pages. We must extract this from the Y + * coordinate. + */ + + page = y & 0x400; // page = 1024 or 0, can be added to Y coordinate + y &= 0x3FF; // Y coordinate within page + + /* + * The lesser of the 2 dimensions determines the number of mipmaps that + * are defined. A dimension (width, height) divided by a mip_scale[] + * element yields the dimension of the mipmap. + */ + + switch (min(w, h)) + { + case 32: num_mips = 3; break; + case 64: num_mips = 4; break; + case 128: num_mips = 5; break; + case 256: num_mips = 6; break; + default: num_mips = 7; break; + } + + /* + * The texture grid is a 64x64 array where each element corresponds to + * a 32x32 texture in texture RAM (2048x2048 pixels total.) Because 4-bit + * textures are stored like 16-bit textures with 4 different fields, + * we need 4 "planes" per element in the texture grid, because 1 32x32 + * texture slot may actually contain 4 different 4-bit textures. + */ + + switch (format) // determine which plane for 4bpp textures + { + case 1: plane = 3; break; + case 2: plane = 2; break; + case 3: plane = 1; break; + default: plane = 0; break; + } + + /* + * If the texture is already cached, bind it and we're done + */ + + tex_id = texture_grid[((y + page) / 32) * (64*4) + (x / 32) + plane]; + if (tex_id != 0) // already exists, bind and exit + { + glBindTexture(GL_TEXTURE_2D, tex_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (rep_mode & 2) ? GL_MIRRORED_REPEAT_ARB : GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (rep_mode & 1) ? GL_MIRRORED_REPEAT_ARB : GL_REPEAT); + return; + } + + /* + * Decode the texture (all mipmaps), bind it, upload it, and mark it in + * the grid as used + */ + + glGenTextures(1, &tex_id); + glBindTexture(GL_TEXTURE_2D, tex_id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (rep_mode & 2) ? GL_MIRRORED_REPEAT_ARB : GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (rep_mode & 1) ? GL_MIRRORED_REPEAT_ARB : GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_mips - 1); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (GLfloat) num_mips - 1); + + for (i = 0; i < num_mips; i++) + { + mx = mip_x[i] + x / mip_scale[i]; + my = mip_y[i] + y / mip_scale[i]; + mwidth = w / mip_scale[i]; + mheight = h / mip_scale[i]; + + decode_texture(mx, my + page, mwidth, mheight, format); + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, mwidth, mheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_buffer); + } + + texture_grid[((y + page) / 32) * (64*4) + (x / 32) + plane] = tex_id; // mark texture as used +} + +/******************************************************************/ +/* Model Caching and Drawing */ +/******************************************************************/ + +#define get_word(a) (*a) + +/* + * Useful Polygon Header Macros + * + * The parameter is a 7-element array of 32-bit words (the 7-word header.) + */ + +#define STOP_BIT(h) (h[1] & 0x04) +#define IS_QUAD(h) (h[0] & 0x40) +#define GET_LINK_DATA(h) (h[0] & 0x0F) +#define IS_UV_16(h) (h[1] & 0x40) +#define IS_TEXTURE_ENABLED(h) (h[6] & 0x04000000) +#define IS_TEXTURE_TRANSPARENT(h) (h[6] & 0x80000000) +#define IS_LIGHTING_DISABLED(h) (h[6] & 0x10000) +#define IS_OPAQUE(h) (h[6] & 0x00800000) +#define COLOR_RED(h) ((h[4] >> 24) & 0xFF) +#define COLOR_GREEN(h) ((h[4] >> 16) & 0xFF) +#define COLOR_BLUE(h) ((h[4] >> 8) & 0xFF) +#define GET_TEXTURE_X(h) ((((h[4] & 0x1F) << 1) | ((h[5] & 0x80) >> 7)) * 32) +#define GET_TEXTURE_Y(h) (((h[5] & 0x1F) | ((h[4] & 0x40) >> 1)) * 32) +#define GET_TEXTURE_WIDTH(h) (32 << ((h[3] >> 3) & 7)) +#define GET_TEXTURE_HEIGHT(h) (32 << ((h[3] >> 0) & 7)) +#define GET_TEXTURE_FORMAT(h) ((h[6] >> 7) & 7) +#define GET_TEXTURE_REPEAT(h) (h[2] & 3) +#define GET_TRANSLUCENCY(h) ((h[6] >> 18) & 0x1F) + +/* + * convert_vertex_to_float(): + * + * Converts from a fixed-point vertex to a float. Accepts a signed INT32. + */ + +static float convert_vertex_to_float(INT32 num) +{ + return (float) num / vertex_divisor; +} + +/* + * convert_texcoord_to_float(): + * + * Converts a texture coordinate into a floating point number. + */ + +static float convert_texcoord_to_float(UINT32 num) +{ + return (float) num / texcoord_divisor; +} + +/* + * Model Cache + */ + +#ifdef USE_MODEL_CACHE + +static BOOL init_model_cache(void) +{ + UINT i; + + // get pointer to VBO interface + + if(glBindBufferARB == NULL) + { + glBindBufferARB = (PFNGLBINDBUFFERARBPROC) + osd_gl_get_proc_address("glBindBufferARB"); + glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) + osd_gl_get_proc_address("glDeleteBuffersARB"); + glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) + osd_gl_get_proc_address("glGenBuffersARB"); + glIsBufferARB = (PFNGLISBUFFERARBPROC) + osd_gl_get_proc_address("glIsBufferARB"); + glBufferDataARB = (PFNGLBUFFERDATAARBPROC) + osd_gl_get_proc_address("glBufferDataARB"); + glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) + osd_gl_get_proc_address("glBufferSubDataARB"); + glMapBufferARB = (PFNGLMAPBUFFERARBPROC) + osd_gl_get_proc_address("glMapBufferARB"); + glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC) + osd_gl_get_proc_address("glUnmapBufferARB"); + glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) + osd_gl_get_proc_address("glGetBufferParameterivARB"); + glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) + osd_gl_get_proc_address("glGetBufferPointervARB"); + } + + // free any resident VBO + + /* + for(i = 0; i < HASH_SIZE; i++); + if(glIsBufferARB(model_cache[i].vbo_id)); + glDeleteBuffersARB(1, &model_cache[i].vbo_id); + */ + + // free unfreed buffers + + SAFE_FREE(model_cache); + SAFE_FREE(model_vertex_array); + SAFE_FREE(model_normal_array); + SAFE_FREE(model_color_array); + SAFE_FREE(model_texcoord_array); + + // alloc buffers + + model_cache = (HASH_ENTRY *)malloc(HASH_SIZE * sizeof(HASH_ENTRY)); + model_vertex_array = (VEC3 *)malloc(MODEL_CACHE_SIZE * sizeof(VEC3)); + model_normal_array = (VEC3 *)malloc(MODEL_CACHE_SIZE * sizeof(VEC3)); + model_color_array = (VEC4 *)malloc(MODEL_CACHE_SIZE * sizeof(VEC4)); + model_texcoord_array = (VEC2 *)malloc(MODEL_CACHE_SIZE * sizeof(VEC2)); + + // check buffer consistency + + if( (model_cache == NULL) || + (model_vertex_array == NULL) || + (model_normal_array == NULL) || + (model_color_array == NULL) || + (model_texcoord_array == NULL) ) + return FALSE; + + // reset the model cache + + cur_model_index = 0; + + // setup the hash table + + for(i = 0; i < HASH_SIZE; i++) + { + model_cache[i].ref_count = 0; + model_cache[i].addr = 0; + model_cache[i].vbo_id = (UINT)-1; + model_cache[i].index = 0; + model_cache[i].num_verts = 0; + } + + return TRUE; +} + +INLINE void cache_vertex(UINT index, VERTEX * src) +{ + model_vertex_array[index]._0 = src->x; + model_vertex_array[index]._1 = src->y; + model_vertex_array[index]._2 = src->z; + + model_normal_array[index]._0 = src->nx; + model_normal_array[index]._1 = src->ny; + model_normal_array[index]._2 = src->nz; + + model_color_array[index]._0 = src->r; + model_color_array[index]._1 = src->g; + model_color_array[index]._2 = src->b; + model_color_array[index]._3 = src->a; + + model_texcoord_array[index]._0 = src->u; + model_texcoord_array[index]._1 = src->v; +} + +UINT model_addr = 0; + +static BOOL cache_model(UINT32 *m, HASH_ENTRY *h) +{ + VERTEX v[4], prev_v[4]; + UINT link_data, i, j, num_verts, index; + GLfloat texture_width = 1.0f, texture_height = 1.0f, + nx, ny, nz, color[4]; + BOOL end; + + UINT has_tex = 0, old_tex_fmt = 0, old_tex_x = 0, old_tex_y = 0; + GLfloat old_tex_w = 0, old_tex_h = 0; + + if (*m == 0) + return TRUE; + + if(cur_model_index >= MODEL_CACHE_SIZE) + return FALSE; + + index = 0; // number of cached vertices, actually + + h->index = cur_model_index; + h->ref_count ++; + + #ifdef ANALYZE_VROM_MODELS + message(0, "============================================================"); + #endif + + do + { + // setup polygon info + + num_verts = (m[0] & 0x40) ? 4 : 3; + link_data = m[0] & 0xF; + + end = m[1] & 4; + + nx = (GLfloat) (((INT32) m[0]) >> 8) / 4194304.0f; + ny = (GLfloat) (((INT32) m[2]) >> 8) / 4194304.0f; + nz = (GLfloat) (((INT32) m[3]) >> 8) / 4194304.0f; + + color[0] = (GLfloat) COLOR_RED(m) / 255.0f; + color[1] = (GLfloat) COLOR_GREEN(m) / 255.0f; + color[2] = (GLfloat) COLOR_BLUE(m) / 255.0f; + color[3] = 1.0f; + + #ifdef ANALYZE_VROM_MODELS + + if((IS_TEXTURE_ENABLED(m) ? 1 : 0) != has_tex) + message(0, "model at %08X: has_tex %u --> %u", model_addr, has_tex, IS_TEXTURE_ENABLED(m) ? 1 : 0); + has_tex = IS_TEXTURE_ENABLED(m) ? 1 : 0; + + if(IS_TEXTURE_ENABLED(m)) + { + UINT texture_format, texture_x, texture_y; + + texture_width = (GLfloat) GET_TEXTURE_WIDTH(m); + texture_height = (GLfloat) GET_TEXTURE_HEIGHT(m); + texture_format = GET_TEXTURE_FORMAT(m); + + texture_x = GET_TEXTURE_X(m); + texture_y = GET_TEXTURE_Y(m); + //IS_TEXTURE_TRANSPARENT(m); + //GET_TEXTURE_REPEAT(m); + + if(old_tex_fmt != texture_format) + message(0, "model at %08X: tex_fmt %u --> %u", model_addr, old_tex_fmt, texture_format); + if(old_tex_x != texture_x) + message(0, "model at %08X: tex_x %u --> %u", model_addr, old_tex_x, texture_x); + if(old_tex_y != texture_y) + message(0, "model at %08X: tex_y %u --> %u", model_addr, old_tex_y, texture_y); + if(old_tex_w != texture_width) + message(0, "model at %08X: tex_w %f --> %f", model_addr, old_tex_w, texture_width); + if(old_tex_h != texture_height) + message(0, "model at %08X: tex_h %f --> %f", model_addr, old_tex_h, texture_height); + + old_tex_fmt = texture_format; + old_tex_x = texture_x; + old_tex_y = texture_y; + old_tex_w = texture_width; + old_tex_h = texture_height; + } + + #endif + + // select texture coordinate format + + if (IS_UV_16(m)) + texcoord_divisor = 1.0f; // 16.0 + else + texcoord_divisor = 8.0f; // 13.3 + + m += 7; + + // fetch all previous vertices that we need + + i = 0; + for(j = 0; j < 4; j++) + { + if ((link_data & 1)) + v[i++] = prev_v[j]; + link_data >>= 1; + } + + // fetch remaining vertices + + for( ; i < num_verts; i++) + { + v[i].x = convert_vertex_to_float(*m++); + v[i].y = convert_vertex_to_float(*m++); + v[i].z = convert_vertex_to_float(*m++); + v[i].nx = nx; + v[i].ny = ny; + v[i].nz = nz; + v[i].r = color[0]; + v[i].g = color[1]; + v[i].b = color[2]; + v[i].a = color[3]; + v[i].u = convert_texcoord_to_float((*m >> 16) / texture_width); + v[i].v = convert_texcoord_to_float((*m & 0xFFFF) / texture_height); + + m++; + } + + // save back old vertices + + for(i = 0; i < num_verts; i++) + prev_v[i] = v[i]; + + // cache all the vertices + + cache_vertex(cur_model_index + index++, &v[0]); + cache_vertex(cur_model_index + index++, &v[1]); + cache_vertex(cur_model_index + index++, &v[2]); + +#ifdef CACHE_POLYS_AS_QUADS + + if(num_verts == 3) + cache_vertex(cur_model_index + index++, &v[2]); + else + cache_vertex(cur_model_index + index++, &v[3]); +#else + if(num_verts == 4) + { + cache_vertex(cur_model_index + index++, &v[0]); + cache_vertex(cur_model_index + index++, &v[2]); + cache_vertex(cur_model_index + index++, &v[3]); + } +#endif + } + while(!end); + + h->num_verts = index; + cur_model_index += index; + + return TRUE; +} + +static BOOL draw_cached_model(UINT addr, UINT32 * m) +{ + HASH_ENTRY * h = &model_cache[HASH_FUNC(addr)]; + + model_addr = addr; + + if(h->ref_count == 0) // never referenced before, cache it + { + if(!cache_model(m, h)) + { + error("draw_cached_model(): model cache overrun!\n"); + return FALSE; + } + h->addr = addr; + } + else // already cached + { + if(h->addr != addr) // same hash entry for different models + { + error("draw_cached_model(): hash table hit! (%08X)\n", addr); + return FALSE; + } + } + + glDisable(GL_TEXTURE_2D); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); +// glEnableClientState(GL_TEXTURE_COORD_ARRAY); + +#ifdef CACHE_POLYS_AS_QUADS + glDrawArrays(GL_QUADS, h->index, h->num_verts); +#else + glDrawArrays(GL_TRIANGLES, h->index, h->num_verts); +#endif + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); +// glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnable(GL_TEXTURE_2D); + + return TRUE; +} + +#endif // USE_MODEL_CACHE + +/* + * void osd_renderer_draw_model(UINT32 *mdl, UINT32 addr, BOOL little_endian); + * + * Draws a model. + * + * Parameters: + * mdl = Pointer to model to draw. + * addr = Real3D address (for debugging purposes, in case it + * needs to be printed. + * little_endian = True if memory is in little endian format. + */ + +void osd_renderer_draw_model(UINT32 *mdl, UINT32 addr, BOOL little_endian) +{ + VERTEX v[4], prev_v[4]; + UINT32 header[7]; + UINT link_data, texture_width = 1.0f, texture_height = 1.0f; + INT i, j, num_verts; + GLfloat u_coord, v_coord, nx, ny, nz, color[4]; + +#ifdef WIREFRAME + glPolygonMode(GL_FRONT, GL_LINE); + glPolygonMode(GL_BACK, GL_LINE); + glDisable(GL_TEXTURE_2D); + glColor3ub(0xFF, 0xFF, 0xFF); +#endif + + //if (get_word(mdl) == 0) + // return; + + /* + * Draw VROM (static) models + */ + +#ifdef USE_MODEL_CACHE + if(!little_endian) + { + if(draw_cached_model(addr, mdl)) + return; + // if draw_cached_model() failed, draw the uncached model + } +#endif + + /* + * Draw RAM (dynamic) models + */ + + do + { + /* + * Fetch the 7 header words + */ + + for (i = 0; i < 7; i++) + header[i] = get_word(mdl++); + + if( header[6] == 0 ) + return; + + /* + * Get normals + */ + + nx = (GLfloat) (((INT32) header[1]) >> 8) / 4194304.0f; + ny = (GLfloat) (((INT32) header[2]) >> 8) / 4194304.0f; + nz = (GLfloat) (((INT32) header[3]) >> 8) / 4194304.0f; + + /* + * Fetch the all of the vertices + */ + + num_verts = IS_QUAD(header) ? 4 : 3; + link_data = GET_LINK_DATA(header); + + i = 0; + for (j = 0; j < 4; j++) // fetch all previous vertices that we need + { + if ((link_data & 1)) + v[i++] = prev_v[j]; + link_data >>= 1; + } + + for ( ; i < num_verts; i++) // fetch remaining vertices + { + v[i].x = convert_vertex_to_float(get_word(mdl++)); + v[i].y = convert_vertex_to_float(get_word(mdl++)); + v[i].z = convert_vertex_to_float(get_word(mdl++)); + v[i].nx = nx; + v[i].ny = ny; + v[i].nz = nz; + v[i].uv = get_word(mdl++); + } + + /* + * Set color and material properties. + * + * Something is hosed here. The Model 3 works differently. Setting + * the ambient and diffuse material properties to all 1.0 fixes VON2 + * but causes issues in Scud Race (shadows turn white.) + */ + + color[0] = (GLfloat) COLOR_RED(header) / 255.0f; + color[1] = (GLfloat) COLOR_GREEN(header) / 255.0f; + color[2] = (GLfloat) COLOR_BLUE(header) / 255.0f; + if (IS_OPAQUE(header)) + color[3] = 1.0f; // TODO: if translucent polygon, modify this + else + color[3] = GET_TRANSLUCENCY(header) / 31.0f; + + glColor4fv(color); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + { + GLfloat v[4] = { 1.0,1.0,1.0,1.0 }; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, v); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v); + } + + +#ifdef ENABLE_LIGHTING + if (IS_LIGHTING_DISABLED(header)) + glDisable(GL_LIGHTING); +#endif + + /* + * Draw it (and save the vertices to prev_v[]) + */ + + if (IS_TEXTURE_ENABLED(header)) + { + texture_width = GET_TEXTURE_WIDTH(header); + texture_height = GET_TEXTURE_HEIGHT(header); + + bind_texture(GET_TEXTURE_X(header), GET_TEXTURE_Y(header), + texture_width, texture_height, + GET_TEXTURE_FORMAT(header), GET_TEXTURE_REPEAT(header)); + if (IS_TEXTURE_TRANSPARENT(header)) + { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.95f); + } + } + else + glDisable(GL_TEXTURE_2D); + + if (IS_UV_16(header)) + texcoord_divisor = 1.0f; // 16.0 texture coordinates + else + texcoord_divisor = 8.0f; // 13.3 + + glBegin((num_verts == 4) ? GL_QUADS : GL_TRIANGLES); + + for (i = 0; i < num_verts; i++) + { + prev_v[i] = v[i]; + u_coord = convert_texcoord_to_float(v[i].uv >> 16); + v_coord = convert_texcoord_to_float(v[i].uv & 0xFFFF); + glNormal3f(v[i].nx, v[i].ny, v[i].nz); + glTexCoord2f(u_coord / (GLfloat) texture_width, v_coord / (GLfloat) texture_height); + glVertex3f(v[i].x, v[i].y, v[i].z); + } + glEnd(); + + if (IS_TEXTURE_ENABLED(header)) + glDisable(GL_ALPHA_TEST); + else + glEnable(GL_TEXTURE_2D); + +#ifdef ENABLE_LIGHTING + if (IS_LIGHTING_DISABLED(header)) + glEnable(GL_LIGHTING); +#endif + } + while (!STOP_BIT(header)); // continue until stop bit is hit +} + +/******************************************************************/ +/* Lighting */ +/******************************************************************/ + +/* + * void osd_renderer_set_light(INT light_num, LIGHT *light); + * + * Sets a light. + * + * Parameters: + * light_num = Which light number. + * light = Light data. + */ + +void osd_renderer_set_light(INT light_num, LIGHT *light) +{ + GLfloat v[4]; + + switch (light->type) + { + case LIGHT_PARALLEL: + v[0] = light->u; + v[1] = light->v; + v[2] = light->w; + v[3] = 0.0f; // this is a directional light + glLightfv(GL_LIGHT0 + light_num, GL_POSITION, v); + + v[0] = v[1] = v[2] = light->diffuse_intensity; // R, G, B + v[3] = 1.0f; + glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, v); + + v[0] = v[1] = v[2] = light->ambient_intensity; // R, G, B + v[3] = 1.0f; + glLightfv(GL_LIGHT0 + light_num, GL_AMBIENT, v); + + break; + default: + error("Unhandled light type: %d", light->type); + break; + } + + glEnable(GL_LIGHT0 + light_num); +} + +/******************************************************************/ +/* Viewport and Projection */ +/******************************************************************/ + +/* + * void osd_renderer_set_coordinate_system(const MATRIX m); + * + * Applies the coordinate system matrix and makes adjustments so that the + * Model 3 coordinate system is properly handled. + * + * Parameters: + * m = Matrix. + */ + +void osd_renderer_set_coordinate_system(const MATRIX m) +{ + glLoadIdentity(); + glScalef(1.0, -1.0, -1.0); + glMultMatrixf(m); +} + +/* + * void osd_renderer_set_viewport(const VIEWPORT *vp); + * + * Sets up a viewport. Enables Z-buffering. + * + * Parameters: + * vp = Viewport and projection parameters. + */ + +void osd_renderer_set_viewport(const VIEWPORT *vp) +{ + glViewport((UINT) ((float) vp->x * xres_ratio), + (UINT) ((float) (384.0f - (vp->y + vp->height)) * yres_ratio), + (GLint) (vp->width * xres_ratio), + (GLint) (vp->height * yres_ratio)); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(vp->up + vp->down, + (GLfloat) vp->width / (GLfloat) vp->height, + 0.1, 1000000.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glScalef(1.0, -1.0, -1.0); // Model 3 default coordinate system (for lighting) + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); +} + +/******************************************************************/ +/* Matrix Stack */ +/* */ +/* Matrices are stored in OpenGL's column major format so they */ +/* can be passed directly to OpenGL matrix functions. */ +/******************************************************************/ + +/* + * void osd_renderer_multiply_matrix(MATRIX m); + * + * Multiplies the top of the matrix stack by the specified matrix + * + * Parameters: + * m = Matrix to multiply. + */ + +void osd_renderer_multiply_matrix(MATRIX m) +{ + glMultMatrixf(m); +} + +/* + * void osd_renderer_translate_matrix(float x, float y, float z); + * + * Translates the top of the matrix stack. + * + * Parameters: + * x = Translation along X axis. + * y = Y axis. + * z = Z axis. + */ + +void osd_renderer_translate_matrix(float x, float y, float z) +{ + glTranslatef(x, y, z); +} + +/* + * void osd_renderer_push_matrix(void); + * + * Pushes a matrix on to the stack. The matrix pushed is the former top of the + * stack. + */ + +void osd_renderer_push_matrix() +{ + glPushMatrix(); +} + +/* + * void osd_renderer_pop_matrix(void); + * + * Pops a matrix off the top of the stack. + */ + +void osd_renderer_pop_matrix(void) +{ + glPopMatrix(); +} + +/******************************************************************/ +/* Misc. State Management */ +/******************************************************************/ + +/* + * void osd_renderer_begin(void); + * + * Called just before rendering begins for the current frame. Does nothing. + */ + +void osd_renderer_begin(void) +{ +} + +/* + * void osd_renderer_end(void); + * + * Called just after rendering ends for the current frame. Does nothing. + */ + +void osd_renderer_end(void) +{ +} + +/* + * void osd_renderer_clear(BOOL fbuf, BOOL zbuf); + * + * Clears the frame and/or Z-buffer. + * + * Parameters: + * fbuf = If true, framebuffer (color buffer) is cleared. + * zbuf = If true, Z-buffer is cleared. + */ + +void osd_renderer_clear(BOOL fbuf, BOOL zbuf) +{ + GLbitfield buffers = 0; + + if (fbuf) buffers |= GL_COLOR_BUFFER_BIT; + if (zbuf) buffers |= GL_DEPTH_BUFFER_BIT; + + glClear(buffers); +} + +/******************************************************************/ +/* Tile Layer Interface */ +/******************************************************************/ + +static BOOL coff_enabled = FALSE; +static GLfloat coff[3]; + +void osd_renderer_set_color_offset(BOOL is_enabled, + FLOAT32 r, + FLOAT32 g, + FLOAT32 b) +{ + if((coff_enabled = is_enabled) != FALSE) + { + coff[0] = r; + coff[1] = g; + coff[2] = b; + } +} + +/* + * void osd_renderer_draw_layer(UINT layer_num); + * + * Draws a layer. Disables Z-buffering and creates an orthogonal projection. + * + * Parameters: + * layer_num = Layer to draw. + */ + +void osd_renderer_draw_layer(UINT layer_num) +{ + GLfloat temp[3]; // combiner color + + /* + * Disable lighting and set the replace texture mode + */ + + glDisable(GL_LIGHTING); + + if(!coff_enabled) // no color offset + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + else + { + /* + * The color combiner operations is set as follows. + * + * final_color = texture_color ± primary_color + * final_alpha = texture_alpha + * + * OpenGL's color combiner doesn't allow specification of individual + * color component operations (to my knowledge) -- Stefano. + */ + + // setup color combiner + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + + if(coff[0] > 0.0f && coff[1] > 0.0f && coff[2] > 0.0f) + { + // set combiner mode to ADD + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD); + temp[0] = coff[0]; + temp[1] = coff[1]; + temp[2] = coff[2]; + } + else if(coff[0] < 0.0f && coff[1] < 0.0f && coff[2] < 0.0f) + { + // set combiner mode to SUB + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_SUBTRACT); + temp[0] = -coff[0]; + temp[1] = -coff[1]; + temp[2] = -coff[2]; + } +#if 0 + else + error("osd_renderer_draw_layer: non-uniform color offset\n"); +#endif + + // setup color combiner operation + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f); + + // setup alpha combiner operation + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0f); + + // setup primary fragment color + glColor3fv(temp); + } + + /* + * Set orthogonal projection and disable Z-buffering and lighting + */ + + glDisable(GL_DEPTH_TEST); + + glViewport(0, 0, xres, yres); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.0, 1.0, 1.0, 0.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + /* + * Draw the texture + */ + + glEnable(GL_BLEND); // enable blending, an alpha of 0xFF is opaque, 0 is transparent + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, layer_texture[layer_num]); + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); + glTexCoord2f(496.0 / 512.0, 0.0); glVertex3f(1.0, 0.0, 0.0); + glTexCoord2f(496.0 / 512.0, 384.0 / 512.0); glVertex3f(1.0, 1.0, 0.0); + glTexCoord2f(0.0, 384.0 / 512.0); glVertex3f(0.0, 1.0, 0.0); + glEnd(); + + glDisable(GL_BLEND); + + /* + * Re-enable lighting + */ + +#ifdef ENABLE_LIGHTING + glEnable(GL_LIGHTING); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#endif +} + +/* + * void osd_renderer_get_layer_buffer(UINT layer_num, UINT8 **buffer, + * UINT *pitch); + * + * Obtains a layer buffer for the caller (the tilegen) to render to. + * + * Parameters: + * layer_num = The layer number (0-3.) + * buffer = A pointer to the buffer pointer to set to the layer + * memory. + * pitch = Width of layer buffer in pixels will be written to this + * pointer. + */ + +void osd_renderer_get_layer_buffer(UINT layer_num, UINT8 **buffer, UINT *pitch) +{ + *pitch = 512; // currently all layer textures are 512x512 + *buffer = (UINT8 *) layer[layer_num]; +} + +/* + * void osd_renderer_free_layer_buffer(UINT layer_num); + * + * Releases the layer buffer. It is not actually freed, this is primarily for + * APIs that need an "unlock" call after drawing to a texture is done. Here, + * we use it to upload the layer texture. + * + * Parameters: + * layer_num = Layer number. + */ + +void osd_renderer_free_layer_buffer(UINT layer_num) +{ + glBindTexture(GL_TEXTURE_2D, layer_texture[layer_num]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, layer[layer_num]); +} + +/******************************************************************/ +/* Initialization and Set Up */ +/******************************************************************/ + +/* + * void osd_renderer_set_memory(UINT8 *culling_ram_8e_ptr, + * UINT8 *culling_ram_8c_ptr, + * UINT8 *polygon_ram_ptr, + * UINT8 *texture_ram_ptr, + * UINT8 *vrom_ptr); + * + * Receives the Real3D memory regions. + * + * Currently, this function checks the Model 3 stepping and configures the + * renderer appropriately. + * + * Parameters: + * culling_ram_8e_ptr = Pointer to Real3D culling RAM at 0x8E000000. + * culling_ram_8c_ptr = Pointer to Real3D culling RAM at 0x8C000000. + * polygon_ram_ptr = Pointer to Real3D polygon RAM. + * texture_ram_ptr = Pointer to Real3D texture RAM. + * vrom_ptr = Pointer to VROM. + */ + +void osd_renderer_set_memory(UINT8 *culling_ram_8e_ptr, + UINT8 *culling_ram_8c_ptr, + UINT8 *polygon_ram_ptr, UINT8 *texture_ram_ptr, + UINT8 *vrom_ptr) +{ + culling_ram_8e = culling_ram_8e_ptr; + culling_ram_8c = culling_ram_8c_ptr; + polygon_ram = polygon_ram_ptr; + texture_ram = texture_ram_ptr; + vrom = vrom_ptr; + + if (m3_config.step == 0x10) + vertex_divisor = 32768.0f; // 17.15-format vertices + else + vertex_divisor = 524288.0f; // 13.19 +} + +/* + * BOOL osd_gl_check_extension(CHAR *extname); + * + * Checks if an extension is supported. + * + * Parameters: + * extname = String containing the extension name. + * + * Returns: + * Non-zero if the extension is not supported. + */ + +BOOL osd_gl_check_extension(CHAR *extname) +{ + CHAR *p, *end; + INT extname_len, n; + + p = (CHAR *) glGetString(GL_EXTENSIONS); + if (p == 0) + return 0; + extname_len = strlen(extname); + end = p + strlen(p); + + while (p < end) + { + n = strcspn(p, " "); + if (extname_len == n) + { + if (strncmp(extname, p, n) == 0) + return 0; + } + p += (n + 1); + } + + return 1; // not supported +} + +/* + * void osd_gl_set_mode(UINT new_xres, UINT new_yres); + * + * Receives the OpenGL physical resolution and reconfigures appropriately. + * Also generates layer textures and configures some miscellaneous stuff. + * + * NOTE: Do NOT call this a second time unless you call osd_gl_unset_mode() + * first. + * + * Parameters: + * xres = X resolution in pixels. + * yres = Y resolution in pixels. + */ + +void osd_gl_set_mode(UINT new_xres, UINT new_yres) +{ + const GLfloat zero[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + INT i; + + osd_renderer_invalidate_textures(0, 0, 2048, 2048); + + xres = new_xres; + yres = new_yres; + xres_ratio = (float) xres / 496.0f; // Model 3 resolution is 496x384 + yres_ratio = (float) yres / 384.0f; + + /* + * Misc. init + */ + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glShadeModel(GL_SMOOTH); + glClearColor(0.0, 0.0, 0.0, 0.0); // background color + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // nicer perspective view + + glClearDepth(1.0); + + /* + * Disable default ambient lighting and enable lighting + */ + +#ifdef ENABLE_LIGHTING + glEnable(GL_LIGHTING); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero); +#endif + + /* + * Enable 2D texture mapping, GL_MODULATE is for the 3D scene, layer + * rendering will have to use GL_REPLACE. + */ + + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + /* + * Create the 2D layer textures + */ + + for(i = 0; i < 4; i++) + { + SAFE_FREE(layer[i]); + layer[i] = (GLubyte *) malloc(512*512*4); + } + + glGenTextures(4, layer_texture); + + for (i = 0; i < 4; i++) // set up properties for each texture + { + glBindTexture(GL_TEXTURE_2D, layer_texture[i]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, layer[i]); + } + + /* + * Configure the tile generator + */ + + tilegen_set_layer_format(32, 0, 8, 16, 24); + + /* + * Set vertex format + */ + + if (m3_config.step == 0x10) + vertex_divisor = 32768.0f; // 17.15-format vertices + else + vertex_divisor = 524288.0f; // 13.19 + + /* + * Setup model cache + */ + +#ifdef USE_MODEL_CACHE + + if(!init_model_cache()) + error("init_model_cache failed!\n"); + + glVertexPointer(3, GL_FLOAT, 0, model_vertex_array); + glNormalPointer(GL_FLOAT, 0, model_normal_array); + glColorPointer(4, GL_FLOAT, 0, model_color_array); + glTexCoordPointer(2, GL_FLOAT, 0, model_texcoord_array); + +#endif +} + +/* + * void osd_gl_unset_mode(void); + * + * "Unsets" the current mode -- frees textures. osd_gl_set_mode() must be + * called before the renderer is used again. + */ + +void osd_gl_unset_mode(void) +{ + osd_renderer_invalidate_textures(0, 0, 2048, 2048); + glDeleteTextures(4, layer_texture); +} diff --git a/osd_common/osd_common.h b/osd_common/osd_common.h new file mode 100644 index 0000000..d6906e7 --- /dev/null +++ b/osd_common/osd_common.h @@ -0,0 +1,125 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * osd_common/osd_common.h + * + * Header file which defines the OSD interface. This is included last in + * model3.h because it relies on data structures defined there. + */ + +#ifndef INCLUDED_OSD_COMMON_OSD_H +#define INCLUDED_OSD_COMMON_OSD_H + +/******************************************************************/ +/* OSD Includes */ +/******************************************************************/ + +#include "disasm.h" // didn't know where to put it, so I stuck it here ;) + +/******************************************************************/ +/* OSD Data Structures */ +/******************************************************************/ + +/* + * OSD_CONTROLS Structure + * + * Holds the current state of the controls. Filled by the input code and used + * by the control emulation code. + */ + +typedef struct +{ + /* + * Common to all games + */ + + UINT8 system_controls[2]; // maps directly to Fx040004 banks 0 and 1 + UINT8 game_controls[2]; // map directly to Fx040008 and Fx04000C + + /* + * For games with guns + * + * The gun positions are reported in screen coordinates. The emulator will + * make the appropriate adjustments. Gun coordinates should range from + * (0,0), the upper-left corner, to (495,383), the lower-right corner. + */ + + UINT gun_x[2], gun_y[2]; // gun positions for players 1 (0) and 2 (1) + BOOL gun_acquired[2]; // gun acquired status for players 1 and 2 + // 0 = acquired, 1 = lost + + // Analog controls + int analog_axis[8]; +} OSD_CONTROLS; + +/******************************************************************/ +/* Executable memory allocation */ +/******************************************************************/ + +extern void *malloc_exec(int length); +extern void free_exec(void *ptr); + +/******************************************************************/ +/* OSD GUI */ +/******************************************************************/ + +extern void osd_message(); +extern void osd_error(); + +/******************************************************************/ +/* Renderer */ +/******************************************************************/ + +extern void osd_renderer_invalidate_textures(UINT x, UINT y, UINT w, UINT h, UINT8 *texture_sheet); +extern void osd_renderer_draw_model(UINT32 *, UINT32, BOOL); +extern void osd_renderer_multiply_matrix(MATRIX); +extern void osd_renderer_translate_matrix(float, float, float); +extern void osd_renderer_push_matrix(void); +extern void osd_renderer_pop_matrix(void); +extern void osd_renderer_set_light(INT, LIGHT *); +extern void osd_renderer_set_viewport(const VIEWPORT *); +extern void osd_renderer_set_coordinate_system(const MATRIX); +extern void osd_renderer_clear(BOOL, BOOL); +extern void osd_renderer_set_color_offset(BOOL, FLOAT32, FLOAT32, FLOAT32); +extern void osd_renderer_draw_layer(int layer, UINT32 color_offset); +extern void osd_renderer_get_layer_buffer(int layer_num, UINT8 **buffer, int *pitch); +extern void osd_renderer_free_layer_buffer(UINT); +extern void osd_renderer_get_palette_buffer(UINT32 **, int *, int *); +extern void osd_renderer_free_palette_buffer(void); +extern void osd_renderer_blit(void); +extern void osd_renderer_begin_3d_scene(void); +extern void osd_renderer_end_3d_scene(void); +extern void osd_renderer_draw_text(int x, int y, const char* string, DWORD color, BOOL shadow); + + + +/******************************************************************/ +/* Sound Output */ +/******************************************************************/ + +/******************************************************************/ +/* Input */ +/******************************************************************/ + +extern OSD_CONTROLS * osd_input_update_controls(void); +extern BOOL osd_input_init(void); +extern void osd_input_shutdown(void); + +#endif // INCLUDED_OSD_COMMON_OSD_H + diff --git a/osd_common/osd_gl.h b/osd_common/osd_gl.h new file mode 100644 index 0000000..d7b4baf --- /dev/null +++ b/osd_common/osd_gl.h @@ -0,0 +1,39 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * osd_common/osd_gl.h + * + * Header file which exposes the OSD OpenGL interface. These are functions + * which the OSD code must call. + */ + +#ifndef INCLUDED_OSD_COMMON_OSD_GL_H +#define INCLUDED_OSD_COMMON_OSD_GL_H + +/******************************************************************/ +/* OSD OpenGL Functions */ +/******************************************************************/ + +extern BOOL osd_gl_check_extension(CHAR *); +extern void * osd_gl_get_proc_address(const CHAR *); +extern void osd_gl_set_mode(UINT, UINT); +extern void osd_gl_unset_mode(void); + +#endif // INCLUDED_OSD_COMMON_OSD_GL_H + diff --git a/ppc_drc/genx86.c b/ppc_drc/genx86.c new file mode 100644 index 0000000..7e75cfc --- /dev/null +++ b/ppc_drc/genx86.c @@ -0,0 +1,1083 @@ +#include "model3.h" +#include "genx86.h" + +static UINT8 *drc_cache_top; +static UINT8 *drc_cache; + +#define DRC_CACHE_SIZE 0x800000 + +static UINT32 cumulative_instruction_amount; + +static void emit_byte(UINT8 value) +{ + if (drc_cache_top - drc_cache > DRC_CACHE_SIZE) + { + error("gen: drc cache overflow!\n"); + } + + *drc_cache_top++ = value; +} + +static void emit_dword(UINT32 value) +{ + if (drc_cache_top - drc_cache > DRC_CACHE_SIZE) + { + error("gen: drc cache overflow!\n"); + } + + *drc_cache_top++ = (value >> 0) & 0xff; + *drc_cache_top++ = (value >> 8) & 0xff; + *drc_cache_top++ = (value >> 16) & 0xff; + *drc_cache_top++ = (value >> 24) & 0xff; +} + +void gen(GENX86_OPCODE opcode, INT32 dst_param, INT32 src_param) +{ + cumulative_instruction_amount++; + + switch (opcode) + { + case ADD: + { + emit_byte(0x01); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case ADDI: + { + // don't generate anything for dummy code + if (src_param == 0) + return; + + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xc0 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xc0 | dst_param); + emit_dword(src_param); + } + break; + } + + case ADDIM: + { + // don't generate anything for dummy code + if (src_param == 0) + return; + + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0x05); + emit_dword(dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0x05); + emit_dword(dst_param); + emit_dword(src_param); + } + break; + } + + case ADDMR: + { + emit_byte(0x03); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case ADC: + { + emit_byte(0x11); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case ADCI: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xd0 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xd0 | dst_param); + emit_dword(src_param); + } + break; + } + + case ADCMR: + { + emit_byte(0x13); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case AND: + { + emit_byte(0x21); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case ANDI: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xe0 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xe0 | dst_param); + emit_dword(src_param); + } + break; + } + + case ANDIM: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0x25); + emit_dword(dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0x25); + emit_dword(dst_param); + emit_dword(src_param); + } + break; + } + + case ANDMR: + { + emit_byte(0x23); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case BSR: + { + emit_byte(0x0f); + emit_byte(0xbd); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case BSWAP: + { + emit_byte(0x0f); + emit_byte(0xc8 | dst_param); + break; + } + + case BTIM: + { + emit_byte(0x0f); + emit_byte(0xba); + emit_byte(0x25); + emit_dword(dst_param); + emit_byte(src_param); + break; + } + + case BTRI: + { + emit_byte(0x0f); + emit_byte(0xba); + emit_byte(0xf0 | dst_param); + emit_byte(src_param); + break; + } + + case CALL: + { + emit_byte(0xff); + emit_byte(0xd0 | dst_param); + break; + } + + case CALLI: + { + UINT32 s = (UINT64)(drc_cache_top) + 5; + emit_byte(0xe8); + emit_dword((UINT32)(dst_param) - s); + break; + } + + case CMOVAMR: + { + emit_byte(0x0f); + emit_byte(0x47); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case CMOVBMR: + { + emit_byte(0x0f); + emit_byte(0x42); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case CMOVGMR: + { + emit_byte(0x0f); + emit_byte(0x4f); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case CMOVLMR: + { + emit_byte(0x0f); + emit_byte(0x4c); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case CMOVZMR: + { + emit_byte(0x0f); + emit_byte(0x44); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case CMP: + { + emit_byte(0x39); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case CMPI: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xf8 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xf8 | dst_param); + emit_dword(src_param); + } + break; + } + + case CMPIM: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0x3d); + emit_dword(dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0x3d); + emit_dword(dst_param); + emit_dword(src_param); + } + break; + } + + case CMPMR: + { + emit_byte(0x3b); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case CVTSD2SS: + { + emit_byte(0xf2); + emit_byte(0x0f); + emit_byte(0x5a); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case CVTSS2SD: + { + emit_byte(0xf3); + emit_byte(0x0f); + emit_byte(0x5a); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case IDIV: + { + emit_byte(0xf7); + emit_byte(0xf8 | dst_param); + break; + } + + case IMUL: + { + emit_byte(0xf7); + emit_byte(0xe8 | dst_param); + break; + } + + case JMPI: + { + UINT32 s = (UINT64)(drc_cache_top) + 5; + emit_byte(0xe9); + emit_dword((UINT32)(dst_param) - s); + return; + } + + case JMPM: + { + emit_byte(0xff); + emit_byte(0x25); + emit_dword(dst_param); + return; + } + + case JMPR: + { + emit_byte(0xff); + emit_byte(0xe0 | dst_param); + return; + } + + case MOV: + { + emit_byte(0x89); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case MOVI: + { + emit_byte(0xc7); + emit_byte(0xc0 | dst_param); + emit_dword(src_param); + break; + } + + case MOVIM: + { + emit_byte(0xc7); + emit_byte(0x05); + emit_dword(dst_param); + emit_dword(src_param); + break; + } + + case MOVMR: + { + emit_byte(0x8b); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case MOVRM: + { + emit_byte(0x89); + emit_byte(0x05 | (src_param << 3)); + emit_dword(dst_param); + break; + } + + case MOVR8M8: + { + emit_byte(0x88); + emit_byte(0x05 | (src_param << 3)); + emit_dword(dst_param); + break; + } + + case MOVM8R8: + { + emit_byte(0x8a); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + + case MOVS_R8R32: + { + emit_byte(0x0f); + emit_byte(0xbe); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case MOVS_R16R32: + { + emit_byte(0x0f); + emit_byte(0xbf); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case MOVZ_M8R32: + { + emit_byte(0x0f); + emit_byte(0xb6); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case MOVZ_R8R32: + { + emit_byte(0x0f); + emit_byte(0xb6); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case MOVZ_R16R32: + { + emit_byte(0x0f); + emit_byte(0xb7); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case MOVDRX: + { + emit_byte(0x66); + emit_byte(0x0f); + emit_byte(0x6e); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case MOVDXR: + { + emit_byte(0x66); + emit_byte(0x0f); + emit_byte(0x7e); + emit_byte(0xc0 | (src_param << 3) | dst_param); + break; + } + + case MOVQMX: + { + emit_byte(0xf3); + emit_byte(0x0f); + emit_byte(0x7e); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case MOVQXM: + { + emit_byte(0x66); + emit_byte(0x0f); + emit_byte(0xd6); + emit_byte(0x05 | (src_param << 3)); + emit_dword(dst_param); + break; + } + + case MUL: + { + emit_byte(0xf7); + emit_byte(0xe0 | dst_param); + break; + } + + case NEG: + { + emit_byte(0xf7); + emit_byte(0xd8 | dst_param); + break; + } + + case NOT: + { + emit_byte(0xf7); + emit_byte(0xd0 | dst_param); + break; + } + + case OR: + { + emit_byte(0x09); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case ORI: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xc8 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xc8 | dst_param); + emit_dword(src_param); + } + break; + } + + case ORIM: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0x0d); + emit_dword(dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0x0d); + emit_dword(dst_param); + emit_dword(src_param); + } + break; + } + + case ORMR: + { + emit_byte(0x0b); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case POP: + { + emit_byte(0x58 | dst_param); + break; + } + + case POPAD: + { + emit_byte(0x61); + break; + } + + case PUSH: + { + emit_byte(0x50 | dst_param); + break; + } + + case PUSHI: + { + emit_byte(0x68); + emit_dword(dst_param); + break; + } + + case PUSHAD: + { + emit_byte(0x60); + break; + } + + case RET: + { + emit_byte(0xc3); + break; + } + + case ROLCL: + { + emit_byte(0xd3); + emit_byte(0xc0 | dst_param); + break; + } + + case ROLI: + { + if (src_param == 1) + { + emit_byte(0xd1); + emit_byte(0xc0 | dst_param); + } + else + { + emit_byte(0xc1); + emit_byte(0xc0 | dst_param); + emit_byte(src_param); + } + break; + } + + case SETCR8: + { + emit_byte(0x0f); + emit_byte(0x92); + emit_byte(0xc0 | dst_param); + break; + } + + case SETNCR8: + { + emit_byte(0x0f); + emit_byte(0x93); + emit_byte(0xc0 | dst_param); + break; + } + + case SETZR8: + { + emit_byte(0x0f); + emit_byte(0x94); + emit_byte(0xc0 | dst_param); + break; + } + + case SHLCL: + { + emit_byte(0xd3); + emit_byte(0xe0 | dst_param); + break; + } + + case SHLI: + { + if (src_param == 1) + { + emit_byte(0xd1); + emit_byte(0xe0 | dst_param); + } + else + { + emit_byte(0xc1); + emit_byte(0xe0 | dst_param); + emit_byte(src_param); + } + break; + } + + case SHRCL: + { + emit_byte(0xd3); + emit_byte(0xe8 | dst_param); + break; + } + + case SHRI: + { + if (src_param == 1) + { + emit_byte(0xd1); + emit_byte(0xe8 | dst_param); + } + else + { + emit_byte(0xc1); + emit_byte(0xe8 | dst_param); + emit_byte(src_param); + } + break; + } + + case SUB: + { + emit_byte(0x29); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case SUBI: + { + // don't generate anything for dummy code + if (src_param == 0) + return; + + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xe8 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xe8 | dst_param); + emit_dword(src_param); + } + break; + } + + case SUBIM: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0x2d); + emit_dword(dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0x2d); + emit_dword(dst_param); + emit_dword(src_param); + } + break; + } + + case SUBMR: + { + emit_byte(0x2b); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + case TESTI: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0xf6); + emit_byte(0xc0 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0xf7); + emit_byte(0xc0 | dst_param); + emit_dword(src_param); + } + break; + } + + case XCHGR8R8: + { + emit_byte(0x86); + emit_byte(0xc0 | (dst_param << 3) | src_param); + break; + } + + case XOR: + { + emit_byte(0x31); + emit_byte(0xc0 | (src_param << 3) | (dst_param)); + break; + } + + case XORI: + { + if (src_param < 128 && src_param >= -128) + { + // 8-bit sign-extended immediate + emit_byte(0x83); + emit_byte(0xf0 | dst_param); + emit_byte(src_param); + } + else + { + // 32-bit immediate + emit_byte(0x81); + emit_byte(0xf0 | dst_param); + emit_dword(src_param); + } + break; + } + + case XORMR: + { + emit_byte(0x33); + emit_byte(0x05 | (dst_param << 3)); + emit_dword(src_param); + break; + } + + default: + { + printf("DRC ERROR: gen: unknown opcode %08X\n", opcode); + exit(1); + } + } +} + +void gen_jmp_target(JUMP_TARGET *target) +{ + if (target->jump_type == JUMP_TYPE_NONE) + { + // target resolved first, this is a backwards jump + target->jump_type = JUMP_TYPE_BACKWARDS; + target->pointer = drc_cache_top; + } + else if (target->jump_type == JUMP_TYPE_FORWARD) + { + // source already resolved, backpatch the source jump + UINT8 *d = (UINT8 *)(target->pointer); + UINT8 *jump_offset = d - 4; + INT32 jump_length = drc_cache_top - d; + *jump_offset++ = (jump_length >> 0) & 0xff; + *jump_offset++ = (jump_length >> 8) & 0xff; + *jump_offset++ = (jump_length >> 16) & 0xff; + *jump_offset++ = (jump_length >> 24) & 0xff; + } + else + { + printf("DRC ERROR: gen_jmp_target: something went wrong!\n"); + exit(1); + } +} + +void gen_jmp(GENX86_OPCODE opcode, JUMP_TARGET *target) +{ + int jump_size; + UINT8 *s; + + cumulative_instruction_amount++; + + switch (opcode) + { + case JMP: + { + // TODO: check if 8-bit displacement is possible + emit_byte(0xe9); + jump_size = 4; + break; + } + + case JA: + { + emit_byte(0x0f); + emit_byte(0x87); + jump_size = 4; + break; + } + + case JAE: + { + emit_byte(0x0f); + emit_byte(0x83); + jump_size = 4; + break; + } + + case JB: + { + emit_byte(0x0f); + emit_byte(0x82); + jump_size = 4; + break; + } + + case JG: + { + emit_byte(0x0f); + emit_byte(0x8f); + jump_size = 4; + break; + } + + case JL: + { + emit_byte(0x0f); + emit_byte(0x8c); + jump_size = 4; + break; + } + + case JNS: + { + emit_byte(0x0f); + emit_byte(0x89); + jump_size = 4; + break; + } + + case JNZ: + { + // TODO: check if 8-bit displacement is possible + emit_byte(0x0f); + emit_byte(0x85); + jump_size = 4; + break; + } + + case JZ: + { + emit_byte(0x0f); + emit_byte(0x84); + jump_size = 4; + break; + } + + default: + { + printf("DRC ERROR: gen_jmp: unknown opcode %08X\n", opcode); + exit(1); + } + } + + // get the proper source location + s = drc_cache_top + jump_size; + + if (target->jump_type == JUMP_TYPE_NONE) + { + // jump source resolved first, this is a forward jump + target->jump_type = JUMP_TYPE_FORWARD; + target->pointer = s; + + // emit the placeholder offset + if (jump_size == 1) + { + emit_byte(0x00); + } + else if (jump_size == 4) + { + emit_dword(0x00000000); + } + } + else if (target->jump_type == JUMP_TYPE_BACKWARDS) + { + // jump destination already resolved, generate the jump + INT32 jump_length = (UINT64)(target->pointer) - (UINT64)(s); + emit_dword(jump_length); + } + else + { + printf("DRC ERROR: gen_jmp: something went wrong!\n"); + exit(1); + } +} + +void gen_jmp_rpr(INT32 reg1, INT32 reg2) +{ + emit_byte(0xff); + emit_byte(0x20 | 0x04); + emit_byte(reg2 << 3 | reg1); +} + +void gen_mov_dpr_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg) +{ + emit_byte(0x8b); + emit_byte(0x80 | (dst_reg << 3) | (disp_reg)); + emit_dword(disp); +} + +void gen_mov_dprs_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg, INT32 disp_reg_scale) +{ + int scale; + switch (disp_reg_scale) + { + case 2: scale = 1; break; + case 4: scale = 2; break; + case 8: scale = 3; break; + default: scale = 0; break; + } + emit_byte(0x8b); + emit_byte((dst_reg << 3) | 0x04); + emit_byte(scale << 6 | disp_reg << 3 | 0x5); + emit_dword(disp); +} + +void gen_mov_reg_to_dpr(INT32 src_reg, INT32 disp, INT32 disp_reg) +{ + emit_byte(0x89); + emit_byte(0x80 | (src_reg << 3) | (disp_reg)); + emit_dword(disp); +} + +void gen_reset_cache(void) +{ + drc_cache_top = drc_cache; + + memset(drc_cache, 0, DRC_CACHE_SIZE); +} + +UINT8 *gen_get_cache_pos(void) +{ + return drc_cache_top; +} + +UINT32 gen_get_instruction_amount(void) +{ + return cumulative_instruction_amount; +} + +void init_jmp_target(JUMP_TARGET *target) +{ + target->jump_type = JUMP_TYPE_NONE; +} + +void init_genx86(void) +{ + drc_cache = malloc_exec(DRC_CACHE_SIZE); + drc_cache_top = drc_cache; +} + +void shutdown_genx86(void) +{ + // save cache + //save_file("drccache.bin", drc_cache, 0x800000, FALSE); + + free_exec(drc_cache); +} diff --git a/ppc_drc/genx86.h b/ppc_drc/genx86.h new file mode 100644 index 0000000..581b7c8 --- /dev/null +++ b/ppc_drc/genx86.h @@ -0,0 +1,167 @@ +typedef enum +{ + JUMP_TYPE_NONE = 0, + JUMP_TYPE_BACKWARDS = 1, + JUMP_TYPE_FORWARD = 2, +} JUMP_TYPE; + +typedef struct +{ + void *pointer; + JUMP_TYPE jump_type; +} JUMP_TARGET; + +enum +{ + REG_EAX = 0, + REG_ECX = 1, + REG_EDX = 2, + REG_EBX = 3, + REG_ESP = 4, + REG_EBP = 5, + REG_ESI = 6, + REG_EDI = 7 +} X86_REGS; + +enum +{ + REG_AL = 0, + REG_CL = 1, + REG_DL = 2, + REG_BL = 3, + REG_AH = 4, + REG_CH = 5, + REG_DH = 6, + REG_BH = 7 +} X86_REGS8; + +enum +{ + REG_AX = 0, + REG_CX = 1, + REG_DX = 2, + REG_BX = 3, + REG_SP = 4, + REG_BP = 5, + REG_SI = 6, + REG_DI = 7 +} X86_REGS16; + +enum +{ + REG_XMM0 = 0, + REG_XMM1 = 1, + REG_XMM2 = 2, + REG_XMM3 = 3, + REG_XMM4 = 4, + REG_XMM5 = 5, + REG_XMM6 = 6, + REG_XMM7 = 7, +} X86_REGS_SSE2; + +typedef enum +{ + ADD, + ADDI, + ADDIM, + ADDMR, + ADC, + ADCI, + ADCMR, + AND, + ANDI, + ANDIM, + ANDMR, + BSR, + BSWAP, + BTIM, + BTRI, + CALL, + CALLI, + CMOVAMR, + CMOVBMR, + CMOVGMR, + CMOVLMR, + CMOVZMR, + CMP, + CMPI, + CMPIM, + CMPMR, + CVTSD2SS, + CVTSS2SD, + IDIV, + IMUL, + JA, + JAE, + JB, + JG, + JL, + JMP, + JMPI, + JMPM, + JMPR, + JNS, + JNZ, + JZ, + MOV, + MOVI, + MOVIM, + MOVMR, + MOVRM, + MOVR8M8, + MOVM8R8, + MOVS_R8R32, + MOVS_R16R32, + MOVZ_M8R32, + MOVZ_R8R32, + MOVZ_R16R32, + MOVDRX, + MOVDXR, + MOVQMX, + MOVQXM, + MUL, + NEG, + NOT, + OR, + ORI, + ORIM, + ORMR, + POP, + POPAD, + PUSH, + PUSHAD, + PUSHI, + RET, + ROLCL, + ROLI, + SETCR8, + SETNCR8, + SETZR8, + SHLCL, + SHLI, + SHRCL, + SHRI, + SUB, + SUBI, + SUBIM, + SUBMR, + TESTI, + XCHGR8R8, + XOR, + XORI, + XORMR, +} GENX86_OPCODE; + +void gen(GENX86_OPCODE opcode, INT32 dst_param, INT32 src_param); +void gen_jmp_target(JUMP_TARGET *target); +void gen_jmp(GENX86_OPCODE opcode, JUMP_TARGET *target); +void gen_jmp_rpr(INT32 reg1, INT32 reg2); +void gen_mov_dpr_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg); +void gen_mov_dprs_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg, INT32 disp_reg_scale); +void gen_mov_reg_to_dpr(INT32 src_reg, INT32 disp, INT32 disp_reg); +void gen_reset_cache(void); +UINT8 *gen_get_cache_pos(void); +UINT32 gen_get_instruction_amount(void); +void init_jmp_target(JUMP_TARGET *target); +void init_genx86(void); +void shutdown_genx86(void); \ No newline at end of file diff --git a/ppc_drc/ppc_drc.c b/ppc_drc/ppc_drc.c new file mode 100644 index 0000000..a01b099 --- /dev/null +++ b/ppc_drc/ppc_drc.c @@ -0,0 +1,1544 @@ +/* Simple PowerPC recompiler */ + +#include "model3.h" +#include "ppc_drc.h" +#include "genx86.h" + +#define COMPILE_OPS 1 +#define DISABLE_UNTESTED_OPS 0 +#define ENABLE_FASTRAM_PATH 1 +#define ENABLE_FASTRAM_PATH_FPU 1 + +#define DONT_COMPILE_ADD 0 +#define DONT_COMPILE_ADDC 0 +#define DONT_COMPILE_ADDE 0 +#define DONT_COMPILE_ADDI 0 +#define DONT_COMPILE_ADDIC 0 +#define DONT_COMPILE_ADDIC_RC 0 +#define DONT_COMPILE_ADDIS 0 +#define DONT_COMPILE_ADDME 0 +#define DONT_COMPILE_ADDZE 0 +#define DONT_COMPILE_AND 0 +#define DONT_COMPILE_ANDC 0 +#define DONT_COMPILE_ANDI_RC 0 +#define DONT_COMPILE_ANDIS_RC 0 +#define DONT_COMPILE_CMP 0 +#define DONT_COMPILE_CMPI 0 +#define DONT_COMPILE_CMPL 0 +#define DONT_COMPILE_CMPLI 0 +#define DONT_COMPILE_EXTSB 0 +#define DONT_COMPILE_EXTSH 0 +#define DONT_COMPILE_LBZ 0 +#define DONT_COMPILE_LBZU 0 +#define DONT_COMPILE_LBZUX 0 +#define DONT_COMPILE_LBZX 0 +#define DONT_COMPILE_LHA 0 +#define DONT_COMPILE_LHAU 0 +#define DONT_COMPILE_LHAUX 0 +#define DONT_COMPILE_LHAX 0 +#define DONT_COMPILE_LHBRX 1 +#define DONT_COMPILE_LHZ 0 +#define DONT_COMPILE_LHZU 0 +#define DONT_COMPILE_LHZUX 0 +#define DONT_COMPILE_LHZX 0 +#define DONT_COMPILE_LWBRX 1 +#define DONT_COMPILE_LWZ 0 +#define DONT_COMPILE_LWZU 0 +#define DONT_COMPILE_LWZUX 0 +#define DONT_COMPILE_LWZX 0 +#define DONT_COMPILE_MFSPR 0 // slow? +#define DONT_COMPILE_MTSPR 0 // slow? +#define DONT_COMPILE_MULHW 0 +#define DONT_COMPILE_MULHWU 0 +#define DONT_COMPILE_MULLI 0 +#define DONT_COMPILE_MULLW 0 +#define DONT_COMPILE_NAND 0 +#define DONT_COMPILE_NEG 0 +#define DONT_COMPILE_NOR 0 +#define DONT_COMPILE_OR 0 +#define DONT_COMPILE_ORC 0 +#define DONT_COMPILE_ORI 0 +#define DONT_COMPILE_ORIS 0 +#define DONT_COMPILE_RLWIMI 1 // slow? +#define DONT_COMPILE_RLWINM 1 // slow? +#define DONT_COMPILE_RLWNM 1 // slow? +#define DONT_COMPILE_SLW 1 // slow? +#define DONT_COMPILE_SRW 1 // slow? +#define DONT_COMPILE_STB 0 +#define DONT_COMPILE_STBU 0 +#define DONT_COMPILE_STBUX 0 +#define DONT_COMPILE_STBX 0 +#define DONT_COMPILE_STH 1 +#define DONT_COMPILE_STW 0 +#define DONT_COMPILE_STWU 0 +#define DONT_COMPILE_STWUX 0 +#define DONT_COMPILE_STWX 0 +#define DONT_COMPILE_SUBF 0 +#define DONT_COMPILE_SUBFC 0 +#define DONT_COMPILE_SUBFIC 0 +#define DONT_COMPILE_XOR 0 +#define DONT_COMPILE_XORI 0 +#define DONT_COMPILE_XORIS 0 +#define DONT_COMPILE_LFS 0 +#define DONT_COMPILE_LFSU 0 +#define DONT_COMPILE_LFSUX 0 +#define DONT_COMPILE_LFSX 0 +#define DONT_COMPILE_LFD 0 +#define DONT_COMPILE_LFDU 0 +#define DONT_COMPILE_LFDUX 0 +#define DONT_COMPILE_LFDX 0 +#define DONT_COMPILE_STFS 0 +#define DONT_COMPILE_STFSU 0 +#define DONT_COMPILE_STFSUX 0 +#define DONT_COMPILE_STFSX 0 +#define DONT_COMPILE_STFD 0 +#define DONT_COMPILE_STFDU 0 +#define DONT_COMPILE_STFDUX 0 +#define DONT_COMPILE_STFDX 0 + + +void **drccore_get_lookup_ptr(UINT32 pc); +void drccore_insert_dispatcher(void); +void drccore_insert_cycle_check(int cycles, UINT32 pc); +void drccore_insert_sanity_check(UINT32 value); +void drccore_init(void); +void drccore_shutdown(void); +void drccore_reset(void); +void drccore_execute(void); + + +// for fastram path +extern UINT8 *ram; + + +#define DRC_END_BLOCK 0x1 + + +#define RD ((op >> 21) & 0x1F) +#define RT ((op >> 21) & 0x1f) +#define RS ((op >> 21) & 0x1f) +#define RA ((op >> 16) & 0x1f) +#define RB ((op >> 11) & 0x1f) +#define RC ((op >> 6) & 0x1f) + +#define MB ((op >> 6) & 0x1f) +#define ME ((op >> 1) & 0x1f) +#define SH ((op >> 11) & 0x1f) +#define BO ((op >> 21) & 0x1f) +#define BI ((op >> 16) & 0x1f) +#define CRFD ((op >> 23) & 0x7) +#define CRFA ((op >> 18) & 0x7) +#define FXM ((op >> 12) & 0xff) +#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) + +#define SIMM16 (INT32)(INT16)(op & 0xffff) +#define UIMM16 (UINT32)(op & 0xffff) + +#define RCBIT (op & 0x1) +#define OEBIT (op & 0x400) +#define AABIT (op & 0x2) +#define LKBIT (op & 0x1) + +#define REG(x) (ppc.r[x]) +#define LR (ppc.lr) +#define CTR (ppc.ctr) +#define XER (ppc.xer) +#define CR(x) (ppc.cr[x]) +#define MSR (ppc.msr) +#define SRR0 (ppc.srr0) +#define SRR1 (ppc.srr1) +#define SRR2 (ppc.srr2) +#define SRR3 (ppc.srr3) +#define EVPR (ppc.evpr) +#define EXIER (ppc.exier) +#define EXISR (ppc.exisr) +#define DEC (ppc.dec) +#define FPR(x) (ppc.fpr[x]) +#define FM ((op >> 17) & 0xFF) +#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) + +#define CHECK_SUPERVISOR() \ + if((ppc.msr & 0x4000) != 0){ \ + } + +#define CHECK_FPU_AVAILABLE() \ + if((ppc.msr & 0x2000) == 0){ \ + } + +static UINT32 ppc_field_xlat[256]; + +#define FPSCR_FX 0x80000000 +#define FPSCR_FEX 0x40000000 +#define FPSCR_VX 0x20000000 +#define FPSCR_OX 0x10000000 +#define FPSCR_UX 0x08000000 +#define FPSCR_ZX 0x04000000 +#define FPSCR_XX 0x02000000 + + + +#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) +#define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) +#define _BIT(n) (1 << (n)) +#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) +#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) +#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) +#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) +#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) + +#define XER_SO 0x80000000 +#define XER_OV 0x40000000 +#define XER_CA 0x20000000 + +#define MSR_POW 0x00040000 /* Power Management Enable */ +#define MSR_WE 0x00040000 +#define MSR_CE 0x00020000 +#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ +#define MSR_EE 0x00008000 /* External Interrupt Enable */ +#define MSR_PR 0x00004000 /* Problem State */ +#define MSR_FP 0x00002000 /* Floating Point Available */ +#define MSR_ME 0x00001000 /* Machine Check Enable */ +#define MSR_FE0 0x00000800 +#define MSR_SE 0x00000400 /* Single Step Trace Enable */ +#define MSR_BE 0x00000200 /* Branch Trace Enable */ +#define MSR_DE 0x00000200 +#define MSR_FE1 0x00000100 +#define MSR_IP 0x00000040 /* Interrupt Prefix */ +#define MSR_IR 0x00000020 /* Instruction Relocate */ +#define MSR_DR 0x00000010 /* Data Relocate */ +#define MSR_PE 0x00000008 +#define MSR_PX 0x00000004 +#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ +#define MSR_LE 0x00000001 + +#define TSR_ENW 0x80000000 +#define TSR_WIS 0x40000000 + +#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) +#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) + +typedef union { + UINT64 id; + double fd; +} FPR; + +typedef union { + UINT32 i; + float f; +} FPR32; + +typedef struct { + UINT32 u; + UINT32 l; +} BATENT; + + +typedef struct { + UINT32 r[32]; + UINT32 pc; + UINT32 npc; + + UINT32 *op; + + UINT32 lr; + UINT32 ctr; + UINT32 xer; + UINT32 msr; + UINT8 cr[8]; + UINT32 pvr; + UINT32 srr0; + UINT32 srr1; + UINT32 srr2; + UINT32 srr3; + UINT32 hid0; + UINT32 hid1; + UINT32 hid2; + UINT32 sdr1; + UINT32 sprg[4]; + + BATENT ibat[4]; + BATENT dbat[4]; + + int reserved; + UINT32 reserved_address; + + int interrupt_pending; + int external_int; + + UINT64 tb; /* 56-bit timebase register */ + + PPC_FETCH_REGION cur_fetch; + PPC_FETCH_REGION * fetch; + + UINT32 dec, dec_frac; + UINT32 fpscr; + + FPR fpr[32]; + UINT32 sr[16]; +} PPC_REGS; + +static int ppc_icount; +static int ppc_stolen_cycles; +static int ppc_decrementer_exception_scheduled; +static int ppc_tb_base_icount; +static int ppc_dec_base_icount; +static int ppc_dec_trigger_cycle; +static int ppc_dec_divider; +static int bus_freq_multiplier = 1; +static PPC_REGS ppc; +static UINT32 ppc_rotate_mask[32][32]; + + +#define TB_DIVIDER 5 + +INLINE int CYCLES_TO_DEC(int cycles) +{ + return cycles / ppc_dec_divider; +} + +INLINE int DEC_TO_CYCLES(int dec) +{ + return dec * ppc_dec_divider; +} + + + +static void ppc_change_pc(UINT32 newpc) +{ + UINT i; + + if (ppc.cur_fetch.start <= newpc && newpc <= ppc.cur_fetch.end) + { + ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start)); + return; + } + + for(i = 0; ppc.fetch[i].ptr != NULL; i++) + { + if (ppc.fetch[i].start <= newpc && newpc <= ppc.fetch[i].end) + { + ppc.cur_fetch.start = ppc.fetch[i].start; + ppc.cur_fetch.end = ppc.fetch[i].end; + ppc.cur_fetch.ptr = ppc.fetch[i].ptr; + + ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start)); + + return; + } + } + + error("Invalid PC %08X, previous PC %08X\n", newpc, ppc.pc); +} + +INLINE UINT8 READ8(UINT32 address) +{ + return m3_ppc_read_8(address); +} + +INLINE UINT16 READ16(UINT32 address) +{ + return m3_ppc_read_16(address); +} + +INLINE UINT32 READ32(UINT32 address) +{ + return m3_ppc_read_32(address); +} + +INLINE UINT64 READ64(UINT32 address) +{ + return m3_ppc_read_64(address); +} + +INLINE void WRITE8(UINT32 address, UINT8 data) +{ + m3_ppc_write_8(address, data); +} + +INLINE void WRITE16(UINT32 address, UINT16 data) +{ + m3_ppc_write_16(address, data); +} + +INLINE void WRITE32(UINT32 address, UINT32 data) +{ + m3_ppc_write_32(address, data); +} + +INLINE void WRITE64(UINT32 address, UINT64 data) +{ + m3_ppc_write_64(address, data); +} + + +/*********************************************************************/ + + +INLINE void SET_CR0(INT32 rd) +{ + if( rd < 0 ) { + CR(0) = 0x8; + } else if( rd > 0 ) { + CR(0) = 0x4; + } else { + CR(0) = 0x2; + } + + if( XER & XER_SO ) + CR(0) |= 0x1; +} + +INLINE void SET_CR1(void) +{ + CR(1) = (ppc.fpscr >> 28) & 0xf; +} + +INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( ADD_OV(rd, ra, rb) ) + XER |= XER_SO | XER_OV; + else + XER &= ~XER_OV; +} + +INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( SUB_OV(rd, ra, rb) ) + XER |= XER_SO | XER_OV; + else + XER &= ~XER_OV; +} + +INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( ADD_CA(rd, ra, rb) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( SUB_CA(rd, ra, rb) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) +{ + UINT32 ctr_ok; + UINT32 condition_ok; + UINT32 bo0 = (bo & 0x10) ? 1 : 0; + UINT32 bo1 = (bo & 0x08) ? 1 : 0; + UINT32 bo2 = (bo & 0x04) ? 1 : 0; + UINT32 bo3 = (bo & 0x02) ? 1 : 0; + + if( bo2 == 0 ) + --CTR; + + ctr_ok = bo2 | ((CTR != 0) ^ bo3); + condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); + + return ctr_ok && condition_ok; +} + +INLINE UINT64 ppc_read_timebase(void) +{ + int cycles = ppc_tb_base_icount - ppc_icount; + + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + return ppc.tb + (cycles / TB_DIVIDER); +} + +INLINE void ppc_write_timebase_l(UINT32 tbl) +{ + ppc_tb_base_icount = ppc_icount; + + ppc.tb &= ~0xffffffff; + ppc.tb |= tbl; +} + +INLINE void ppc_write_timebase_h(UINT32 tbh) +{ + ppc_tb_base_icount = ppc_icount; + + ppc.tb &= 0xffffffff; + ppc.tb |= (UINT64)(tbh) << 32; +} + +INLINE UINT32 read_decrementer(void) +{ + int cycles = ppc_dec_base_icount - ppc_icount; + int dec_cycles = CYCLES_TO_DEC(cycles); + + // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly + return DEC - dec_cycles; +} + +INLINE void write_decrementer(UINT32 value) +{ + int dec_cycles; + //ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2); + ppc_dec_base_icount = ppc_icount; + + DEC = value; + + dec_cycles = CYCLES_TO_DEC(ppc_icount); + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - dec_cycles) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = DEC_TO_CYCLES((dec_cycles - DEC)); + + ppc_stolen_cycles += ppc_dec_trigger_cycle; + ppc_icount = ppc_icount - ppc_dec_trigger_cycle; + + ppc_decrementer_exception_scheduled = 1; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + + ppc_decrementer_exception_scheduled = 0; + } +} + +/*********************************************************************/ + +INLINE void ppc_set_spr(int spr, UINT32 value) +{ + switch (spr) + { + case SPR_LR: LR = value; return; + case SPR_CTR: CTR = value; return; + case SPR_XER: XER = value; return; + case SPR_SRR0: ppc.srr0 = value; return; + case SPR_SRR1: ppc.srr1 = value; return; + case SPR_SPRG0: ppc.sprg[0] = value; return; + case SPR_SPRG1: ppc.sprg[1] = value; return; + case SPR_SPRG2: ppc.sprg[2] = value; return; + case SPR_SPRG3: ppc.sprg[3] = value; return; + case SPR_PVR: return; + + case SPR603E_DEC: + if(((value & 0x80000000) && !(DEC & 0x80000000)) || value == 0) + { + /* trigger interrupt */ + //ppc.interrupt_pending |= 0x2; + } + write_decrementer(value); + return; + + case SPR603E_TBL_W: + case SPR603E_TBL_R: // special 603e case + ppc_write_timebase_l(value); + return; + + case SPR603E_TBU_R: + case SPR603E_TBU_W: // special 603e case + ppc_write_timebase_h(value); + return; + + case SPR603E_HID0: ppc.hid0 = value; return; + case SPR603E_HID1: ppc.hid1 = value; return; + case SPR603E_HID2: ppc.hid2 = value; return; + + case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; + case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; + case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; + case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; + case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; + case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; + case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; + case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; + case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; + case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; + case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; + case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; + case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; + case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; + case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; + case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; + + case SPR603E_SDR1: + ppc.sdr1 = value; + return; + } + + error("ppc: set_spr: unknown spr %d (%03X) !", spr, spr); +} + +INLINE UINT32 ppc_get_spr(int spr) +{ + switch(spr) + { + case SPR_LR: return LR; + case SPR_CTR: return CTR; + case SPR_XER: return XER; + case SPR_SRR0: return ppc.srr0; + case SPR_SRR1: return ppc.srr1; + case SPR_SPRG0: return ppc.sprg[0]; + case SPR_SPRG1: return ppc.sprg[1]; + case SPR_SPRG2: return ppc.sprg[2]; + case SPR_SPRG3: return ppc.sprg[3]; + case SPR_PVR: return ppc.pvr; + case SPR603E_TBL_R: + error("ppc: get_spr: TBL_R "); + break; + + case SPR603E_TBU_R: + error("ppc: get_spr: TBU_R "); + break; + + case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); + case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); + case SPR603E_HID0: return ppc.hid0; + case SPR603E_HID1: return ppc.hid1; + case SPR603E_HID2: return ppc.hid2; + case SPR603E_DEC: return read_decrementer(); + case SPR603E_SDR1: return ppc.sdr1; + case SPR603E_IBAT0L: return ppc.ibat[0].l; + case SPR603E_IBAT0U: return ppc.ibat[0].u; + case SPR603E_IBAT1L: return ppc.ibat[1].l; + case SPR603E_IBAT1U: return ppc.ibat[1].u; + case SPR603E_IBAT2L: return ppc.ibat[2].l; + case SPR603E_IBAT2U: return ppc.ibat[2].u; + case SPR603E_IBAT3L: return ppc.ibat[3].l; + case SPR603E_IBAT3U: return ppc.ibat[3].u; + case SPR603E_DBAT0L: return ppc.dbat[0].l; + case SPR603E_DBAT0U: return ppc.dbat[0].u; + case SPR603E_DBAT1L: return ppc.dbat[1].l; + case SPR603E_DBAT1U: return ppc.dbat[1].u; + case SPR603E_DBAT2L: return ppc.dbat[2].l; + case SPR603E_DBAT2U: return ppc.dbat[2].u; + case SPR603E_DBAT3L: return ppc.dbat[3].l; + case SPR603E_DBAT3U: return ppc.dbat[3].u; + } + + error("ppc: get_spr: unknown spr %d (%03X) !", spr, spr); + return 0; +} + +INLINE void ppc_set_msr(UINT32 value) +{ + if( value & (MSR_ILE | MSR_LE) ) + error("ppc: set_msr: little_endian mode not supported !"); + + if (ppc.interrupt_pending != 0) + { + ppc_stolen_cycles = ppc_icount; + ppc_icount = 0; + } + + MSR = value; +} + +INLINE UINT32 ppc_get_msr(void) +{ + return MSR; +} + +INLINE void ppc_set_cr(UINT32 value) +{ + CR(0) = (value >> 28) & 0xf; + CR(1) = (value >> 24) & 0xf; + CR(2) = (value >> 20) & 0xf; + CR(3) = (value >> 16) & 0xf; + CR(4) = (value >> 12) & 0xf; + CR(5) = (value >> 8) & 0xf; + CR(6) = (value >> 4) & 0xf; + CR(7) = (value >> 0) & 0xf; +} + +INLINE UINT32 ppc_get_cr(void) +{ + return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); +} + +static UINT32 (* drc_op_table19[1024])(UINT32); +static UINT32 (* drc_op_table31[1024])(UINT32); +static UINT32 (* drc_op_table59[1024])(UINT32); +static UINT32 (* drc_op_table63[1024])(UINT32); +static UINT32 (* drc_op_table[64])(UINT32); + +#include "ppc_itp\ppc_ops.c" +#include "ppc_drc_ops.c" + +static void init_ppc_drc(void) +{ + int i; + for (i=0; i < 64; i++) + { + drc_op_table[i] = drc_invalid; + } + for (i=0; i < 1024; i++) + { + drc_op_table19[i] = drc_invalid; + drc_op_table31[i] = drc_invalid; + drc_op_table59[i] = drc_invalid; + drc_op_table63[i] = drc_invalid; + } + + drc_op_table[ 3] = drc_twi; + drc_op_table[ 7] = drc_mulli; + drc_op_table[ 8] = drc_subfic; + drc_op_table[10] = drc_cmpli; + drc_op_table[11] = drc_cmpi; + drc_op_table[12] = drc_addic; + drc_op_table[13] = drc_addic_rc; + drc_op_table[14] = drc_addi; + drc_op_table[15] = drc_addis; + drc_op_table[16] = drc_bc; + drc_op_table[17] = drc_sc; + drc_op_table[18] = drc_b; + drc_op_table[20] = drc_rlwimi; + drc_op_table[21] = drc_rlwinm; + drc_op_table[23] = drc_rlwnm; + drc_op_table[24] = drc_ori; + drc_op_table[25] = drc_oris; + drc_op_table[26] = drc_xori; + drc_op_table[27] = drc_xoris; + drc_op_table[28] = drc_andi_rc; + drc_op_table[29] = drc_andis_rc; + drc_op_table[32] = drc_lwz; + drc_op_table[33] = drc_lwzu; + drc_op_table[34] = drc_lbz; + drc_op_table[35] = drc_lbzu; + drc_op_table[36] = drc_stw; + drc_op_table[37] = drc_stwu; + drc_op_table[38] = drc_stb; + drc_op_table[39] = drc_stbu; + drc_op_table[40] = drc_lhz; + drc_op_table[41] = drc_lhzu; + drc_op_table[42] = drc_lha; + drc_op_table[43] = drc_lhau; + drc_op_table[44] = drc_sth; + drc_op_table[45] = drc_sthu; + drc_op_table[46] = drc_lmw; + drc_op_table[47] = drc_stmw; + drc_op_table[48] = drc_lfs; + drc_op_table[49] = drc_lfsu; + drc_op_table[50] = drc_lfd; + drc_op_table[51] = drc_lfdu; + drc_op_table[52] = drc_stfs; + drc_op_table[53] = drc_stfsu; + drc_op_table[54] = drc_stfd; + drc_op_table[55] = drc_stfdu; + + drc_op_table19[ 0] = drc_mcrf; + drc_op_table19[ 16] = drc_bclr; + drc_op_table19[ 33] = drc_crnor; + drc_op_table19[ 50] = drc_rfi; + drc_op_table19[ 129] = drc_crandc; + drc_op_table19[ 150] = drc_isync; + drc_op_table19[ 193] = drc_crxor; + drc_op_table19[ 225] = drc_crnand; + drc_op_table19[ 257] = drc_crand; + drc_op_table19[ 289] = drc_creqv; + drc_op_table19[ 417] = drc_crorc; + drc_op_table19[ 449] = drc_cror; + drc_op_table19[ 528] = drc_bcctr; + + drc_op_table31[0x000] = drc_cmp; + drc_op_table31[0x004] = drc_tw; + drc_op_table31[0x008] = drc_subfc; + drc_op_table31[0x208] = drc_subfc; + drc_op_table31[0x00a] = drc_addc; + drc_op_table31[0x20a] = drc_addc; + drc_op_table31[0x00b] = drc_mulhwu; + drc_op_table31[0x013] = drc_mfcr; + drc_op_table31[0x014] = drc_lwarx; + drc_op_table31[0x017] = drc_lwzx; + drc_op_table31[0x018] = drc_slw; + drc_op_table31[0x01a] = drc_cntlzw; + drc_op_table31[0x01c] = drc_and; + drc_op_table31[0x020] = drc_cmpl; + drc_op_table31[0x028] = drc_subf; + drc_op_table31[0x228] = drc_subf; + drc_op_table31[0x036] = drc_dcbst; + drc_op_table31[0x037] = drc_lwzux; + drc_op_table31[0x03c] = drc_andc; + drc_op_table31[0x04b] = drc_mulhw; + drc_op_table31[0x053] = drc_mfmsr; + drc_op_table31[0x056] = drc_dcbf; + drc_op_table31[0x057] = drc_lbzx; + drc_op_table31[0x068] = drc_neg; + drc_op_table31[0x268] = drc_neg; + drc_op_table31[0x077] = drc_lbzux; + drc_op_table31[0x07c] = drc_nor; + drc_op_table31[0x088] = drc_subfe; + drc_op_table31[0x288] = drc_subfe; + drc_op_table31[0x08a] = drc_adde; + drc_op_table31[0x28a] = drc_adde; + drc_op_table31[0x090] = drc_mtcrf; + drc_op_table31[0x092] = drc_mtmsr; + drc_op_table31[0x096] = drc_stwcx_rc; + drc_op_table31[0x097] = drc_stwx; + drc_op_table31[0x0b7] = drc_stwux; + drc_op_table31[0x0c8] = drc_subfze; + drc_op_table31[0x2c8] = drc_subfze; + drc_op_table31[0x0ca] = drc_addze; + drc_op_table31[0x2ca] = drc_addze; + drc_op_table31[0x0d2] = drc_mtsr; + drc_op_table31[0x0d7] = drc_stbx; + drc_op_table31[0x0e8] = drc_subfme; + drc_op_table31[0x2e8] = drc_subfme; + drc_op_table31[0x0ea] = drc_addme; + drc_op_table31[0x2ea] = drc_addme; + drc_op_table31[0x0eb] = drc_mullw; + drc_op_table31[0x2eb] = drc_mullw; + drc_op_table31[0x0f2] = drc_mtsrin; + drc_op_table31[0x0f6] = drc_dcbtst; + drc_op_table31[0x0f7] = drc_stbux; + drc_op_table31[0x10a] = drc_add; + drc_op_table31[0x30a] = drc_add; + drc_op_table31[0x116] = drc_dcbt; + drc_op_table31[0x117] = drc_lhzx; + drc_op_table31[0x11c] = drc_eqv; + drc_op_table31[0x132] = drc_tlbie; + drc_op_table31[0x136] = drc_eciwx; + drc_op_table31[0x137] = drc_lhzux; + drc_op_table31[0x13c] = drc_xor; + drc_op_table31[0x153] = drc_mfspr; + drc_op_table31[0x157] = drc_lhax; + drc_op_table31[0x172] = drc_tlbia; + drc_op_table31[0x173] = drc_mftb; + drc_op_table31[0x177] = drc_lhaux; + drc_op_table31[0x197] = drc_sthx; + drc_op_table31[0x19c] = drc_orc; + drc_op_table31[0x1b6] = drc_ecowx; + drc_op_table31[0x1b7] = drc_sthux; + drc_op_table31[0x1bc] = drc_or; + drc_op_table31[0x1cb] = drc_divwu; + drc_op_table31[0x3cb] = drc_divwu; + drc_op_table31[0x1d3] = drc_mtspr; + drc_op_table31[0x1d6] = drc_dcbi; + drc_op_table31[0x1dc] = drc_nand; + drc_op_table31[0x1eb] = drc_divw; + drc_op_table31[0x3eb] = drc_divw; + drc_op_table31[0x200] = drc_mcrxr; + drc_op_table31[0x215] = drc_lswx; + drc_op_table31[0x216] = drc_lwbrx; + drc_op_table31[0x217] = drc_lfsx; + drc_op_table31[0x218] = drc_srw; + drc_op_table31[0x236] = drc_tlbsync; + drc_op_table31[0x237] = drc_lfsux; + drc_op_table31[0x253] = drc_mfsr; + drc_op_table31[0x255] = drc_lswi; + drc_op_table31[0x256] = drc_sync; + drc_op_table31[0x257] = drc_lfdx; + drc_op_table31[0x277] = drc_lfdux; + drc_op_table31[0x293] = drc_mfsrin; + drc_op_table31[0x295] = drc_stswx; + drc_op_table31[0x296] = drc_stwbrx; + drc_op_table31[0x297] = drc_stfsx; + drc_op_table31[0x2b7] = drc_stfsux; + drc_op_table31[0x2d5] = drc_stswi; + drc_op_table31[0x2d7] = drc_stfdx; + drc_op_table31[0x2f6] = drc_dcba; + drc_op_table31[0x2f7] = drc_stfdux; + drc_op_table31[0x316] = drc_lhbrx; + drc_op_table31[0x318] = drc_sraw; + drc_op_table31[0x338] = drc_srawi; + drc_op_table31[0x356] = drc_eieio; + drc_op_table31[0x396] = drc_sthbrx; + drc_op_table31[0x39a] = drc_extsh; + drc_op_table31[0x3ba] = drc_extsb; + drc_op_table31[0x3d6] = drc_icbi; + drc_op_table31[0x3d7] = drc_stfiwx; + drc_op_table31[0x3f6] = drc_dcbz; + + drc_op_table59[0x012] = drc_fdivs; + drc_op_table59[0x014] = drc_fsubs; + drc_op_table59[0x015] = drc_fadds; + drc_op_table59[0x016] = drc_fsqrts; + drc_op_table59[0x018] = drc_fres; + for (i=0; i < 32; i++) + { + drc_op_table59[(i << 5) | 0x019] = drc_fmuls; + drc_op_table59[(i << 5) | 0x01c] = drc_fmsubs; + drc_op_table59[(i << 5) | 0x01d] = drc_fmadds; + drc_op_table59[(i << 5) | 0x01e] = drc_fnmsubs; + drc_op_table59[(i << 5) | 0x01f] = drc_fnmadds; + } + + drc_op_table63[0x000] = drc_fcmpu; + drc_op_table63[0x00c] = drc_frsp; + drc_op_table63[0x00e] = drc_fctiw; + drc_op_table63[0x00f] = drc_fctiwz; + drc_op_table63[0x012] = drc_fdiv; + drc_op_table63[0x014] = drc_fsub; + drc_op_table63[0x015] = drc_fadd; + drc_op_table63[0x016] = drc_fsqrt; + drc_op_table63[0x01a] = drc_frsqrte; + drc_op_table63[0x020] = drc_fcmpo; + drc_op_table63[0x026] = drc_mtfsb1; + drc_op_table63[0x028] = drc_fneg; + drc_op_table63[0x040] = drc_mcrfs; + drc_op_table63[0x046] = drc_mtfsb0; + drc_op_table63[0x048] = drc_fmr; + drc_op_table63[0x086] = drc_mtfsfi; + drc_op_table63[0x088] = drc_fnabs; + drc_op_table63[0x108] = drc_fabs; + drc_op_table63[0x247] = drc_mffs; + drc_op_table63[0x2c7] = drc_mtfsf; + for (i=0; i < 32; i++) + { + drc_op_table63[(i << 5) | 0x017] = drc_fsel; + drc_op_table63[(i << 5) | 0x019] = drc_fmul; + drc_op_table63[(i << 5) | 0x01c] = drc_fmsub; + drc_op_table63[(i << 5) | 0x01d] = drc_fmadd; + drc_op_table63[(i << 5) | 0x01e] = drc_fnmsub; + drc_op_table63[(i << 5) | 0x01f] = drc_fnmadd; + } + + drccore_init(); +} + +void ppc_init(const PPC_CONFIG *config) +{ + int pll_config = 0; + float multiplier; + int i, j; + + /* Calculate rotate mask table */ + for( i=0; i < 32; i++ ) { + for( j=0; j < 32; j++ ) { + UINT32 mask; + int mb = i; + int me = j; + mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); + if( mb > me ) + mask = ~mask; + + ppc_rotate_mask[i][j] = mask; + } + } + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + ppc.pvr = config->pvr; + + multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + + (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); + + switch(config->pvr) + { + case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; + case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; + case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; + default: break; + } + + ppc_dec_divider = (int)(multiplier * 2); + + if (pll_config == -1) + { + error("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); + } + + ppc.hid1 = pll_config << 28; + + init_ppc_drc(); +} + +void ppc_shutdown(void) +{ + drccore_shutdown(); +} + +void ppc_exception(int exception) +{ + switch (exception) + { + case EXCEPTION_IRQ: /* External Interrupt */ + { + if( ppc_get_msr() & MSR_EE ) + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.pc = 0xfff00000 | 0x0500; + else + ppc.pc = 0x00000000 | 0x0500; + + ppc.interrupt_pending &= ~0x1; + ppc_change_pc(ppc.pc); + } + break; + } + + case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */ + { + if (ppc_get_msr() & MSR_EE) + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.pc = 0xfff00000 | 0x0900; + else + ppc.pc = 0x00000000 | 0x0900; + + ppc.interrupt_pending &= ~0x2; + ppc_change_pc(ppc.pc); + } + break; + } + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */ + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.pc = 0xfff00000 | 0x0700; + else + ppc.pc = 0x00000000 | 0x0700; + ppc_change_pc(ppc.pc); + } + break; + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = (msr & 0xff73); + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.pc = 0xfff00000 | 0x0c00; + else + ppc.pc = 0x00000000 | 0x0c00; + ppc_change_pc(ppc.pc); + } + break; + + default: + error("ppc: Unhandled exception %d", exception); + break; + } +} + +void ppc_set_irq_line(int irqline) +{ + ppc.interrupt_pending |= 0x1; + + ppc_stolen_cycles += ppc_icount; + ppc_icount = 0; +} + +UINT32 ppc_get_pc(void) +{ + return ppc.pc; +} + +void ppc_set_fetch(PPC_FETCH_REGION * fetch) +{ + ppc.fetch = fetch; +} + +void ppc_reset(void) +{ + ppc.pc = ppc.npc = 0xfff00100; + + ppc_set_msr(0x40); + ppc_change_pc(ppc.pc); + + ppc.hid0 = 1; + + ppc.interrupt_pending = 0; + + drccore_reset(); +} + +void ppc_check_interrupts(void) +{ + if (ppc.msr & MSR_EE) + { + if (ppc.interrupt_pending & 0x1) + { + ppc_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc_exception(EXCEPTION_DECREMENTER); + } + } +} + +int ppc_execute(int cycles) +{ + int run_cycles; + int cumulative_cycles; + int cycles_left; + UINT32 opcode; + + /* + ppc_icount = cycles; + ppc_tb_base_icount = cycles; + ppc_dec_base_icount = cycles + ppc.dec_frac; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - (cycles / (bus_freq_multiplier * 2))) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ((cycles / (bus_freq_multiplier * 2)) - DEC) * 4; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + run_cycles = ppc_icount; + ppc_icount = run_cycles / 2; + + ppc_change_pc(ppc.pc); + ppc_check_interrupts(); + drccore_execute(); + + ppc_icount = run_cycles / 2; + ppc.interrupt_pending |= 2; + ppc_change_pc(ppc.pc); + ppc_check_interrupts(); + drccore_execute(); + */ + + cumulative_cycles = 0; + cycles_left = cycles; + while (cumulative_cycles < cycles) + { + int dec_count; + int real_cycles; + int target_cycles; + ppc_stolen_cycles = 0; + + ppc_decrementer_exception_scheduled = 0; + + //ppc_change_pc(ppc.pc); + ppc_check_interrupts(); + + //ppc_tb_base_icount = cycles_left; + //ppc_dec_base_icount = cycles_left + ppc.dec_frac; + + // check if decrementer exception occurs during execution + dec_count = CYCLES_TO_DEC(cycles_left); + if ((UINT32)(DEC - dec_count) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = DEC_TO_CYCLES((dec_count - DEC)); + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + if (ppc_dec_trigger_cycle == cycles_left) + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + if (ppc_dec_trigger_cycle != 0x7fffffff) + { + target_cycles = ppc_icount = cycles_left - ppc_dec_trigger_cycle; + ppc_decrementer_exception_scheduled = 1; + } + else + { + target_cycles = ppc_icount = cycles_left; + ppc_decrementer_exception_scheduled = 0; + } + + ppc_tb_base_icount = ppc_icount; + ppc_dec_base_icount = ppc_icount + ppc.dec_frac; + + drccore_execute(); + if (ppc_decrementer_exception_scheduled) + { + ppc.interrupt_pending |= 2; + //ppc_change_pc(ppc.pc); + //ppc_check_interrupts(); + } + + real_cycles = (target_cycles - ppc_stolen_cycles) - ppc_icount; + cycles_left -= real_cycles; + cumulative_cycles += real_cycles; + +// printf("run for %d cycles, stolen cycles %d, trigger cycle %d\n", real_cycles, ppc_stolen_cycles, ppc_dec_trigger_cycle); + + { + int tb_cycles = (ppc_tb_base_icount) - ppc_stolen_cycles; + int dec_cycles = (ppc_dec_base_icount) - ppc_stolen_cycles; + + // update timebase + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + ppc.tb += ((tb_cycles) / TB_DIVIDER); + + // update decrementer + ppc.dec_frac = ((dec_cycles) % (bus_freq_multiplier * 2)); + DEC -= CYCLES_TO_DEC(dec_cycles); + } + } + + /* + // update timebase + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); + + // update decrementer + ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2)); + DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); + */ + + /* + { + char string1[200]; + char string2[200]; + opcode = BSWAP32(*ppc.op); + DisassemblePowerPC(opcode, ppc.pc, string1, string2, TRUE); + printf("%08X: %s %s\n", ppc.pc, string1, string2); + } + */ + + return cycles - ppc_icount; +} + + + + +static void **pc_lookup; +static void **pc_ram_lookup; +static void **pc_rom_lookup; +static void **pc_dummy_lookup; + +#define PC_LOOKUP_SIZE 0x200 // 9 top bits of address +#define PC_LOOKUP_SIZE_SUB 0x200000 // 23 bits - 2 unused LSB bits + +#define PC_LOOKUP_SHIFT 23 // how much to shift address to index main lookup + +static void (* drc_entry_point)(void); +static void (* drc_exit_point)(void); +static void (* drc_compiler_point)(void); +static void (* drc_invalid_area_point)(void); +static void ( *drc_check_interrupts)(void); +static void (* drc_irq_exception)(void); +static void (* drc_decrementer_exception)(void); + +void **drccore_get_lookup_ptr(UINT32 pc) +{ + switch (pc >> PC_LOOKUP_SHIFT) + { + case 0x000: return &pc_ram_lookup[(pc & 0x7fffff) / 4]; + case 0x1ff: return &pc_rom_lookup[(pc & 0x7fffff) / 4]; + default: return &pc_dummy_lookup[(pc & 0x7fffff) / 4]; + } +} + +void drccore_insert_dispatcher(void) +{ + gen(MOVMR, REG_ECX, (UINT32)&ppc.pc); + gen(MOV, REG_EAX, REG_ECX); + gen(SHRI, REG_EAX, PC_LOOKUP_SHIFT); + gen_mov_dprs_to_reg(REG_EAX, (UINT32)pc_lookup, REG_EAX, 4); + gen(ANDI, REG_ECX, (PC_LOOKUP_SIZE_SUB - 1) << 2); + gen_jmp_rpr(REG_EAX, REG_ECX); +} + +static void out_of_cycles_sanity_check(void) +{ + printf("out of cycles sanity check\n"); +} + +void drccore_insert_cycle_check(int cycles, UINT32 pc) +{ + JUMP_TARGET timeslice_not_expired; + JUMP_TARGET no_decrementer_check; + JUMP_TARGET no_decrementer_exception; + JUMP_TARGET no_interrupts; + JUMP_TARGET interrupts_not_enabled; + init_jmp_target(×lice_not_expired); + init_jmp_target(&no_decrementer_check); + init_jmp_target(&no_decrementer_exception); + init_jmp_target(&no_interrupts); + init_jmp_target(&interrupts_not_enabled); + + + //gen(SUBIM, (UINT32)&ppc_icount, cycles); + + // AAAAAARGH this is complex :-/ + + /*gen(MOVMR, REG_EAX, (UINT32)&ppc_icount); + gen(CMPIM, (UINT32)&ppc_dec_trigger_cycle, 0x7fffffff); + gen_jmp(JNZ, &no_decrementer_check); + + gen(MOVMR, REG_EDX, (UINT32)&ppc_dec_trigger_cycle); + gen(CMP, REG_EDX, REG_EAX); + gen_jmp(JNS, &no_decrementer_exception); + + gen(ORIM, (UINT32)&ppc.interrupt_pending, 0x2); + gen_jmp_target(&no_decrementer_exception); + + gen_jmp_target(&no_decrementer_check); + + + + gen(CMPIM, (UINT32)&ppc.interrupt_pending, 0); + gen_jmp(JZ, &no_interrupts); + + gen(MOVMR, REG_EDX, (UINT32)&ppc.msr); + gen(TESTI, REG_EDX, MSR_EE); + gen_jmp(JZ, &interrupts_not_enabled); + gen(MOVIM, (UINT32)&ppc.pc, pc); + gen(JMPI, (UINT32)drc_check_interrupts, 0); + + gen_jmp_target(&interrupts_not_enabled); + + gen_jmp_target(&no_interrupts); + + gen(CMPI, REG_EAX, 0); + */ + + gen(CMPIM, (UINT32)&ppc_icount, 0); + + gen_jmp(JNS, ×lice_not_expired); // continue if cycles >= 0 + gen(MOVIM, (UINT32)&ppc.pc, pc); + gen(JMPI, (UINT32)drc_exit_point, 0); + + gen_jmp_target(×lice_not_expired); +} + +static void sanity_check(UINT32 value) +{ + printf("ppc_sanity_check: %08X, cycles = %d\n", value, ppc_icount); + //printf("CTR = %08X, CR0 = %01X, CR1 = %01X\n", ppc.ctr, ppc.cr[0], ppc.cr[1]); +} + +void drccore_insert_sanity_check(UINT32 value) +{ + //gen(PUSHI, value, 0); + //gen(CALLI, (UINT32)&sanity_check, 0); + //gen(ADDI, REG_ESP, 4); +} + +static UINT32 entry_point_stackptr; +static void exit_point_sanity_check(UINT32 stackptr) +{ + printf("exit point sanity check: current ESP %08X, start %08X\n", stackptr, entry_point_stackptr); +} + +static void check_irqs_sanity_check(void) +{ + printf("check IRQs sanity check\n"); +} + +static void exception_sanity_check(void) +{ + printf("exception sanity check\n"); +} + +static void drccore_insert_check_interrupts(void) +{ + JUMP_TARGET interrupt_not_irq; + init_jmp_target(&interrupt_not_irq); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.interrupt_pending); + gen(TESTI, REG_EAX, 0x1); + gen_jmp(JZ, &interrupt_not_irq); + // IRQ + gen(MOVMR, REG_EDX, (UINT32)&ppc.pc); + gen(MOVRM, (UINT32)&ppc.srr0, REG_EDX); + gen(JMPM, (UINT32)&drc_irq_exception, 0); + + gen_jmp_target(&interrupt_not_irq); + // decrementer + gen(MOVMR, REG_EDX, (UINT32)&ppc.pc); + gen(MOVRM, (UINT32)&ppc.srr0, REG_EDX); + gen(JMPM, (UINT32)&drc_decrementer_exception, 0); +} + +static void drccore_insert_exception_generator(int exception) +{ + JUMP_TARGET clear_le, exception_base_0; + init_jmp_target(&clear_le); + init_jmp_target(&exception_base_0); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.msr); + gen(ANDI, REG_EAX, 0xff73); + gen(MOVRM, (UINT32)&ppc.srr1, REG_EAX); + + // Clear POW, EE, PR, FP, FE0, SE, BE, FE1, IR, DR, RI + gen(ANDI, REG_EAX, ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI)); + + // Set LE to ILE + gen(ANDI, REG_EAX, ~MSR_LE); // clear LE first + gen(TESTI, REG_EAX, MSR_ILE); + gen_jmp(JZ, &clear_le); // if Z == 0, bit = 1 + gen(ORI, REG_EAX, MSR_LE); // set LE + gen_jmp_target(&clear_le); + + gen(MOVRM, (UINT32)&ppc.msr, REG_EAX); + + switch (exception) + { + case EXCEPTION_IRQ: + { + gen(MOVI, REG_EDI, 0x00000500); // exception vector + gen(TESTI, REG_EAX, MSR_IP); + gen_jmp(JZ, &exception_base_0); // if Z == 1, bit = 0 means base == 0x00000000 + gen(ORI, REG_EDI, 0xfff00000); + gen_jmp_target(&exception_base_0); + + gen(ANDIM, (UINT32)&ppc.interrupt_pending, ~0x1); // clear decrementer exception + + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + break; + } + case EXCEPTION_DECREMENTER: + { + gen(MOVI, REG_EDI, 0x00000900); // exception vector + gen(TESTI, REG_EAX, MSR_IP); + gen_jmp(JZ, &exception_base_0); // if Z == 1, bit = 0 means base == 0x00000000 + gen(ORI, REG_EDI, 0xfff00000); + gen_jmp_target(&exception_base_0); + + gen(ANDIM, (UINT32)&ppc.interrupt_pending, ~0x2); // clear decrementer exception + + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + break; + } + } +} + +void drccore_init(void) +{ + int i; + + init_genx86(); + + pc_lookup = malloc(sizeof(void*) * PC_LOOKUP_SIZE); + + // these lookups are the only ones we need runtime for Model 3 + pc_ram_lookup = malloc(sizeof(void*) * PC_LOOKUP_SIZE_SUB); + pc_rom_lookup = malloc(sizeof(void*) * PC_LOOKUP_SIZE_SUB); + + // this table will catch all the possible jumps outside ram/rom + pc_dummy_lookup = malloc(sizeof(void*) * PC_LOOKUP_SIZE_SUB); + + // initialize main lookup + for (i=0; i < PC_LOOKUP_SIZE; i++) + { + pc_lookup[i] = pc_dummy_lookup; + } + + // we know that rom is at location 0xff800000 - 0xffffffff + pc_lookup[0x1ff] = pc_rom_lookup; + // we know that ram is at location 0x00000000 - 0x007fffff + pc_lookup[0x000] = pc_ram_lookup; +} + +void drccore_shutdown(void) +{ + shutdown_genx86(); +} + +void drccore_reset(void) +{ + int i; + + gen_reset_cache(); + + // insert dynarec entry point + drc_entry_point = (void*)gen_get_cache_pos(); + gen(PUSHAD, 0, 0); + drccore_insert_dispatcher(); + + // insert dynarec exit point + drc_exit_point = (void*)gen_get_cache_pos(); + gen(POPAD, 0, 0); + gen(RET, 0, 0); + + // insert dynarec compiler point + drc_compiler_point = (void*)gen_get_cache_pos(); + gen(CALLI, (UINT32)drc_recompile_block, 0); + drccore_insert_dispatcher(); + + // insert dynarec invalid area point + drc_invalid_area_point = (void*)gen_get_cache_pos(); + gen(CALLI, (UINT32)drc_invalid_area, 0); + + // insert check interrupts + drc_check_interrupts = (void*)gen_get_cache_pos(); + drccore_insert_check_interrupts(); + + // insert irq exception generator + drc_irq_exception = (void*)gen_get_cache_pos(); + drccore_insert_exception_generator(EXCEPTION_IRQ); + + // insert decrementer exception generator + drc_decrementer_exception = (void*)gen_get_cache_pos(); + drccore_insert_exception_generator(EXCEPTION_DECREMENTER); + + // initialize sub lookups + for (i=0; i < PC_LOOKUP_SIZE_SUB; i++) + { + // point valid areas to recompile handler + pc_ram_lookup[i] = (void*)drc_compiler_point; + pc_rom_lookup[i] = (void*)drc_compiler_point; + + // point invalid areas to invalid area handler + pc_dummy_lookup[i] = (void*)drc_invalid_area; + } +} + +void drccore_execute(void) +{ + drc_entry_point(); +} \ No newline at end of file diff --git a/ppc_drc/ppc_drc.h b/ppc_drc/ppc_drc.h new file mode 100644 index 0000000..e69de29 diff --git a/ppc_drc/ppc_drc_ops.c b/ppc_drc/ppc_drc_ops.c new file mode 100644 index 0000000..00b11d3 --- /dev/null +++ b/ppc_drc/ppc_drc_ops.c @@ -0,0 +1,4123 @@ +static UINT32 drc_invalid_area(void) +{ + error("drc_invalid_area: PC: %08X", ppc.pc); +} + +#define PPCREG(x) ((UINT32)&ppc.r[x]) + +static int block_cycle_count; +static UINT32 block_start_pc; + +static UINT32 drc_pc; + +static UINT32 drc_recompile_block(void) +{ + UINT32 res = 0; + + block_start_pc = ppc.pc; + drc_pc = ppc.pc; + +// printf("Recompile block start: %08X\n", drc_pc); + + block_cycle_count = 0; + do + { + void **lookup; + UINT32 op; + + // point the PC lookup to this instruction + lookup = drccore_get_lookup_ptr(drc_pc); + + *lookup = gen_get_cache_pos(); + + drccore_insert_sanity_check(drc_pc); + //drccore_insert_cycle_check(1, drc_pc); + + gen(SUBIM, (UINT32)&ppc_icount, 1); + + op = READ32(drc_pc); + switch (op >> 26) + { + case 19: res = drc_op_table19[(op >> 1) & 0x3ff](op); break; + case 31: res = drc_op_table31[(op >> 1) & 0x3ff](op); break; + case 59: res = drc_op_table59[(op >> 1) & 0x3ff](op); break; + case 63: res = drc_op_table63[(op >> 1) & 0x3ff](op); break; + default: res = drc_op_table[op >> 26](op); break; + } + + block_cycle_count++; + drc_pc += 4; + } while (res == 0); + +// printf("Recompile block end: %08X\n", drc_pc); +} + +static UINT32 cr_flag_eq = 0x02; +static UINT32 cr_flag_lt = 0x08; +static UINT32 cr_flag_gt = 0x04; + +static void insert_set_cr0(int reg) +{ + gen(CMPI, reg, 0); + gen(CMOVZMR, REG_EAX, (UINT32)&cr_flag_eq); + gen(CMOVLMR, REG_EAX, (UINT32)&cr_flag_lt); + gen(CMOVGMR, REG_EAX, (UINT32)&cr_flag_gt); + gen(BTIM, (UINT32)&ppc.xer, 31); + gen(ADCI, REG_EAX, 0); + gen(MOVR8M8, (UINT32)&ppc.cr[0], REG_AL); +} + + + +static UINT32 drc_add(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADD + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addx), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_addc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addcx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addcx), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(ANDI, REG_EBX, ~XER_CA); // clear carry + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RT), REG_EDX); + gen(SETCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_adde(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDE + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addex), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addex), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(BTRI, REG_EBX, 29); // move CA bit to carry and clear it + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADCMR, REG_EDX, PPCREG(RB)); + gen(SETCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_addi(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addi), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (RA == 0) + { + gen(MOVIM, PPCREG(RT), SIMM16); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RT), REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_addic(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDIC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addic), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(ANDI, REG_EBX, ~XER_CA); + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RT), REG_EDX); + gen(SETCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + +#endif + return 0; +} + +static UINT32 drc_addic_rc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDIC_RC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addic_rc), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(ANDI, REG_EBX, ~XER_CA); + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RT), REG_EDX); + gen(SETCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + + insert_set_cr0(REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_addis(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDIS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addis), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (RA == 0) + { + gen(MOVIM, PPCREG(RT), UIMM16 << 16); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, UIMM16 << 16); + gen(MOVRM, PPCREG(RT), REG_EDX); + } + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_addme(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS || DONT_COMPILE_ADDME + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addmex), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addmex), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(BTRI, REG_EBX, 29); // move CA bit to carry and clear it + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADCI, REG_EDX, -1); + gen(SETCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_addze(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ADDZE + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addzex), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_addzex), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(BTRI, REG_EBX, 29); // move CA bit to carry and clear it + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADCI, REG_EDX, 0); + gen(SETCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_and(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_AND + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_andx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ANDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_andc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ANDC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_andcx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVMR, REG_EAX, PPCREG(RB)); + gen(NOT, REG_EAX, 0); + gen(AND, REG_EDX, REG_EAX); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_andi_rc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ANDI_RC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_andi_rc), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ANDI, REG_EDX, UIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + + insert_set_cr0(REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_andis_rc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ANDIS_RC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_andis_rc), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ANDI, REG_EDX, UIMM16 << 16); + gen(MOVRM, PPCREG(RA), REG_EDX); + + insert_set_cr0(REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_b(UINT32 op) +{ + void *jmpptr; + UINT32 newpc; + INT32 li = op & 0x3fffffc; + + drccore_insert_cycle_check(block_cycle_count, drc_pc); + + if (li & 0x2000000) + { + li |= 0xfc000000; + } + + if (AABIT) + { + newpc = li; + } + else + { + newpc = drc_pc + li; + } + + if (LKBIT) + { + gen(MOVIM, (UINT32)&ppc.lr, drc_pc+4); + } + + //drccore_insert_cycle_check(block_cycle_count); + + jmpptr = drccore_get_lookup_ptr(newpc); + gen(MOVIM, (UINT32)&ppc.pc, newpc); + gen(JMPM, (UINT32)jmpptr, 0); + + return DRC_END_BLOCK; +} + +static UINT32 drc_bc(UINT32 op) +{ + void *jmpptr; + UINT32 newpc; + int bo = BO; + int bi = BI; + int gen_jmp1 = 0; + int gen_jmp2 = 0; + JUMP_TARGET skip_branch1, skip_branch2; + init_jmp_target(&skip_branch1); + init_jmp_target(&skip_branch2); + + if (AABIT) + { + newpc = SIMM16 & ~0x3; + } + else + { + newpc = drc_pc + (SIMM16 & ~0x3); + } + + if (newpc >= block_start_pc && newpc < drc_pc) + { + // jumped inside the current block + // probably a long loop, so cycle length is the length of the loop + drccore_insert_cycle_check(abs((newpc-drc_pc)), drc_pc); + } + else + { + drccore_insert_cycle_check(block_cycle_count, drc_pc); + } + + if (LKBIT) + { + gen(MOVIM, (UINT32)&ppc.lr, drc_pc+4); + } + + // if BO[2] == 0, update CTR and check CTR condition + if ((bo & 0x4) == 0) + { + gen_jmp1 = 1; + gen(SUBIM, (UINT32)&ppc.ctr, 1); + + // if BO[1] == 0, branch if CTR != 0 + if ((bo & 0x2) == 0) + { + gen_jmp(JZ, &skip_branch1); + } + else + { + gen_jmp(JNZ, &skip_branch1); + } + } + + // if BO[0] == 0, check condition + if ((bo & 0x10) == 0) + { + gen_jmp2 = 1; + gen(MOVZ_M8R32, REG_EAX, &ppc.cr[bi/4]); + gen(TESTI, REG_EAX, 1 << (3 - ((bi) & 0x3))); + + // if BO[3] == 0, branch if condition == FALSE (bit zero) + if ((bo & 0x8) == 0) + { + gen_jmp(JNZ, &skip_branch2); + } + // if BO[3] == 1, branch if condition == TRUE (bit not zero) + else + { + gen_jmp(JZ, &skip_branch2); + } + } + + // take the branch + jmpptr = drccore_get_lookup_ptr(newpc); + gen(MOVIM, (UINT32)&ppc.pc, newpc); + gen(JMPM, (UINT32)jmpptr, 0); + + // skip the branch + if (gen_jmp1) + { + gen_jmp_target(&skip_branch1); + } + if (gen_jmp2) + { + gen_jmp_target(&skip_branch2); + } + + return 0; +} + +static UINT32 drc_bcctr(UINT32 op) +{ + UINT32 newpc; + int bo = BO; + int bi = BI; + int gen_jmp1 = 0; + int gen_jmp2 = 0; + JUMP_TARGET skip_branch1, skip_branch2; + init_jmp_target(&skip_branch1); + init_jmp_target(&skip_branch2); + + drccore_insert_cycle_check(block_cycle_count, drc_pc); + + if (LKBIT) + { + gen(MOVIM, (UINT32)&ppc.lr, drc_pc+4); + } + + if (bo == 20) // Condition is always true, basic block ends here + { + gen(MOVMR, REG_EDI, (UINT32)&ppc.ctr); + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + return DRC_END_BLOCK; + } + else + { + // if BO[2] == 0, update CTR and check CTR condition + if ((bo & 0x4) == 0) + { + gen_jmp1 = 1; + gen(SUBIM, (UINT32)&ppc.ctr, 1); + + // if BO[1] == 0, branch if CTR != 0 + if ((bo & 0x2) == 0) + { + gen_jmp(JZ, &skip_branch1); + } + else + { + gen_jmp(JNZ, &skip_branch1); + } + } + + // if BO[0] == 0, check condition + if ((bo & 0x10) == 0) + { + gen_jmp2 = 1; + gen(MOVZ_M8R32, REG_EAX, &ppc.cr[bi/4]); + gen(TESTI, REG_EAX, 1 << (3 - ((bi) & 0x3))); + + // if BO[3] == 0, branch if condition == FALSE (bit zero) + if ((bo & 0x8) == 0) + { + gen_jmp(JNZ, &skip_branch2); + } + // if BO[3] == 1, branch if condition == TRUE (bit not zero) + else + { + gen_jmp(JZ, &skip_branch2); + } + } + + // take the branch + gen(MOVMR, REG_EDI, (UINT32)&ppc.ctr); + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + + // skip the branch + if (gen_jmp1) + { + gen_jmp_target(&skip_branch1); + } + if (gen_jmp2) + { + gen_jmp_target(&skip_branch2); + } + } + return 0; +} + +static UINT32 drc_bclr(UINT32 op) +{ + UINT32 newpc; + int bo = BO; + int bi = BI; + int gen_jmp1 = 0; + int gen_jmp2 = 0; + JUMP_TARGET skip_branch1, skip_branch2; + init_jmp_target(&skip_branch1); + init_jmp_target(&skip_branch2); + + drccore_insert_cycle_check(block_cycle_count, drc_pc); + + gen(MOVMR, REG_EDI, (UINT32)&ppc.lr); + + if (LKBIT) + { + gen(MOVIM, (UINT32)&ppc.lr, drc_pc+4); + } + + if (bo == 20) // Condition is always true, basic block ends here + { + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + return DRC_END_BLOCK; + } + else + { + // if BO[2] == 0, update CTR and check CTR condition + if ((bo & 0x4) == 0) + { + gen_jmp1 = 1; + gen(SUBIM, (UINT32)&ppc.ctr, 1); + + // if BO[1] == 0, branch if CTR != 0 + if ((bo & 0x2) == 0) + { + gen_jmp(JZ, &skip_branch1); + } + else + { + gen_jmp(JNZ, &skip_branch1); + } + } + + // if BO[0] == 0, check condition + if ((bo & 0x10) == 0) + { + gen_jmp2 = 1; + gen(MOVZ_M8R32, REG_EAX, &ppc.cr[bi/4]); + gen(TESTI, REG_EAX, 1 << (3 - ((bi) & 0x3))); + + // if BO[3] == 0, branch if condition == FALSE (bit zero) + if ((bo & 0x8) == 0) + { + gen_jmp(JNZ, &skip_branch2); + } + // if BO[3] == 1, branch if condition == TRUE (bit not zero) + else + { + gen_jmp(JZ, &skip_branch2); + } + } + + // take the branch + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + + // skip the branch + if (gen_jmp1) + { + gen_jmp_target(&skip_branch1); + } + if (gen_jmp2) + { + gen_jmp_target(&skip_branch2); + } + } + return 0; +} + +static UINT32 drc_cmp(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_CMP + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_cmp), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(CMPMR, REG_EDX, PPCREG(RB)); + gen(CMOVZMR, REG_EAX, (UINT32)&cr_flag_eq); + gen(CMOVLMR, REG_EAX, (UINT32)&cr_flag_lt); + gen(CMOVGMR, REG_EAX, (UINT32)&cr_flag_gt); + gen(BTIM, (UINT32)&ppc.xer, 31); + gen(ADCI, REG_EAX, 0); + gen(MOVR8M8, (UINT32)&ppc.cr[CRFD], REG_AL); + +#endif + return 0; +} + +static UINT32 drc_cmpi(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_CMPI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_cmpi), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(CMPI, REG_EDX, SIMM16); + gen(CMOVZMR, REG_EAX, (UINT32)&cr_flag_eq); + gen(CMOVLMR, REG_EAX, (UINT32)&cr_flag_lt); + gen(CMOVGMR, REG_EAX, (UINT32)&cr_flag_gt); + gen(BTIM, (UINT32)&ppc.xer, 31); + gen(ADCI, REG_EAX, 0); + gen(MOVR8M8, (UINT32)&ppc.cr[CRFD], REG_AL); + +#endif + return 0; +} + +static UINT32 drc_cmpl(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_CMPL + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_cmpl), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(CMPMR, REG_EDX, PPCREG(RB)); + gen(CMOVZMR, REG_EAX, (UINT32)&cr_flag_eq); + gen(CMOVBMR, REG_EAX, (UINT32)&cr_flag_lt); + gen(CMOVAMR, REG_EAX, (UINT32)&cr_flag_gt); + gen(BTIM, (UINT32)&ppc.xer, 31); + gen(ADCI, REG_EAX, 0); + gen(MOVR8M8, (UINT32)&ppc.cr[CRFD], REG_AL); + +#endif + return 0; +} + +static UINT32 drc_cmpli(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_CMPLI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_cmpli), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(CMPI, REG_EDX, SIMM16); + gen(CMOVZMR, REG_EAX, (UINT32)&cr_flag_eq); + gen(CMOVBMR, REG_EAX, (UINT32)&cr_flag_lt); + gen(CMOVAMR, REG_EAX, (UINT32)&cr_flag_gt); + gen(BTIM, (UINT32)&ppc.xer, 31); + gen(ADCI, REG_EAX, 0); + gen(MOVR8M8, (UINT32)&ppc.cr[CRFD], REG_AL); + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_cntlzw(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_cntlzw), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(XOR, REG_EBX, REG_EBX); + gen(MOVI, REG_EDX, 31); + gen(MOVMR, REG_EAX, PPCREG(RS)); + gen(BSR, REG_EAX, REG_EAX); + gen(SETZR8, REG_BL, 0); // if zero is set then source is 0. add zero bit to 31 -> so result is 32 + gen(SUB, REG_EDX, REG_EAX); + gen(ADD, REG_EDX, REG_EBX); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_crand(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_crand), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_crandc(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_crandc), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_creqv(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_creqv), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_crnand(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_crnand), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_crnor(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_crnor), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_cror(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_cror), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_crorc(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_crorc), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_crxor(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_crxor), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_dcbf(UINT32 op) +{ + return 0; +} + +static UINT32 drc_dcbi(UINT32 op) +{ + return 0; +} + +static UINT32 drc_dcbst(UINT32 op) +{ + return 0; +} + +static UINT32 drc_dcbt(UINT32 op) +{ + return 0; +} + +static UINT32 drc_dcbtst(UINT32 op) +{ + return 0; +} + +static UINT32 drc_dcbz(UINT32 op) +{ + return 0; +} + +static UINT32 drc_divw(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_divwx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_divwu(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_divwux), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_eieio(UINT32 op) +{ + return 0; +} + +// NOTE: not tested! +static UINT32 drc_eqv(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_eqvx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(XORMR, REG_EDX, PPCREG(RB)); + gen(NOT, REG_EDX, 0); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_extsb(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_EXTSB + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_extsbx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVS_R8R32, REG_EDX, REG_DL); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_extsh(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_EXTSH + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_extshx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVS_R16R32, REG_EDX, REG_DX); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_icbi(UINT32 op) +{ + return 0; +} + +static UINT32 drc_isync(UINT32 op) +{ + return 0; +} + +static UINT32 drc_lbz(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LBZ + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lbz), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(PUSH, REG_EDX, 0); + } + gen(CALLI, (UINT32)m3_ppc_read_8, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R8R32, REG_EAX, REG_AL); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lbzu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LBZU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lbzu), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_8, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R8R32, REG_EAX, REG_AL); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lbzux(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LBZUX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lbzux), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_8, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R8R32, REG_EAX, REG_AL); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lbzx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LBZX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lbzx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_8, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R8R32, REG_EAX, REG_AL); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lha(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LHA + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lha), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(PUSH, REG_EDX, 0); + } + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVS_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lhau(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LHAU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhau), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVS_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_lhaux(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhaux), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVS_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_lhax(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhax), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVS_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_lhbrx(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS || DONT_COMPILE_LHBRX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhbrx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(XCHGR8R8, REG_AL, REG_AH); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lhz(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LHZ + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhz), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(PUSH, REG_EDX, 0); + } + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lhzu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LHZU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhzu), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_lhzux(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhzux), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lhzx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LHZX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lhzx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_16, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVZ_R16R32, REG_EAX, REG_AX); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lmw(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lmw), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_lswi(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lswi), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_lswx(UINT32 op) +{ + error("PPCDRC: drc_lswx\n"); + return 0; +} + +static UINT32 drc_lwarx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lwarx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +// FIXME: why does the compiled version have a huge hit on performance? +static UINT32 drc_lwbrx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LWBRX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lwbrx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(BSWAP, REG_EAX, 0); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_lwz(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LWZ + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lwz), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + if (RA == 0) + { + UINT32 address = SIMM16; + if (address < 0x800000) + { + gen(MOVMR, REG_EAX, (UINT32)ram + address); + gen(BSWAP, REG_EAX, 0); + gen(MOVRM, PPCREG(RT), REG_EAX); + } + else + { + gen(PUSHI, SIMM16, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVRM, PPCREG(RT), REG_EAX); + } + } + else + { + JUMP_TARGET lwz_slow_path, lwz_end; + init_jmp_target(&lwz_slow_path); + init_jmp_target(&lwz_end); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lwz_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lwz_end); + // slow path + gen_jmp_target(&lwz_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lwz_end); + gen(MOVRM, PPCREG(RT), REG_EAX); + } +#else + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(PUSH, REG_EDX, 0); + } + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVRM, PPCREG(RT), REG_EAX); +#endif + +#endif + return 0; +} + +static UINT32 drc_lwzu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LWZU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lwzu), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + { + JUMP_TARGET lwzu_slow_path, lwzu_end; + init_jmp_target(&lwzu_slow_path); + init_jmp_target(&lwzu_end); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lwzu_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lwzu_end); + // slow path + gen_jmp_target(&lwzu_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lwzu_end); + gen(MOVRM, PPCREG(RT), REG_EAX); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVRM, PPCREG(RT), REG_EAX); +#endif + +#endif + return 0; +} + +static UINT32 drc_lwzux(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LWZUX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lwzux), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + { + JUMP_TARGET lwzux_slow_path, lwzux_end; + init_jmp_target(&lwzux_slow_path); + init_jmp_target(&lwzux_end); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lwzux_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lwzux_end); + // slow path + gen_jmp_target(&lwzux_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lwzux_end); + gen(MOVRM, PPCREG(RT), REG_EAX); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVRM, PPCREG(RT), REG_EAX); +#endif + +#endif + return 0; +} + +static UINT32 drc_lwzx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LWZX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lwzx), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + { + JUMP_TARGET lwzx_slow_path, lwzx_end; + init_jmp_target(&lwzx_slow_path); + init_jmp_target(&lwzx_end); + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lwzx_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lwzx_end); + // slow path + gen_jmp_target(&lwzx_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lwzx_end); + gen(MOVRM, PPCREG(RT), REG_EAX); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVRM, PPCREG(RT), REG_EAX); +#endif + +#endif + return 0; +} + +static UINT32 drc_mcrf(UINT32 op) +{ +#if !COMPILE_OPS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mcrf), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVM8R8, REG_AL, (UINT32)&ppc.cr[RA >> 2]); + gen(MOVR8M8, (UINT32)&ppc.cr[RT >> 2], REG_AL); + +#endif + return 0; +} + +static UINT32 drc_mcrxr(UINT32 op) +{ + error("PPCDRC: drc mcrxr\n"); + return 0; +} + +static UINT32 drc_mfcr(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mfcr), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mfmsr(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mfmsr), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mfspr(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_MFSPR + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mfspr), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (SPR == SPR_LR) + { + gen(MOVMR, REG_EAX, (UINT32)&ppc.lr); + } + else if (SPR == SPR_CTR) + { + gen(MOVMR, REG_EAX, (UINT32)&ppc.ctr); + } + else if (SPR == SPR_XER) + { + gen(MOVMR, REG_EAX, (UINT32)&ppc.xer); + } + else + { + // non-optimized cases + gen(PUSHI, SPR, 0); + gen(CALLI, (UINT32)ppc_get_spr, 0); + gen(ADDI, REG_ESP, 4); + } + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_mtcrf(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtcrf), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtmsr(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtmsr), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtspr(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_MTSPR + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtspr), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EAX, PPCREG(RS)); + if (SPR == SPR_LR) + { + gen(MOVRM, (UINT32)&ppc.lr, REG_EAX); + } + else if (SPR == SPR_CTR) + { + gen(MOVRM, (UINT32)&ppc.ctr, REG_EAX); + } + else if (SPR == SPR_XER) + { + gen(MOVRM, (UINT32)&ppc.xer, REG_EAX); + } + else + { + // non-optimized cases + gen(PUSH, REG_EAX, 0); + gen(PUSHI, SPR, 0); + gen(CALLI, (UINT32)ppc_set_spr, 0); + gen(ADDI, REG_ESP, 8); + } + +#endif + return 0; +} + +static UINT32 drc_mulhw(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_MULHW + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mulhwx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(MOVMR, REG_EBX, PPCREG(RB)); + gen(IMUL, REG_EBX, 0); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_mulhwu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_MULHWU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mulhwux), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(MOVMR, REG_EBX, PPCREG(RB)); + gen(MUL, REG_EBX, 0); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_mulli(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_MULLI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mulli), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(MOVI, REG_EBX, SIMM16); + gen(IMUL, REG_EBX, 0); + gen(MOVRM, PPCREG(RT), REG_EAX); + +#endif + return 0; +} + +static UINT32 drc_mullw(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_MULLW + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mullwx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mullwx), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(MOVMR, REG_EBX, PPCREG(RB)); + gen(MUL, REG_EBX, 0); + gen(MOVRM, PPCREG(RT), REG_EAX); + if (RCBIT) + { + insert_set_cr0(REG_EAX); + } + } + +#endif + return 0; +} + +static UINT32 drc_nand(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_NAND + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_nandx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ANDMR, REG_EDX, PPCREG(RB)); + gen(NOT, REG_EDX, 0); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_neg(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_NEG + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_negx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(NEG, REG_EDX, 0); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_nor(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_NOR + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_norx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ORMR, REG_EDX, PPCREG(RB)); + gen(NOT, REG_EDX, 0); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_or(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_OR + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_orx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ORMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_orc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ORC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_orcx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RB)); + gen(NOT, REG_EDX, 0); + gen(ORMR, REG_EDX, PPCREG(RS)); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_ori(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ORI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_ori), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ORI, REG_EDX, UIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_oris(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_ORIS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_oris), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ORI, REG_EDX, UIMM16 << 16); + gen(MOVRM, PPCREG(RA), REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_rfi(UINT32 op) +{ + gen(MOVMR, REG_EDX, (UINT32)&ppc.srr1); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)ppc_set_msr, 0); + gen(ADDI, REG_ESP, 4); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.srr0); + gen(MOVRM, (UINT32)&ppc.pc, REG_EAX); + + drccore_insert_dispatcher(); + + return DRC_END_BLOCK; +} + +static UINT32 drc_rlwimi(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_RLWIMI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_rlwimix), 0); + gen(ADDI, REG_ESP, 4); + +#else + + UINT32 mask = GET_ROTATE_MASK(MB, ME); + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ROLI, REG_EDX, SH); + gen(ANDI, REG_EDX, mask); + gen(ANDI, REG_EAX, ~mask); + gen(OR, REG_EDX, REG_EAX); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_rlwinm(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_RLWINM + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_rlwinmx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + UINT32 mask = GET_ROTATE_MASK(MB, ME); + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ROLI, REG_EDX, SH); + gen(ANDI, REG_EDX, mask); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_rlwnm(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_RLWNM + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_rlwnmx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + UINT32 mask = GET_ROTATE_MASK(MB, ME); + + gen(MOVMR, REG_ECX, PPCREG(RB)); + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ROLCL, REG_EDX, 0); + gen(ANDI, REG_EDX, mask); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_sc(UINT32 op) +{ + // generate exception + { + JUMP_TARGET clear_le, exception_base_0; + init_jmp_target(&clear_le); + init_jmp_target(&exception_base_0); + + gen(MOVIM, (UINT32)&ppc.srr0, drc_pc+4); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.msr); + gen(ANDI, REG_EAX, 0xff73); + gen(MOVRM, (UINT32)&ppc.srr1, REG_EAX); + + // Clear POW, EE, PR, FP, FE0, SE, BE, FE1, IR, DR, RI + gen(ANDI, REG_EAX, ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI)); + + // Set LE to ILE + gen(ANDI, REG_EAX, ~MSR_LE); // clear LE first + gen(TESTI, REG_EAX, MSR_ILE); + gen_jmp(JZ, &clear_le); // if Z == 0, bit = 1 + gen(ORI, REG_EAX, MSR_LE); // set LE + gen_jmp_target(&clear_le); + + gen(MOVRM, (UINT32)&ppc.msr, REG_EAX); + + gen(MOVI, REG_EDI, 0x00000c00); // exception vector + gen(TESTI, REG_EAX, MSR_IP); + gen_jmp(JZ, &exception_base_0); // if Z == 1, bit = 0 means base == 0x00000000 + gen(ORI, REG_EDI, 0xfff00000); + gen_jmp_target(&exception_base_0); + + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + } + + return 0; +} + +// FIXME: why does the compiled version slow things down? +static UINT32 drc_slw(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_SLW + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_slwx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + JUMP_TARGET slw_zero, slw_end; + init_jmp_target(&slw_zero); + init_jmp_target(&slw_end); + + gen(MOVMR, REG_ECX, PPCREG(RB)); + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ANDI, REG_ECX, 0x3f); + gen(CMPI, REG_ECX, 0x1f); + gen_jmp(JA, &slw_zero); + gen(SHLCL, REG_EDX, 0); + gen_jmp(JMP, &slw_end); + gen_jmp_target(&slw_zero); + gen(MOVI, REG_EDX, 0); + gen_jmp_target(&slw_end); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_sraw(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_srawx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_srawi(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_srawix), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +// FIXME: why does the compiled version slow things down? +static UINT32 drc_srw(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_SRW + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_srwx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + JUMP_TARGET srw_zero, srw_end; + init_jmp_target(&srw_zero); + init_jmp_target(&srw_end); + + gen(MOVMR, REG_ECX, PPCREG(RB)); + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(ANDI, REG_ECX, 0x3f); + gen(CMPI, REG_ECX, 0x1f); + gen_jmp(JA, &srw_zero); + gen(SHRCL, REG_EDX, 0); + gen_jmp(JMP, &srw_end); + gen_jmp_target(&srw_zero); + gen(MOVI, REG_EDX, 0); + gen_jmp_target(&srw_end); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_stb(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STB + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stb), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVZ_R8R32, REG_EDX, REG_DL); + gen(PUSH, REG_EDX, 0); + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(PUSH, REG_EAX, 0); + } + + gen(CALLI, (UINT32)m3_ppc_write_8, 0); + gen(ADDI, REG_ESP, 8); + +#endif + return 0; +} + +static UINT32 drc_stbu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STBU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stbu), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVZ_R8R32, REG_EDX, REG_DL); + gen(PUSH, REG_EDX, 0); + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(PUSH, REG_EAX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_8, 0); + gen(ADDI, REG_ESP, 8); + +#endif + return 0; +} + +static UINT32 drc_stbux(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STBUX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stbux), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVZ_R8R32, REG_EDX, REG_DL); + gen(PUSH, REG_EDX, 0); + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDMR, REG_EAX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(PUSH, REG_EAX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_8, 0); + gen(ADDI, REG_ESP, 8); + +#endif + return 0; +} + +static UINT32 drc_stbx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STBX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stbx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVZ_R8R32, REG_EDX, REG_DL); + gen(PUSH, REG_EDX, 0); + + gen(MOVMR, REG_EAX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EAX, PPCREG(RA)); + } + gen(PUSH, REG_EAX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_8, 0); + gen(ADDI, REG_ESP, 8); + +#endif + return 0; +} + +static UINT32 drc_sth(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STH + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_sth), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVZ_R16R32, REG_EDX, REG_DX); + gen(PUSH, REG_EDX, 0); + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(PUSH, REG_EAX, 0); + } + + gen(CALLI, (UINT32)m3_ppc_write_16, 0); + gen(ADDI, REG_ESP, 8); + +#endif + return 0; +} + +static UINT32 drc_sthbrx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_sthbrx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_sthu(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_sthu), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_sthux(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_sthux), 0); + gen(ADDI, REG_ESP, 4); + return 0; +} + +static UINT32 drc_sthx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_sthx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stmw(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stmw), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stswi(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stswi), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stswx(UINT32 op) +{ + error("PPCDRC: drc_stswx\n"); + return 0; +} + +static UINT32 drc_stw(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STW + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stw), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + if (RA == 0) + { + UINT32 address = SIMM16; + gen(MOVMR, REG_EDX, PPCREG(RS)); + if (address < 0x800000) + { + gen(BSWAP, REG_EDX, 0); + gen(MOVRM, (UINT32)ram + address, REG_EDX); + } + else + { + gen(PUSH, REG_EDX, 0); + gen(PUSHI, SIMM16, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + } + } + else + { + JUMP_TARGET stw_slow_path, stw_end; + init_jmp_target(&stw_slow_path); + init_jmp_target(&stw_end); + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stw_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stw_end); + // slow path + gen_jmp_target(&stw_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stw_end); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(PUSH, REG_EDX, 0); + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(PUSH, REG_EAX, 0); + } + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_stwbrx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stwbrx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stwcx_rc(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stwcx_rc), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stwu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STWU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stwu), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + { + JUMP_TARGET stwu_slow_path, stwu_end; + init_jmp_target(&stwu_slow_path); + init_jmp_target(&stwu_end); + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stwu_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stwu_end); + // slow path + gen_jmp_target(&stwu_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stwu_end); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(PUSH, REG_EDX, 0); + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(PUSH, REG_EAX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_stwux(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STWUX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stwux), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + { + JUMP_TARGET stwux_slow_path, stwux_end; + init_jmp_target(&stwux_slow_path); + init_jmp_target(&stwux_end); + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDMR, REG_EAX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stwux_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stwux_end); + // slow path + gen_jmp_target(&stwux_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stwux_end); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(PUSH, REG_EDX, 0); + + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDMR, REG_EAX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(PUSH, REG_EAX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_stwx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STWX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stwx), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH + { + JUMP_TARGET stwx_slow_path, stwx_end; + init_jmp_target(&stwx_slow_path); + init_jmp_target(&stwx_end); + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(MOVMR, REG_EAX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EAX, PPCREG(RA)); + } + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stwx_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stwx_end); + // slow path + gen_jmp_target(&stwx_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stwx_end); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(PUSH, REG_EDX, 0); + + gen(MOVMR, REG_EAX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EAX, PPCREG(RA)); + } + gen(PUSH, REG_EAX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +// NOTE: not tested! +static UINT32 drc_subf(UINT32 op) +{ +#if !COMPILE_OPS || DISABLE_UNTESTED_OPS || DONT_COMPILE_SUBF + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfx), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RB)); + gen(SUBMR, REG_EDX, PPCREG(RA)); + gen(MOVRM, PPCREG(RT), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_subfc(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_SUBFC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfcx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + if (OEBIT) + { + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfcx), 0); + gen(ADDI, REG_ESP, 4); + } + else + { + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(ANDI, REG_EBX, ~XER_CA); + gen(MOVMR, REG_EDX, PPCREG(RB)); + gen(SUBMR, REG_EDX, PPCREG(RA)); + gen(SETNCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, PPCREG(RT), REG_EDX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + } + +#endif + return 0; +} + +static UINT32 drc_subfe(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfex), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_subfic(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_SUBFIC + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfic), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EBX, (UINT32)&ppc.xer); + gen(ANDI, REG_EBX, ~XER_CA); + gen(MOVI, REG_EDX, SIMM16); + gen(SUBMR, REG_EDX, PPCREG(RA)); + gen(SETNCR8, REG_AL, 0); + gen(SHLI, REG_EAX, 29); + gen(OR, REG_EBX, REG_EAX); + gen(MOVRM, PPCREG(RT), REG_EDX); + gen(MOVRM, (UINT32)&ppc.xer, REG_EBX); + +#endif + return 0; +} + +static UINT32 drc_subfme(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfmex), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_subfze(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_subfzex), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_sync(UINT32 op) +{ + return 0; +} + +static UINT32 drc_tw(UINT32 op) +{ + JUMP_TARGET branch_link1; + JUMP_TARGET branch_link2; + JUMP_TARGET branch_link3; + JUMP_TARGET branch_link4; + JUMP_TARGET branch_link5; + JUMP_TARGET branch_link6; + int do_link1 = 0; + int do_link2 = 0; + int do_link3 = 0; + int do_link4 = 0; + int do_link5 = 0; + init_jmp_target(&branch_link1); + init_jmp_target(&branch_link2); + init_jmp_target(&branch_link3); + init_jmp_target(&branch_link4); + init_jmp_target(&branch_link5); + init_jmp_target(&branch_link6); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.r[RA]); + gen(MOVMR, REG_EDX, (UINT32)&ppc.r[RB]); + gen(CMP, REG_EAX, REG_EDX); + + if (RT & 0x10) + { + gen_jmp(JL, &branch_link1); // less than = signed < + do_link1 = 1; + } + if (RT & 0x08) + { + gen_jmp(JG, &branch_link2); // greater = signed > + do_link2 = 1; + } + if (RT & 0x04) + { + gen_jmp(JZ, &branch_link3); // equal + do_link3 = 1; + } + if (RT & 0x02) + { + gen_jmp(JB, &branch_link4); // below = unsigned < + do_link4 = 1; + } + if (RT & 0x01) + { + gen_jmp(JA, &branch_link5); // above = unsigned > + do_link5 = 1; + } + + gen_jmp(JMP, &branch_link6); + + if (do_link1) + { + gen_jmp_target(&branch_link1); + } + if (do_link2) + { + gen_jmp_target(&branch_link2); + } + if (do_link3) + { + gen_jmp_target(&branch_link3); + } + if (do_link4) + { + gen_jmp_target(&branch_link4); + } + if (do_link5) + { + gen_jmp_target(&branch_link5); + } + + // generate exception + { + JUMP_TARGET clear_le, exception_base_0; + init_jmp_target(&clear_le); + init_jmp_target(&exception_base_0); + + gen(MOVIM, (UINT32)&ppc.srr0, drc_pc+4); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.msr); + gen(ANDI, REG_EAX, 0xff73); + gen(MOVRM, (UINT32)&ppc.srr1, REG_EAX); + + // Clear POW, EE, PR, FP, FE0, SE, BE, FE1, IR, DR, RI + gen(ANDI, REG_EAX, ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI)); + + // Set LE to ILE + gen(ANDI, REG_EAX, ~MSR_LE); // clear LE first + gen(TESTI, REG_EAX, MSR_ILE); + gen_jmp(JZ, &clear_le); // if Z == 0, bit = 1 + gen(ORI, REG_EAX, MSR_LE); // set LE + gen_jmp_target(&clear_le); + + gen(MOVRM, (UINT32)&ppc.msr, REG_EAX); + + gen(MOVI, REG_EDI, 0x00000700); // exception vector + gen(TESTI, REG_EAX, MSR_IP); + gen_jmp(JZ, &exception_base_0); // if Z == 1, bit = 0 means base == 0x00000000 + gen(ORI, REG_EDI, 0xfff00000); + gen_jmp_target(&exception_base_0); + + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + } + + gen_jmp_target(&branch_link6); + + return 0; +} + +static UINT32 drc_twi(UINT32 op) +{ + JUMP_TARGET branch_link1; + JUMP_TARGET branch_link2; + JUMP_TARGET branch_link3; + JUMP_TARGET branch_link4; + JUMP_TARGET branch_link5; + JUMP_TARGET branch_link6; + int do_link1 = 0; + int do_link2 = 0; + int do_link3 = 0; + int do_link4 = 0; + int do_link5 = 0; + init_jmp_target(&branch_link1); + init_jmp_target(&branch_link2); + init_jmp_target(&branch_link3); + init_jmp_target(&branch_link4); + init_jmp_target(&branch_link5); + init_jmp_target(&branch_link6); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.r[RA]); + gen(MOVI, REG_EDX, SIMM16); + gen(CMP, REG_EAX, REG_EDX); + + if (RT & 0x10) + { + gen_jmp(JL, &branch_link1); // less than = signed < + do_link1 = 1; + } + if (RT & 0x08) + { + gen_jmp(JG, &branch_link2); // greater = signed > + do_link2 = 1; + } + if (RT & 0x04) + { + gen_jmp(JZ, &branch_link3); // equal + do_link3 = 1; + } + if (RT & 0x02) + { + gen_jmp(JB, &branch_link4); // below = unsigned < + do_link4 = 1; + } + if (RT & 0x01) + { + gen_jmp(JA, &branch_link5); // above = unsigned > + do_link5 = 1; + } + + gen_jmp(JMP, &branch_link6); + + if (do_link1) + { + gen_jmp_target(&branch_link1); + } + if (do_link2) + { + gen_jmp_target(&branch_link2); + } + if (do_link3) + { + gen_jmp_target(&branch_link3); + } + if (do_link4) + { + gen_jmp_target(&branch_link4); + } + if (do_link5) + { + gen_jmp_target(&branch_link5); + } + + // generate exception + { + JUMP_TARGET clear_le, exception_base_0; + init_jmp_target(&clear_le); + init_jmp_target(&exception_base_0); + + gen(MOVIM, (UINT32)&ppc.srr0, drc_pc+4); + + gen(MOVMR, REG_EAX, (UINT32)&ppc.msr); + gen(ANDI, REG_EAX, 0xff73); + gen(MOVRM, (UINT32)&ppc.srr1, REG_EAX); + + // Clear POW, EE, PR, FP, FE0, SE, BE, FE1, IR, DR, RI + gen(ANDI, REG_EAX, ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI)); + + // Set LE to ILE + gen(ANDI, REG_EAX, ~MSR_LE); // clear LE first + gen(TESTI, REG_EAX, MSR_ILE); + gen_jmp(JZ, &clear_le); // if Z == 0, bit = 1 + gen(ORI, REG_EAX, MSR_LE); // set LE + gen_jmp_target(&clear_le); + + gen(MOVRM, (UINT32)&ppc.msr, REG_EAX); + + gen(MOVI, REG_EDI, 0x00000700); // exception vector + gen(TESTI, REG_EAX, MSR_IP); + gen_jmp(JZ, &exception_base_0); // if Z == 1, bit = 0 means base == 0x00000000 + gen(ORI, REG_EDI, 0xfff00000); + gen_jmp_target(&exception_base_0); + + gen(MOVRM, (UINT32)&ppc.pc, REG_EDI); + drccore_insert_dispatcher(); + } + + gen_jmp_target(&branch_link6); + + return 0; +} + +static UINT32 drc_xor(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_XOR + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_xorx), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(XORMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + if (RCBIT) + { + insert_set_cr0(REG_EDX); + } + +#endif + return 0; +} + +static UINT32 drc_xori(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_XORI + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_xori), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(XORI, REG_EDX, UIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_xoris(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_XORIS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_xoris), 0); + gen(ADDI, REG_ESP, 4); + +#else + + gen(MOVMR, REG_EDX, PPCREG(RS)); + gen(XORI, REG_EDX, UIMM16 << 16); + gen(MOVRM, PPCREG(RA), REG_EDX); + +#endif + return 0; +} + +static UINT32 drc_dccci(UINT32 op) +{ + return 0; +} + +static UINT32 drc_dcread(UINT32 op) +{ + return 0; +} + +static UINT32 drc_icbt(UINT32 op) +{ + return 0; +} + +static UINT32 drc_iccci(UINT32 op) +{ + return 0; +} + +static UINT32 drc_icread(UINT32 op) +{ + return 0; +} + + + +static UINT32 drc_invalid(UINT32 op) +{ + error("PPCDRC: Invalid opcode %08X PC : %X\n", op, ppc.pc); + return 0; +} + +static UINT32 drc_lfs(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LFS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfs), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + if (RA == 0) + { + UINT32 address = SIMM16; + if (address < 0x800000) + { + gen(MOVMR, REG_EAX, (UINT32)ram + address); + gen(BSWAP, REG_EAX, 0); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); + } + else + { + gen(PUSHI, SIMM16, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); + } + } + else + { + JUMP_TARGET lfs_slow_path, lfs_end; + init_jmp_target(&lfs_slow_path); + init_jmp_target(&lfs_end); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lfs_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lfs_end); + // slow path + gen_jmp_target(&lfs_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lfs_end); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); + } +#else + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(PUSH, REG_EDX, 0); + } + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); +#endif + +#endif + return 0; +} + +static UINT32 drc_lfsu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LFSU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfsu), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + { + JUMP_TARGET lfsu_slow_path, lfsu_end; + init_jmp_target(&lfsu_slow_path); + init_jmp_target(&lfsu_end); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lfsu_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lfsu_end); + // slow path + gen_jmp_target(&lfsu_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lfsu_end); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); +#endif + +#endif + return 0; +} + +static UINT32 drc_lfd(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfd), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_lfdu(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfdu), 0); + gen(ADDI, REG_ESP, 4); + + + return 0; +} + +static UINT32 drc_stfs(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STFS + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfs), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + if (RA == 0) + { + UINT32 address = SIMM16; + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EDX, REG_XMM1); + if (address < 0x800000) + { + gen(BSWAP, REG_EDX, 0); + gen(MOVRM, (UINT32)ram + address, REG_EDX); + } + else + { + gen(PUSH, REG_EDX, 0); + gen(PUSHI, SIMM16, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + } + } + else + { + JUMP_TARGET stfs_slow_path, stfs_end; + init_jmp_target(&stfs_slow_path); + init_jmp_target(&stfs_end); + + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EDX, REG_XMM1); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stfs_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stfs_end); + // slow path + gen_jmp_target(&stfs_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stfs_end); + } +#else + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EAX, REG_XMM1); + gen(PUSH, REG_EAX, 0); + + if (RA == 0) + { + gen(PUSHI, SIMM16, 0); + } + else + { + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(PUSH, REG_EDX, 0); + } + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_stfsu(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STFSU + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfsu), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + { + JUMP_TARGET stfsu_slow_path, stfsu_end; + init_jmp_target(&stfsu_slow_path); + init_jmp_target(&stfsu_end); + + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EDX, REG_XMM1); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDI, REG_EAX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stfsu_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stfsu_end); + // slow path + gen_jmp_target(&stfsu_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stfsu_end); + } +#else + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EAX, REG_XMM1); + gen(PUSH, REG_EAX, 0); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDI, REG_EDX, SIMM16); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_stfd(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfd), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stfdu(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfdu), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_lfdux(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfdux), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_lfdx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfdx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_lfsux(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LFSUX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfsux), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + { + JUMP_TARGET lfsux_slow_path, lfsux_end; + init_jmp_target(&lfsux_slow_path); + init_jmp_target(&lfsux_end); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lfsux_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lfsux_end); + // slow path + gen_jmp_target(&lfsux_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lfsux_end); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); +#endif + +#endif + return 0; +} + +static UINT32 drc_lfsx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_LFSX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_lfsx), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + { + JUMP_TARGET lfsx_slow_path, lfsx_end; + init_jmp_target(&lfsx_slow_path); + init_jmp_target(&lfsx_end); + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(CMPI, REG_EDX, 0x800000); + gen_jmp(JAE, &lfsx_slow_path); + // fast path + gen_mov_dpr_to_reg(REG_EAX, ram, REG_EDX); + gen(BSWAP, REG_EAX, 0); + gen_jmp(JMP, &lfsx_end); + // slow path + gen_jmp_target(&lfsx_slow_path); + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + // end + gen_jmp_target(&lfsx_end); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); + } +#else + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + gen(CALLI, (UINT32)m3_ppc_read_32, 0); + gen(ADDI, REG_ESP, 4); + gen(MOVDRX, REG_XMM0, REG_EAX); + gen(CVTSS2SD, REG_XMM1, REG_XMM0); + gen(MOVQXM, (UINT32)&ppc.fpr[RT], REG_XMM1); +#endif + +#endif + return 0; +} + +static UINT32 drc_mfsr(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mfsr), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mfsrin(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mfsrin), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mftb(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mftb), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtsr(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtsr), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtsrin(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtsrin), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_dcba(UINT32 op) +{ + return 0; +} + +static UINT32 drc_stfdux(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfdux), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stfdx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfdx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stfiwx(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfiwx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_stfsux(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STFSUX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfsux), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + { + JUMP_TARGET stfsux_slow_path, stfsux_end; + init_jmp_target(&stfsux_slow_path); + init_jmp_target(&stfsux_end); + + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EDX, REG_XMM1); + gen(MOVMR, REG_EAX, PPCREG(RA)); + gen(ADDMR, REG_EAX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EAX); + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stfsux_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stfsux_end); + // slow path + gen_jmp_target(&stfsux_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stfsux_end); + } +#else + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EAX, REG_XMM1); + gen(PUSH, REG_EAX, 0); + + gen(MOVMR, REG_EDX, PPCREG(RA)); + gen(ADDMR, REG_EDX, PPCREG(RB)); + gen(MOVRM, PPCREG(RA), REG_EDX); + gen(PUSH, REG_EDX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_stfsx(UINT32 op) +{ +#if !COMPILE_OPS || DONT_COMPILE_STFSX + + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_stfsx), 0); + gen(ADDI, REG_ESP, 4); + +#else + +#if ENABLE_FASTRAM_PATH_FPU + { + JUMP_TARGET stfsux_slow_path, stfsux_end; + init_jmp_target(&stfsux_slow_path); + init_jmp_target(&stfsux_end); + + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EDX, REG_XMM1); + gen(MOVMR, REG_EAX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EAX, PPCREG(RA)); + } + gen(CMPI, REG_EAX, 0x800000); + gen_jmp(JAE, &stfsux_slow_path); + // fast path + gen(BSWAP, REG_EDX, 0); + gen_mov_reg_to_dpr(REG_EDX, ram, REG_EAX); + gen_jmp(JMP, &stfsux_end); + // slow path + gen_jmp_target(&stfsux_slow_path); + gen(PUSH, REG_EDX, 0); + gen(PUSH, REG_EAX, 0); + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); + // end + gen_jmp_target(&stfsux_end); + } +#else + gen(MOVQMX, REG_XMM0, (UINT32)&ppc.fpr[RT]); + gen(CVTSD2SS, REG_XMM1, REG_XMM0); + gen(MOVDXR, REG_EAX, REG_XMM1); + gen(PUSH, REG_EAX, 0); + + gen(MOVMR, REG_EDX, PPCREG(RB)); + if (RA != 0) + { + gen(ADDMR, REG_EDX, PPCREG(RA)); + } + gen(PUSH, REG_EDX, 0); + + gen(CALLI, (UINT32)m3_ppc_write_32, 0); + gen(ADDI, REG_ESP, 8); +#endif + +#endif + return 0; +} + +static UINT32 drc_tlbia(UINT32 op) +{ + return 0; +} + +static UINT32 drc_tlbie(UINT32 op) +{ + return 0; +} + +static UINT32 drc_tlbsync(UINT32 op) +{ + return 0; +} + +static UINT32 drc_eciwx(UINT32 op) +{ + error("PPCDRC: eciwx unimplemented\n"); + return 0; +} + +static UINT32 drc_ecowx(UINT32 op) +{ + error("PPCDRC: ecowx unimplemented\n"); + return 0; +} + +static UINT32 drc_fabs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fabsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fadd(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_faddx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fcmpo(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fcmpo), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fcmpu(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fcmpu), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fctiw(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fctiwx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fctiwz(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fctiwzx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fdiv(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fdivx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmr(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmrx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fnabs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fnabsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fneg(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fnegx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_frsp(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_frspx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_frsqrte(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_frsqrtex), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fsqrt(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fsqrtx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fsub(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fsubx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mffs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mffsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtfsb0(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtfsb0x), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtfsb1(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtfsb1x), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtfsf(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtfsfx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mtfsfi(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mtfsfix), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_mcrfs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_mcrfs), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fadds(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_faddsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fdivs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fdivsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fres(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fresx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fsqrts(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fsqrtsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fsubs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fsubsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmadd(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmaddx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmsub(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmsubx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmul(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmulx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fnmadd(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fnmaddx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fnmsub(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fnmsubx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fsel(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fselx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmadds(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmaddsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmsubs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmsubsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fmuls(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fmulsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fnmadds(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fnmaddsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} + +static UINT32 drc_fnmsubs(UINT32 op) +{ + gen(PUSHI, op, 0); + gen(CALLI, (UINT32)(ppc_fnmsubsx), 0); + gen(ADDI, REG_ESP, 4); + + return 0; +} diff --git a/ppc_itp/ppc.c b/ppc_itp/ppc.c new file mode 100644 index 0000000..f49bc08 --- /dev/null +++ b/ppc_itp/ppc.c @@ -0,0 +1,808 @@ +/* IBM/Motorola PowerPC 4xx/6xx Emulator */ + +#include "model3.h" +#include "ppc.h" + +void ppc603_exception(int exception); +void ppc603_check_interrupts(void); + +#define RD ((op >> 21) & 0x1F) +#define RT ((op >> 21) & 0x1f) +#define RS ((op >> 21) & 0x1f) +#define RA ((op >> 16) & 0x1f) +#define RB ((op >> 11) & 0x1f) +#define RC ((op >> 6) & 0x1f) + +#define MB ((op >> 6) & 0x1f) +#define ME ((op >> 1) & 0x1f) +#define SH ((op >> 11) & 0x1f) +#define BO ((op >> 21) & 0x1f) +#define BI ((op >> 16) & 0x1f) +#define CRFD ((op >> 23) & 0x7) +#define CRFA ((op >> 18) & 0x7) +#define FXM ((op >> 12) & 0xff) +#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) + +#define SIMM16 (INT32)(INT16)(op & 0xffff) +#define UIMM16 (UINT32)(op & 0xffff) + +#define RCBIT (op & 0x1) +#define OEBIT (op & 0x400) +#define AABIT (op & 0x2) +#define LKBIT (op & 0x1) + +#define REG(x) (ppc.r[x]) +#define LR (ppc.lr) +#define CTR (ppc.ctr) +#define XER (ppc.xer) +#define CR(x) (ppc.cr[x]) +#define MSR (ppc.msr) +#define SRR0 (ppc.srr0) +#define SRR1 (ppc.srr1) +#define SRR2 (ppc.srr2) +#define SRR3 (ppc.srr3) +#define EVPR (ppc.evpr) +#define EXIER (ppc.exier) +#define EXISR (ppc.exisr) +#define DEC (ppc.dec) + + +// Stuff added for the 6xx +#define FPR(x) (ppc.fpr[x]) +#define FM ((op >> 17) & 0xFF) +#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) + + +#define CHECK_SUPERVISOR() \ + if((ppc.msr & 0x4000) != 0){ \ + } + +#define CHECK_FPU_AVAILABLE() \ + if((ppc.msr & 0x2000) == 0){ \ + } + +static UINT32 ppc_field_xlat[256]; + + + +#define FPSCR_FX 0x80000000 +#define FPSCR_FEX 0x40000000 +#define FPSCR_VX 0x20000000 +#define FPSCR_OX 0x10000000 +#define FPSCR_UX 0x08000000 +#define FPSCR_ZX 0x04000000 +#define FPSCR_XX 0x02000000 + + + +#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) +#define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) +#define _BIT(n) (1 << (n)) +#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) +#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) +#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) +#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) +#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) + +#define XER_SO 0x80000000 +#define XER_OV 0x40000000 +#define XER_CA 0x20000000 + +#define MSR_POW 0x00040000 /* Power Management Enable */ +#define MSR_WE 0x00040000 +#define MSR_CE 0x00020000 +#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ +#define MSR_EE 0x00008000 /* External Interrupt Enable */ +#define MSR_PR 0x00004000 /* Problem State */ +#define MSR_FP 0x00002000 /* Floating Point Available */ +#define MSR_ME 0x00001000 /* Machine Check Enable */ +#define MSR_FE0 0x00000800 +#define MSR_SE 0x00000400 /* Single Step Trace Enable */ +#define MSR_BE 0x00000200 /* Branch Trace Enable */ +#define MSR_DE 0x00000200 +#define MSR_FE1 0x00000100 +#define MSR_IP 0x00000040 /* Interrupt Prefix */ +#define MSR_IR 0x00000020 /* Instruction Relocate */ +#define MSR_DR 0x00000010 /* Data Relocate */ +#define MSR_PE 0x00000008 +#define MSR_PX 0x00000004 +#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ +#define MSR_LE 0x00000001 + +#define TSR_ENW 0x80000000 +#define TSR_WIS 0x40000000 + +#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) +#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) + +typedef union { + UINT64 id; + double fd; +} FPR; + +typedef union { + UINT32 i; + float f; +} FPR32; + +typedef struct { + UINT32 u; + UINT32 l; +} BATENT; + + +typedef struct { + UINT32 r[32]; + UINT32 pc; + UINT32 npc; + + UINT32 *op; + + UINT32 lr; + UINT32 ctr; + UINT32 xer; + UINT32 msr; + UINT8 cr[8]; + UINT32 pvr; + UINT32 srr0; + UINT32 srr1; + UINT32 srr2; + UINT32 srr3; + UINT32 hid0; + UINT32 hid1; + UINT32 hid2; + UINT32 sdr1; + UINT32 sprg[4]; + + UINT32 dsisr; + UINT32 dar; + UINT32 ear; + UINT32 dmiss; + UINT32 dcmp; + UINT32 hash1; + UINT32 hash2; + UINT32 imiss; + UINT32 icmp; + UINT32 rpa; + + + BATENT ibat[4]; + BATENT dbat[4]; + + UINT32 evpr; + UINT32 exier; + UINT32 exisr; + UINT32 bear; + UINT32 besr; + UINT32 iocr; + UINT32 br[8]; + UINT32 iabr; + UINT32 esr; + UINT32 iccr; + UINT32 dccr; + UINT32 pit; + UINT32 pit_counter; + UINT32 pit_int_enable; + UINT32 tsr; + UINT32 dbsr; + UINT32 sgr; + UINT32 pid; + + int reserved; + UINT32 reserved_address; + + int interrupt_pending; + int external_int; + + UINT64 tb; /* 56-bit timebase register */ + + int (*irq_callback)(int irqline); + + PPC_FETCH_REGION cur_fetch; + PPC_FETCH_REGION * fetch; + + // STUFF added for the 6xx series + UINT32 dec, dec_frac; + UINT32 fpscr; + + FPR fpr[32]; + UINT32 sr[16]; + +#if HAS_PPC603 + int is603; +#endif +#if HAS_PPC602 + int is602; +#endif +} PPC_REGS; + + + +typedef struct { + int code; + int subcode; + void (* handler)(UINT32); +} PPC_OPCODE; + + + +static int ppc_icount; +static int ppc_tb_base_icount; +static int ppc_dec_base_icount; +static int ppc_dec_trigger_cycle; +static int bus_freq_multiplier = 1; +static PPC_REGS ppc; +static UINT32 ppc_rotate_mask[32][32]; + + + +static void ppc_change_pc(UINT32 newpc) +{ + UINT i; + + if (ppc.cur_fetch.start <= newpc && newpc <= ppc.cur_fetch.end) + { + ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start)); + return; + } + + for(i = 0; ppc.fetch[i].ptr != NULL; i++) + { + if (ppc.fetch[i].start <= newpc && newpc <= ppc.fetch[i].end) + { + ppc.cur_fetch.start = ppc.fetch[i].start; + ppc.cur_fetch.end = ppc.fetch[i].end; + ppc.cur_fetch.ptr = ppc.fetch[i].ptr; + + ppc.op = (UINT32 *)((UINT32)ppc.cur_fetch.ptr + (UINT32)(newpc - ppc.cur_fetch.start)); + + return; + } + } + + error("Invalid PC %08X, previous PC %08X\n", newpc, ppc.pc); +} + +INLINE UINT8 READ8(UINT32 address) +{ + return m3_ppc_read_8(address); +} + +INLINE UINT16 READ16(UINT32 address) +{ + return m3_ppc_read_16(address); +} + +INLINE UINT32 READ32(UINT32 address) +{ + return m3_ppc_read_32(address); +} + +INLINE UINT64 READ64(UINT32 address) +{ + return m3_ppc_read_64(address); +} + +INLINE void WRITE8(UINT32 address, UINT8 data) +{ + m3_ppc_write_8(address, data); +} + +INLINE void WRITE16(UINT32 address, UINT16 data) +{ + m3_ppc_write_16(address, data); +} + +INLINE void WRITE32(UINT32 address, UINT32 data) +{ + m3_ppc_write_32(address, data); +} + +INLINE void WRITE64(UINT32 address, UINT64 data) +{ + m3_ppc_write_64(address, data); +} + + +/*********************************************************************/ + + +INLINE void SET_CR0(INT32 rd) +{ + if( rd < 0 ) { + CR(0) = 0x8; + } else if( rd > 0 ) { + CR(0) = 0x4; + } else { + CR(0) = 0x2; + } + + if( XER & XER_SO ) + CR(0) |= 0x1; +} + +INLINE void SET_CR1(void) +{ + CR(1) = (ppc.fpscr >> 28) & 0xf; +} + +INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( ADD_OV(rd, ra, rb) ) + XER |= XER_SO | XER_OV; + else + XER &= ~XER_OV; +} + +INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( SUB_OV(rd, ra, rb) ) + XER |= XER_SO | XER_OV; + else + XER &= ~XER_OV; +} + +INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( ADD_CA(rd, ra, rb) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( SUB_CA(rd, ra, rb) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) +{ + UINT32 ctr_ok; + UINT32 condition_ok; + UINT32 bo0 = (bo & 0x10) ? 1 : 0; + UINT32 bo1 = (bo & 0x08) ? 1 : 0; + UINT32 bo2 = (bo & 0x04) ? 1 : 0; + UINT32 bo3 = (bo & 0x02) ? 1 : 0; + + if( bo2 == 0 ) + --CTR; + + ctr_ok = bo2 | ((CTR != 0) ^ bo3); + condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); + + return ctr_ok && condition_ok; +} + +INLINE UINT64 ppc_read_timebase(void) +{ + int cycles = ppc_tb_base_icount - ppc_icount; + + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + return ppc.tb + (cycles / 4); +} + +INLINE void ppc_write_timebase_l(UINT32 tbl) +{ + ppc_tb_base_icount = ppc_icount; + + ppc.tb &= ~0xffffffff; + ppc.tb |= tbl; +} + +INLINE void ppc_write_timebase_h(UINT32 tbh) +{ + ppc_tb_base_icount = ppc_icount; + + ppc.tb &= 0xffffffff; + ppc.tb |= (UINT64)(tbh) << 32; +} + +INLINE UINT32 read_decrementer(void) +{ + int cycles = ppc_dec_base_icount - ppc_icount; + + // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly + return DEC - (cycles / (bus_freq_multiplier * 2)); +} + +INLINE void write_decrementer(UINT32 value) +{ + ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2); + + DEC = value; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - (ppc_icount / (bus_freq_multiplier * 2))) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ((ppc_icount / (bus_freq_multiplier * 2)) - DEC) * 4; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + printf("DEC = %08X at %08X\n", value, ppc.pc); +} + +/*********************************************************************/ + +INLINE void ppc_set_spr(int spr, UINT32 value) +{ + switch (spr) + { + case SPR_LR: LR = value; return; + case SPR_CTR: CTR = value; return; + case SPR_XER: XER = value; return; + case SPR_SRR0: ppc.srr0 = value; return; + case SPR_SRR1: ppc.srr1 = value; return; + case SPR_SPRG0: ppc.sprg[0] = value; return; + case SPR_SPRG1: ppc.sprg[1] = value; return; + case SPR_SPRG2: ppc.sprg[2] = value; return; + case SPR_SPRG3: ppc.sprg[3] = value; return; + case SPR_PVR: return; + + case SPR603E_DEC: + if(((value & 0x80000000) && !(DEC & 0x80000000)) || value == 0) + { + /* trigger interrupt */ + ppc.interrupt_pending |= 0x2; + ppc603_check_interrupts(); + } + write_decrementer(value); + return; + + case SPR603E_TBL_W: + case SPR603E_TBL_R: // special 603e case + ppc_write_timebase_l(value); + return; + + case SPR603E_TBU_R: + case SPR603E_TBU_W: // special 603e case + ppc_write_timebase_h(value); + return; + + case SPR603E_HID0: ppc.hid0 = value; return; + case SPR603E_HID1: ppc.hid1 = value; return; + case SPR603E_HID2: ppc.hid2 = value; return; + + case SPR603E_DSISR: ppc.dsisr = value; return; + case SPR603E_DAR: ppc.dar = value; return; + case SPR603E_EAR: ppc.ear = value; return; + case SPR603E_DMISS: ppc.dmiss = value; return; + case SPR603E_DCMP: ppc.dcmp = value; return; + case SPR603E_HASH1: ppc.hash1 = value; return; + case SPR603E_HASH2: ppc.hash2 = value; return; + case SPR603E_IMISS: ppc.imiss = value; return; + case SPR603E_ICMP: ppc.icmp = value; return; + case SPR603E_RPA: ppc.rpa = value; return; + + case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; + case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; + case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; + case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; + case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; + case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; + case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; + case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; + case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; + case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; + case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; + case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; + case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; + case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; + case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; + case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; + + case SPR603E_SDR1: + ppc.sdr1 = value; + return; + + case SPR603E_IABR: ppc.iabr = value; return; + } + + error("ppc: set_spr: unknown spr %d (%03X) !", spr, spr); +} + +INLINE UINT32 ppc_get_spr(int spr) +{ + switch(spr) + { + case SPR_LR: return LR; + case SPR_CTR: return CTR; + case SPR_XER: return XER; + case SPR_SRR0: return ppc.srr0; + case SPR_SRR1: return ppc.srr1; + case SPR_SPRG0: return ppc.sprg[0]; + case SPR_SPRG1: return ppc.sprg[1]; + case SPR_SPRG2: return ppc.sprg[2]; + case SPR_SPRG3: return ppc.sprg[3]; + case SPR_PVR: return ppc.pvr; + case SPR603E_TBL_R: + error("ppc: get_spr: TBL_R "); + break; + + case SPR603E_TBU_R: + error("ppc: get_spr: TBU_R "); + break; + + case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); + case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); + case SPR603E_HID0: return ppc.hid0; + case SPR603E_HID1: return ppc.hid1; + case SPR603E_HID2: return ppc.hid2; + case SPR603E_DEC: return read_decrementer(); + case SPR603E_SDR1: return ppc.sdr1; + case SPR603E_DSISR: return ppc.dsisr; + case SPR603E_DAR: return ppc.dar; + case SPR603E_EAR: return ppc.ear; + case SPR603E_DMISS: return ppc.dmiss; + case SPR603E_DCMP: return ppc.dcmp; + case SPR603E_HASH1: return ppc.hash1; + case SPR603E_HASH2: return ppc.hash2; + case SPR603E_IMISS: return ppc.imiss; + case SPR603E_ICMP: return ppc.icmp; + case SPR603E_RPA: return ppc.rpa; + case SPR603E_IBAT0L: return ppc.ibat[0].l; + case SPR603E_IBAT0U: return ppc.ibat[0].u; + case SPR603E_IBAT1L: return ppc.ibat[1].l; + case SPR603E_IBAT1U: return ppc.ibat[1].u; + case SPR603E_IBAT2L: return ppc.ibat[2].l; + case SPR603E_IBAT2U: return ppc.ibat[2].u; + case SPR603E_IBAT3L: return ppc.ibat[3].l; + case SPR603E_IBAT3U: return ppc.ibat[3].u; + case SPR603E_DBAT0L: return ppc.dbat[0].l; + case SPR603E_DBAT0U: return ppc.dbat[0].u; + case SPR603E_DBAT1L: return ppc.dbat[1].l; + case SPR603E_DBAT1U: return ppc.dbat[1].u; + case SPR603E_DBAT2L: return ppc.dbat[2].l; + case SPR603E_DBAT2U: return ppc.dbat[2].u; + case SPR603E_DBAT3L: return ppc.dbat[3].l; + case SPR603E_DBAT3U: return ppc.dbat[3].u; + } + + error("ppc: get_spr: unknown spr %d (%03X) !", spr, spr); + return 0; +} + +INLINE void ppc_set_msr(UINT32 value) +{ + if( value & (MSR_ILE | MSR_LE) ) + error("ppc: set_msr: little_endian mode not supported !"); + + MSR = value; + + ppc603_check_interrupts(); +} + +INLINE UINT32 ppc_get_msr(void) +{ + return MSR; +} + +INLINE void ppc_set_cr(UINT32 value) +{ + CR(0) = (value >> 28) & 0xf; + CR(1) = (value >> 24) & 0xf; + CR(2) = (value >> 20) & 0xf; + CR(3) = (value >> 16) & 0xf; + CR(4) = (value >> 12) & 0xf; + CR(5) = (value >> 8) & 0xf; + CR(6) = (value >> 4) & 0xf; + CR(7) = (value >> 0) & 0xf; +} + +INLINE UINT32 ppc_get_cr(void) +{ + return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); +} + +/***********************************************************************/ + +static void (* optable19[1024])(UINT32); +static void (* optable31[1024])(UINT32); +static void (* optable59[1024])(UINT32); +static void (* optable63[1024])(UINT32); +static void (* optable[64])(UINT32); + +#include "ppc603.c" + +/********************************************************************/ + +#include "ppc_ops.c" +#include "ppc_ops.h" + +/* Initialization and shutdown */ + +void ppc_base_init(void) +{ + int i,j; + + memset(&ppc, 0, sizeof(ppc)); + + for( i=0; i < 64; i++ ) { + optable[i] = ppc_invalid; + } + for( i=0; i < 1024; i++ ) { + optable19[i] = ppc_invalid; + optable31[i] = ppc_invalid; + optable59[i] = ppc_invalid; + optable63[i] = ppc_invalid; + } + + /* Fill the opcode tables */ + for( i=0; i < (sizeof(ppc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) { + + switch(ppc_opcode_common[i].code) + { + case 19: + optable19[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler; + break; + + case 31: + optable31[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler; + break; + + case 59: + case 63: + break; + + default: + optable[ppc_opcode_common[i].code] = ppc_opcode_common[i].handler; + } + + } + + /* Calculate rotate mask table */ + for( i=0; i < 32; i++ ) { + for( j=0; j < 32; j++ ) { + UINT32 mask; + int mb = i; + int me = j; + mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); + if( mb > me ) + mask = ~mask; + + ppc_rotate_mask[i][j] = mask; + } + } +} + +void ppc_init(const PPC_CONFIG *config) +{ + int pll_config = 0; + float multiplier; + int i ; + + ppc_base_init() ; + + optable[48] = ppc_lfs; + optable[49] = ppc_lfsu; + optable[50] = ppc_lfd; + optable[51] = ppc_lfdu; + optable[52] = ppc_stfs; + optable[53] = ppc_stfsu; + optable[54] = ppc_stfd; + optable[55] = ppc_stfdu; + optable31[631] = ppc_lfdux; + optable31[599] = ppc_lfdx; + optable31[567] = ppc_lfsux; + optable31[535] = ppc_lfsx; + optable31[595] = ppc_mfsr; + optable31[659] = ppc_mfsrin; + optable31[371] = ppc_mftb; + optable31[210] = ppc_mtsr; + optable31[242] = ppc_mtsrin; + optable31[758] = ppc_dcba; + optable31[759] = ppc_stfdux; + optable31[727] = ppc_stfdx; + optable31[983] = ppc_stfiwx; + optable31[695] = ppc_stfsux; + optable31[663] = ppc_stfsx; + optable31[370] = ppc_tlbia; + optable31[306] = ppc_tlbie; + optable31[566] = ppc_tlbsync; + optable31[310] = ppc_eciwx; + optable31[438] = ppc_ecowx; + + optable63[264] = ppc_fabsx; + optable63[21] = ppc_faddx; + optable63[32] = ppc_fcmpo; + optable63[0] = ppc_fcmpu; + optable63[14] = ppc_fctiwx; + optable63[15] = ppc_fctiwzx; + optable63[18] = ppc_fdivx; + optable63[72] = ppc_fmrx; + optable63[136] = ppc_fnabsx; + optable63[40] = ppc_fnegx; + optable63[12] = ppc_frspx; + optable63[26] = ppc_frsqrtex; + optable63[22] = ppc_fsqrtx; + optable63[20] = ppc_fsubx; + optable63[583] = ppc_mffsx; + optable63[70] = ppc_mtfsb0x; + optable63[38] = ppc_mtfsb1x; + optable63[711] = ppc_mtfsfx; + optable63[134] = ppc_mtfsfix; + optable63[64] = ppc_mcrfs; + + optable59[21] = ppc_faddsx; + optable59[18] = ppc_fdivsx; + optable59[24] = ppc_fresx; + optable59[22] = ppc_fsqrtsx; + optable59[20] = ppc_fsubsx; + + for(i = 0; i < 32; i++) + { + optable63[i * 32 | 29] = ppc_fmaddx; + optable63[i * 32 | 28] = ppc_fmsubx; + optable63[i * 32 | 25] = ppc_fmulx; + optable63[i * 32 | 31] = ppc_fnmaddx; + optable63[i * 32 | 30] = ppc_fnmsubx; + optable63[i * 32 | 23] = ppc_fselx; + + optable59[i * 32 | 29] = ppc_fmaddsx; + optable59[i * 32 | 28] = ppc_fmsubsx; + optable59[i * 32 | 25] = ppc_fmulsx; + optable59[i * 32 | 31] = ppc_fnmaddsx; + optable59[i * 32 | 30] = ppc_fnmsubsx; + } + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + ppc.pvr = config->pvr; + + multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + + (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); + + switch(config->pvr) + { + case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; + case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; + case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; + default: break; + } + + if (pll_config == -1) + { + error("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); + } + + ppc.hid1 = pll_config << 28; +} + +void ppc_shutdown(void) +{ + +} + +void ppc_set_irq_line(int irqline) +{ + ppc.interrupt_pending |= 0x1; + + ppc603_check_interrupts(); +} + +UINT32 ppc_get_pc(void) +{ + return ppc.pc; +} + +void ppc_set_fetch(PPC_FETCH_REGION * fetch) +{ + ppc.fetch = fetch; +} \ No newline at end of file diff --git a/ppc_itp/ppc.h b/ppc_itp/ppc.h new file mode 100644 index 0000000..6493a96 --- /dev/null +++ b/ppc_itp/ppc.h @@ -0,0 +1,314 @@ +#ifndef _PPC_H +#define _PPC_H + +#define SPR_XER 1 /* Fixed Point Exception Register Read / Write */ +#define SPR_LR 8 /* Link Register Read / Write */ +#define SPR_CTR 9 /* Count Register Read / Write */ +#define SPR_SRR0 26 /* Save/Restore Register 0 Read / Write */ +#define SPR_SRR1 27 /* Save/Restore Register 1 Read / Write */ +#define SPR_SPRG0 272 /* SPR General 0 Read / Write */ +#define SPR_SPRG1 273 /* SPR General 1 Read / Write */ +#define SPR_SPRG2 274 /* SPR General 2 Read / Write */ +#define SPR_SPRG3 275 /* SPR General 3 Read / Write */ +#define SPR_PVR 287 /* Processor Version Number Read Only */ + +#define SPR403_ICDBDR 0x3D3 /* 406GA Instruction Cache Debug Data Register Rad Only */ +#define SPR403_ESR 0x3D4 /* 406GA Exception Syndrome Register Read / Write */ +#define SPR403_DEAR 0x3D5 /* 406GA Data Exception Address Register Read Only */ +#define SPR403_EVPR 0x3D6 /* 406GA Exception Vector Prefix Register Read / Write */ +#define SPR403_CDBCR 0x3D7 /* 406GA Cache Debug Control Register Read/Write */ +#define SPR403_TSR 0x3D8 /* 406GA Timer Status Register Read / Clear */ +#define SPR403_TCR 0x3DA /* 406GA Timer Control Register Read / Write */ +#define SPR403_PIT 0x3DB /* 406GA Programmable Interval Timer Read / Write */ +#define SPR403_TBHI 988 /* 406GA Time Base High Read / Write */ +#define SPR403_TBLO 989 /* 406GA Time Base Low Read / Write */ +#define SPR403_SRR2 0x3DE /* 406GA Save/Restore Register 2 Read / Write */ +#define SPR403_SRR3 0x3DF /* 406GA Save/Restore Register 3 Read / Write */ +#define SPR403_DBSR 0x3F0 /* 406GA Debug Status Register Read / Clear */ +#define SPR403_DBCR 0x3F2 /* 406GA Debug Control Register Read / Write */ +#define SPR403_IAC1 0x3F4 /* 406GA Instruction Address Compare 1 Read / Write */ +#define SPR403_IAC2 0x3F5 /* 406GA Instruction Address Compare 2 Read / Write */ +#define SPR403_DAC1 0x3F6 /* 406GA Data Address Compare 1 Read / Write */ +#define SPR403_DAC2 0x3F7 /* 406GA Data Address Compare 2 Read / Write */ +#define SPR403_DCCR 0x3FA /* 406GA Data Cache Cacheability Register Read / Write */ +#define SPR403_ICCR 0x3FB /* 406GA I Cache Cacheability Registe Read / Write */ +#define SPR403_PBL1 0x3FC /* 406GA Protection Bound Lower 1 Read / Write */ +#define SPR403_PBU1 0x3FD /* 406GA Protection Bound Upper 1 Read / Write */ +#define SPR403_PBL2 0x3FE /* 406GA Protection Bound Lower 2 Read / Write */ +#define SPR403_PBU2 0x3FF /* 406GA Protection Bound Upper 2 Read / Write */ + +#define SPR403_SGR 0x3b9 /* 403GCX Storage Guarded Register */ +#define SPR403_DCWR 0x3ba /* 403GCX Data Cache Write Through */ +#define SPR403_PID 0x3b1 /* 403GCX Process ID */ +#define SPR403_TBHU 0x3cc /* 403GCX Time Base High User-mode */ +#define SPR403_TBLU 0x3cd /* 403GCX Time Base Low User-mode */ + +#define SPR603E_DSISR 18 /* 603E */ +#define SPR603E_DAR 19 /* 603E */ +#define SPR603E_DEC 22 /* 603E */ +#define SPR603E_SDR1 25 /* 603E */ +#define SPR603E_TBL_R 268 /* 603E Time Base Low (Read-only) */ +#define SPR603E_TBU_R 269 /* 603E Time Base High (Read-only) */ +#define SPR603E_TBL_W 284 /* 603E Time Base Low (Write-only) */ +#define SPR603E_TBU_W 285 /* 603E Time Base Hight (Write-only) */ +#define SPR603E_EAR 282 /* 603E */ +#define SPR603E_IBAT0U 528 /* 603E */ +#define SPR603E_IBAT0L 529 /* 603E */ +#define SPR603E_IBAT1U 530 /* 603E */ +#define SPR603E_IBAT1L 531 /* 603E */ +#define SPR603E_IBAT2U 532 /* 603E */ +#define SPR603E_IBAT2L 533 /* 603E */ +#define SPR603E_IBAT3U 534 /* 603E */ +#define SPR603E_IBAT3L 535 /* 603E */ +#define SPR603E_DBAT0U 536 /* 603E */ +#define SPR603E_DBAT0L 537 /* 603E */ +#define SPR603E_DBAT1U 538 /* 603E */ +#define SPR603E_DBAT1L 539 /* 603E */ +#define SPR603E_DBAT2U 540 /* 603E */ +#define SPR603E_DBAT2L 541 /* 603E */ +#define SPR603E_DBAT3U 542 /* 603E */ +#define SPR603E_DBAT3L 543 /* 603E */ +#define SPR603E_DABR 1013 /* 603E */ +#define SPR603E_DMISS 0x3d0 /* 603E */ +#define SPR603E_DCMP 0x3d1 /* 603E */ +#define SPR603E_HASH1 0x3d2 /* 603E */ +#define SPR603E_HASH2 0x3d3 /* 603E */ +#define SPR603E_IMISS 0x3d4 /* 603E */ +#define SPR603E_ICMP 0x3d5 /* 603E */ +#define SPR603E_RPA 0x3d6 /* 603E */ +#define SPR603E_HID0 1008 /* 603E */ +#define SPR603E_HID1 1009 /* 603E */ +#define SPR603E_IABR 1010 /* 603E */ +#define SPR603E_HID2 1011 /* 603E */ + +#define SPR602_TCR 984 /* 602 */ +#define SPR602_IBR 986 /* 602 */ +#define SPR602_SP 1021 /* 602 */ +#define SPR602_LT 1022 /* 602 */ + + +#define DCR_BEAR 0x90 /* bus error address */ +#define DCR_BESR 0x91 /* bus error syndrome */ +#define DCR_BR0 0x80 /* bank */ +#define DCR_BR1 0x81 /* bank */ +#define DCR_BR2 0x82 /* bank */ +#define DCR_BR3 0x83 /* bank */ +#define DCR_BR4 0x84 /* bank */ +#define DCR_BR5 0x85 /* bank */ +#define DCR_BR6 0x86 /* bank */ +#define DCR_BR7 0x87 /* bank */ +#define DCR_DMACC0 0xc4 /* dma chained count */ +#define DCR_DMACC1 0xcc /* dma chained count */ +#define DCR_DMACC2 0xd4 /* dma chained count */ +#define DCR_DMACC3 0xdc /* dma chained count */ +#define DCR_DMACR0 0xc0 /* dma channel control */ +#define DCR_DMACR1 0xc8 /* dma channel control */ +#define DCR_DMACR2 0xd0 /* dma channel control */ +#define DCR_DMACR3 0xd8 /* dma channel control */ +#define DCR_DMACT0 0xc1 /* dma destination address */ +#define DCR_DMACT1 0xc9 /* dma destination address */ +#define DCR_DMACT2 0xd1 /* dma destination address */ +#define DCR_DMACT3 0xd9 /* dma destination address */ +#define DCR_DMADA0 0xc2 /* dma destination address */ +#define DCR_DMADA1 0xca /* dma destination address */ +#define DCR_DMADA2 0xd2 /* dma source address */ +#define DCR_DMADA3 0xda /* dma source address */ +#define DCR_DMASA0 0xc3 /* dma source address */ +#define DCR_DMASA1 0xcb /* dma source address */ +#define DCR_DMASA2 0xd3 /* dma source address */ +#define DCR_DMASA3 0xdb /* dma source address */ +#define DCR_DMASR 0xe0 /* dma status */ +#define DCR_EXIER 0x42 /* external interrupt enable */ +#define DCR_EXISR 0x40 /* external interrupt status */ +#define DCR_IOCR 0xa0 /* io configuration */ + +enum { + EXCEPTION_IRQ = 1, + EXCEPTION_DECREMENTER = 2, + EXCEPTION_TRAP = 3, + EXCEPTION_SYSTEM_CALL = 4, + EXCEPTION_SMI = 5, + EXCEPTION_DSI = 6, + EXCEPTION_ISI = 7, + EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER = 20, + EXCEPTION_FIXED_INTERVAL_TIMER = 21, + EXCEPTION_WATCHDOG_TIMER = 22, + EXCEPTION_CRITICAL_INTERRUPT = 23, +}; + +enum { + PPC_INPUT_LINE_SMI = 10, + PPC_INPUT_LINE_TLBISYNC +}; + +enum { + PPC_PC=1, + PPC_MSR, + PPC_CR, + PPC_LR, + PPC_CTR, + PPC_XER, + PPC_DEC, + PPC_SRR0, + PPC_SRR1, + PPC_R0, + PPC_R1, + PPC_R2, + PPC_R3, + PPC_R4, + PPC_R5, + PPC_R6, + PPC_R7, + PPC_R8, + PPC_R9, + PPC_R10, + PPC_R11, + PPC_R12, + PPC_R13, + PPC_R14, + PPC_R15, + PPC_R16, + PPC_R17, + PPC_R18, + PPC_R19, + PPC_R20, + PPC_R21, + PPC_R22, + PPC_R23, + PPC_R24, + PPC_R25, + PPC_R26, + PPC_R27, + PPC_R28, + PPC_R29, + PPC_R30, + PPC_R31 +}; + +typedef enum { + PPC_MODEL_403GA = 0x00200000, + PPC_MODEL_403GB = 0x00200100, + PPC_MODEL_403GC = 0x00200200, + PPC_MODEL_403GCX = 0x00201400, + PPC_MODEL_405GP = 0x40110000, + PPC_MODEL_601 = 0x00010000, + PPC_MODEL_603 = 0x00030000, /* "Wart" */ + PPC_MODEL_604 = 0x00040000, /* "Zephyr" */ + PPC_MODEL_602 = 0x00050000, /* "Galahad" */ + PPC_MODEL_603E = 0x00060103, /* "Stretch", version 1.3 */ + PPC_MODEL_603EV = 0x00070000, /* "Valiant" */ + PPC_MODEL_603R = 0x00071202, /* "Goldeneye", version 2.1 */ + PPC_MODEL_740 = 0x00080301, /* "Arthur", version 3.1 */ + PPC_MODEL_750 = PPC_MODEL_740, + PPC_MODEL_740P = 0x00080202, /* "Conan Doyle", version 1.2 */ + PPC_MODEL_750P = PPC_MODEL_740P, + PPC_MODEL_755 = 0x00083203 /* "Goldfinger", version 2.3 */ +} PPC_MODEL; + +typedef enum { + BUS_FREQUENCY_16MHZ = 0, + BUS_FREQUENCY_20MHZ, + BUS_FREQUENCY_25MHZ, + BUS_FREQUENCY_33MHZ, + BUS_FREQUENCY_40MHZ, + BUS_FREQUENCY_50MHZ, + BUS_FREQUENCY_60MHZ, + BUS_FREQUENCY_66MHZ, + BUS_FREQUENCY_75MHZ, +} PPC_BUS_FREQUENCY; + +// PLL Configuration based on the table in MPC603EUM page 7-31 +static const int mpc603e_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, -1, 0x0, -1 }, + { -1, -1, -1, -1, -1, 0xc, -1, 0xc, -1 }, + { 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, -1, -1, -1 }, + { -1, -1, -1, 0x6, 0x6, -1, -1, -1, -1 }, + { -1, -1, 0x8, 0x8, -1, -1, -1, -1, -1 }, + { -1, 0xe, 0xe, -1, -1, -1, -1, -1, -1 }, + { 0xa, 0xa, 0xa, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +}; + +// PLL Configuration based on the table in MPC603E7VEC page 29 +static const int mpc603ev_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + // 2:1 + { -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4 }, + // 2.5:1 + { -1, -1, -1, -1, -1, 0x6, 0x6, 0x6, 0x6 }, + // 3:1 + { -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8, 0x8 }, + // 3.5:1 + { -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe, -1 }, + // 4:1 + { -1, -1, -1, 0xa, 0xa, 0xa, 0xa, -1, -1 }, + // 4.5:1 + { -1, -1, -1, 0x7, 0x7, 0x7, -1, -1, -1 }, + // 5:1 + { -1, -1, 0xb, 0xb, 0xb, -1, -1, -1, -1 }, + // 5.5:1 + { -1, -1, 0x9, 0x9, 0x9, -1, -1, -1, -1 }, + // 6:1 + { -1, -1, 0xd, 0xd, 0xd, -1, -1, -1, -1 } +}; + +// PLL Configuration based on the table in MPC603E7TEC page 23 +static const int mpc603r_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + // 2:1 + { -1, -1, -1, -1, 0x5, 0x5, 0x5, 0x5, 0x5 }, + // 2.5:1 + { -1, -1, -1, -1, -1, -1, 0x6, 0x6, 0x6 }, + // 3:1 + { -1, -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8 }, + // 3.5:1 + { -1, -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe }, + // 4:1 + { -1, -1, -1, -1, 0xa, 0xa, 0xa, 0xa, 0xa }, + // 4.5:1 + { -1, -1, -1, 0x7, 0x7, 0x7, 0x7, 0x7, -1 }, + // 5:1 + { -1, -1, -1, 0xb, 0xb, 0xb, 0xb, -1, -1 }, + // 5.5:1 + { -1, -1, -1, 0x9, 0x9, 0x9, -1, -1, -1 }, + // 6:1 + { -1, -1, 0xd, 0xd, 0xd, 0xd, -1, -1, -1 }, +}; + +typedef struct { + PPC_MODEL pvr; + int bus_frequency_multiplier; + PPC_BUS_FREQUENCY bus_frequency; +} PPC_CONFIG; + +typedef struct +{ + UINT32 start; + UINT32 end; + UINT32 * ptr; + +} PPC_FETCH_REGION; + +UINT32 ppc_get_pc(void); +void ppc_set_irq_line(int irqline); +int ppc_execute(int cycles); +void ppc_reset(void); +void ppc_shutdown(void); +void ppc_init(const PPC_CONFIG *config); +void ppc_set_fetch(PPC_FETCH_REGION * fetch); + +#endif /* _PPC_H */ diff --git a/ppc_itp/ppc603.c b/ppc_itp/ppc603.c new file mode 100644 index 0000000..8fb482b --- /dev/null +++ b/ppc_itp/ppc603.c @@ -0,0 +1,294 @@ +void ppc603_exception(int exception) +{ + switch( exception ) + { + case EXCEPTION_IRQ: /* External Interrupt */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0500; + else + ppc.npc = 0x00000000 | 0x0500; + + ppc.interrupt_pending &= ~0x1; + ppc_change_pc(ppc.npc); + } + break; + + case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0900; + else + ppc.npc = 0x00000000 | 0x0900; + + ppc.interrupt_pending &= ~0x2; + ppc_change_pc(ppc.npc); + } + break; + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */ + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0700; + else + ppc.npc = 0x00000000 | 0x0700; + ppc_change_pc(ppc.npc); + } + break; + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = (msr & 0xff73); + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0c00; + else + ppc.npc = 0x00000000 | 0x0c00; + ppc_change_pc(ppc.npc); + } + break; + + case EXCEPTION_SMI: + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x1400; + else + ppc.npc = 0x00000000 | 0x1400; + + ppc.interrupt_pending &= ~0x4; + ppc_change_pc(ppc.npc); + } + break; + + case EXCEPTION_DSI: + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0300; + else + ppc.npc = 0x00000000 | 0x0300; + + ppc.interrupt_pending &= ~0x4; + ppc_change_pc(ppc.npc); + } + break; + + case EXCEPTION_ISI: + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0400; + else + ppc.npc = 0x00000000 | 0x0400; + + ppc.interrupt_pending &= ~0x4; + ppc_change_pc(ppc.npc); + } + break; + + default: + error("ppc: Unhandled exception %d", exception); + break; + } +} + +static void ppc603_set_smi_line(int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x4; + } +} + +static void ppc603_check_interrupts(void) +{ + if (MSR & MSR_EE) + { + if (ppc.interrupt_pending != 0) + { + if (ppc.interrupt_pending & 0x1) + { + ppc603_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc603_exception(EXCEPTION_DECREMENTER); + } + else if (ppc.interrupt_pending & 0x4) + { + ppc603_exception(EXCEPTION_SMI); + } + } + } +} + +void ppc_reset(void) +{ + ppc.pc = ppc.npc = 0xfff00100; + + ppc_set_msr(0x40); + ppc_change_pc(ppc.pc); + + ppc.hid0 = 1; + + ppc.interrupt_pending = 0; +} + +int ppc_execute(int cycles) +{ + UINT32 opcode; + ppc_icount = cycles; + ppc_tb_base_icount = cycles; + ppc_dec_base_icount = cycles + ppc.dec_frac; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - (cycles / (bus_freq_multiplier * 2))) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ((cycles / (bus_freq_multiplier * 2)) - DEC) * 4; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + ppc_change_pc(ppc.npc); + + /*{ + char string1[200]; + char string2[200]; + opcode = BSWAP32(*ppc.op); + DisassemblePowerPC(opcode, ppc.npc, string1, string2, TRUE); + printf("%08X: %s %s\n", ppc.npc, string1, string2); + }*/ + printf("trigger cycle %d (%08X)\n", ppc_dec_trigger_cycle, ppc_dec_trigger_cycle); + printf("tb = %08X %08X\n", (UINT32)(ppc.tb >> 32), (UINT32)(ppc.tb)); + + ppc603_check_interrupts(); + + while( ppc_icount > 0 ) + { + ppc.pc = ppc.npc; + + opcode = BSWAP32(*ppc.op++); + + ppc.npc = ppc.pc + 4; + switch(opcode >> 26) + { + case 19: optable19[(opcode >> 1) & 0x3ff](opcode); break; + case 31: optable31[(opcode >> 1) & 0x3ff](opcode); break; + case 59: optable59[(opcode >> 1) & 0x3ff](opcode); break; + case 63: optable63[(opcode >> 1) & 0x3ff](opcode); break; + default: optable[opcode >> 26](opcode); break; + } + + ppc_icount--; + + if(ppc_icount == ppc_dec_trigger_cycle) + { + printf("dec int at %d\n", ppc_icount); + ppc.interrupt_pending |= 0x2; + ppc603_check_interrupts(); + } + + //ppc603_check_interrupts(); + } + + // update timebase + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); + + // update decrementer + ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2)); + DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); + + /* + { + char string1[200]; + char string2[200]; + opcode = BSWAP32(*ppc.op); + DisassemblePowerPC(opcode, ppc.npc, string1, string2, TRUE); + printf("%08X: %s %s\n", ppc.npc, string1, string2); + } + */ + + return cycles - ppc_icount; +} diff --git a/ppc_itp/ppc_ops.c b/ppc_itp/ppc_ops.c new file mode 100644 index 0000000..8e577b0 --- /dev/null +++ b/ppc_itp/ppc_ops.c @@ -0,0 +1,2711 @@ +/* PowerPC common opcodes */ + +// it really seems like this should be elsewhere - like maybe the floating point checks can hang out someplace else +#include + +static void ppc_unimplemented(UINT32 op) +{ + error("ppc: Unimplemented opcode %08X at %08X", op, ppc.pc); +} + +static void ppc_addx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + + REG(RT) = ra + rb; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, rb); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_addcx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + + REG(RT) = ra + rb; + + SET_ADD_CA(REG(RT), ra, rb); + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, rb); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_addex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 tmp; + + tmp = rb + carry; + REG(RT) = ra + tmp; + + if( ADD_CA(tmp, rb, carry) || ADD_CA(REG(RT), ra, tmp) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, rb); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_addi(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 a = RA; + + if( a ) + i += REG(a); + + REG(RT) = i; +} + +static void ppc_addic(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 ra = REG(RA); + + REG(RT) = ra + i; + + if( ADD_CA(REG(RT), ra, i) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +static void ppc_addic_rc(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 ra = REG(RA); + + REG(RT) = ra + i; + + if( ADD_CA(REG(RT), ra, i) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + SET_CR0(REG(RT)); +} + +static void ppc_addis(UINT32 op) +{ + UINT32 i = UIMM16 << 16; + UINT32 a = RA; + + if( a ) + i += REG(a); + + REG(RT) = i; +} + +static void ppc_addmex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 tmp; + + tmp = ra + carry; + REG(RT) = tmp + -1; + + if( ADD_CA(tmp, ra, carry) || ADD_CA(REG(RT), tmp, -1) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, carry - 1); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_addzex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + + REG(RT) = ra + carry; + + if( ADD_CA(REG(RT), ra, carry) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, carry); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_andx(UINT32 op) +{ + REG(RA) = REG(RS) & REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_andcx(UINT32 op) +{ + REG(RA) = REG(RS) & ~REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_andi_rc(UINT32 op) +{ + UINT32 i = UIMM16; + + REG(RA) = REG(RS) & i; + + SET_CR0(REG(RA)); +} + +static void ppc_andis_rc(UINT32 op) +{ + UINT32 i = UIMM16 << 16; + + REG(RA) = REG(RS) & i; + + SET_CR0(REG(RA)); +} + +static void ppc_bx(UINT32 op) +{ + INT32 li = op & 0x3fffffc; + if( li & 0x2000000 ) + li |= 0xfc000000; + + if( AABIT ) { + ppc.npc = li; + } else { + ppc.npc = ppc.pc + li; + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } + + ppc_change_pc(ppc.npc); +} + +static void ppc_bcx(UINT32 op) +{ + int condition = check_condition_code(BO, BI); + + if( condition ) { + if( AABIT ) { + ppc.npc = SIMM16 & ~0x3; + } else { + ppc.npc = ppc.pc + (SIMM16 & ~0x3); + } + + ppc_change_pc(ppc.npc); + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_bcctrx(UINT32 op) +{ + int condition = check_condition_code(BO, BI); + + if( condition ) { + ppc.npc = CTR & ~0x3; + ppc_change_pc(ppc.npc); + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_bclrx(UINT32 op) +{ + int condition = check_condition_code(BO, BI); + + if( condition ) { + ppc.npc = LR & ~0x3; + ppc_change_pc(ppc.npc); + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_cmp(UINT32 op) +{ + INT32 ra = REG(RA); + INT32 rb = REG(RB); + int d = CRFD; + + if( ra < rb ) + CR(d) = 0x8; + else if( ra > rb ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cmpi(UINT32 op) +{ + INT32 ra = REG(RA); + INT32 i = SIMM16; + int d = CRFD; + + if( ra < i ) + CR(d) = 0x8; + else if( ra > i ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cmpl(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + int d = CRFD; + + if( ra < rb ) + CR(d) = 0x8; + else if( ra > rb ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cmpli(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 i = UIMM16; + int d = CRFD; + + if( ra < i ) + CR(d) = 0x8; + else if( ra > i ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cntlzw(UINT32 op) +{ + int n = 0; + int t = RT; + UINT32 m = 0x80000000; + + while(n < 32) + { + if( REG(t) & m ) + break; + m >>= 1; + n++; + } + + REG(RA) = n; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_crand(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) & CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crandc(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) & ~CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_creqv(UINT32 op) +{ + int bit = RT; + int b = ~(CRBIT(RA) ^ CRBIT(RB)); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crnand(UINT32 op) +{ + int bit = RT; + int b = ~(CRBIT(RA) & CRBIT(RB)); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crnor(UINT32 op) +{ + int bit = RT; + int b = ~(CRBIT(RA) | CRBIT(RB)); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_cror(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) | CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crorc(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) | ~CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crxor(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) ^ CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_dcbf(UINT32 op) +{ + +} + +static void ppc_dcbi(UINT32 op) +{ + +} + +static void ppc_dcbst(UINT32 op) +{ + +} + +static void ppc_dcbt(UINT32 op) +{ + +} + +static void ppc_dcbtst(UINT32 op) +{ + +} + +static void ppc_dcbz(UINT32 op) +{ + +} + +static void ppc_divwx(UINT32 op) +{ + if( REG(RB) == 0 && REG(RA) < 0x80000000 ) + { + REG(RT) = 0; + if( OEBIT ) { + XER |= XER_SO | XER_OV; + } + } + else if( REG(RB) == 0 || (REG(RB) == 0xffffffff && REG(RA) == 0x80000000) ) + { + REG(RT) = 0xffffffff; + if( OEBIT ) { + XER |= XER_SO | XER_OV; + } + } + else + { + REG(RT) = (INT32)REG(RA) / (INT32)REG(RB); + if( OEBIT ) { + XER &= ~XER_OV; + } + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_divwux(UINT32 op) +{ + if( REG(RB) == 0 ) + { + REG(RT) = 0; + if( OEBIT ) { + XER |= XER_SO | XER_OV; + } + } + else + { + REG(RT) = (UINT32)REG(RA) / (UINT32)REG(RB); + if( OEBIT ) { + XER &= ~XER_OV; + } + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_eieio(UINT32 op) +{ + +} + +static void ppc_eqvx(UINT32 op) +{ + REG(RA) = ~(REG(RS) ^ REG(RB)); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_extsbx(UINT32 op) +{ + REG(RA) = (INT32)(INT8)REG(RS); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_extshx(UINT32 op) +{ + REG(RA) = (INT32)(INT16)REG(RS); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_icbi(UINT32 op) +{ + +} + +static void ppc_isync(UINT32 op) +{ + +} + +static void ppc_lbz(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ8(ea); +} + +static void ppc_lbzu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ8(ea); + REG(RA) = ea; +} + +static void ppc_lbzux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ8(ea); + REG(RA) = ea; +} + +static void ppc_lbzx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ8(ea); +} + +static void ppc_lha(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = (INT32)(INT16)READ16(ea); +} + +static void ppc_lhau(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = (INT32)(INT16)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhaux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = (INT32)(INT16)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhax(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = (INT32)(INT16)READ16(ea); +} + +static void ppc_lhbrx(UINT32 op) +{ + UINT32 ea; + UINT16 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = READ16(ea); + REG(RT) = (UINT32)BYTE_REVERSE16(w); +} + +static void ppc_lhz(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ16(ea); +} + +static void ppc_lhzu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhzux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhzx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ16(ea); +} + +static void ppc_lmw(UINT32 op) +{ + int r = RT; + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + while( r <= 31 ) + { + REG(r) = READ32(ea); + ea += 4; + r++; + } +} + +static void ppc_lswi(UINT32 op) +{ + int n, r, i; + UINT32 ea = 0; + if( RA != 0 ) + ea = REG(RA); + + if( RB == 0 ) + n = 32; + else + n = RB; + + r = RT - 1; + i = 0; + + while(n > 0) + { + if (i == 0) { + r = (r + 1) % 32; + REG(r) = 0; + } + REG(r) |= ((READ8(ea) & 0xff) << (24 - i)); + i += 8; + if (i == 32) { + i = 0; + } + ea++; + n--; + } +} + +static void ppc_lswx(UINT32 op) +{ + error("ppc: lswx unimplemented at %08X", ppc.pc); +} + +static void ppc_lwarx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + ppc.reserved_address = ea; + ppc.reserved = 1; + + REG(RT) = READ32(ea); +} + +static void ppc_lwbrx(UINT32 op) +{ + UINT32 ea; + UINT32 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = READ32(ea); + REG(RT) = BYTE_REVERSE32(w); +} + +static void ppc_lwz(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = READ32(ea); +} + +static void ppc_lwzu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = READ32(ea); + REG(RA) = ea; +} + +static void ppc_lwzux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = READ32(ea); + REG(RA) = ea; +} + +static void ppc_lwzx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = READ32(ea); +} + +static void ppc_mcrf(UINT32 op) +{ + CR(RT >> 2) = CR(RA >> 2); +} + +static void ppc_mcrxr(UINT32 op) +{ + CR(RT >> 2) = (XER >> 28) & 0x0F; + XER &= ~0xf0000000; +} + +static void ppc_mfcr(UINT32 op) +{ + REG(RT) = ppc_get_cr(); +} + +static void ppc_mfmsr(UINT32 op) +{ + REG(RT) = ppc_get_msr(); +} + +static void ppc_mfspr(UINT32 op) +{ + REG(RT) = ppc_get_spr(SPR); +} + +static void ppc_mtcrf(UINT32 op) +{ + int fxm = FXM; + int t = RT; + + if( fxm & 0x80 ) CR(0) = (REG(t) >> 28) & 0xf; + if( fxm & 0x40 ) CR(1) = (REG(t) >> 24) & 0xf; + if( fxm & 0x20 ) CR(2) = (REG(t) >> 20) & 0xf; + if( fxm & 0x10 ) CR(3) = (REG(t) >> 16) & 0xf; + if( fxm & 0x08 ) CR(4) = (REG(t) >> 12) & 0xf; + if( fxm & 0x04 ) CR(5) = (REG(t) >> 8) & 0xf; + if( fxm & 0x02 ) CR(6) = (REG(t) >> 4) & 0xf; + if( fxm & 0x01 ) CR(7) = (REG(t) >> 0) & 0xf; +} + +static void ppc_mtmsr(UINT32 op) +{ + ppc_set_msr(REG(RS)); +} + +static void ppc_mtspr(UINT32 op) +{ + ppc_set_spr(SPR, REG(RS)); +} + +static void ppc_mulhwx(UINT32 op) +{ + INT64 ra = (INT64)(INT32)REG(RA); + INT64 rb = (INT64)(INT32)REG(RB); + + REG(RT) = (UINT32)((ra * rb) >> 32); + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_mulhwux(UINT32 op) +{ + UINT64 ra = (UINT64)REG(RA); + UINT64 rb = (UINT64)REG(RB); + + REG(RT) = (UINT32)((ra * rb) >> 32); + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_mulli(UINT32 op) +{ + INT32 ra = (INT32)REG(RA); + INT32 i = SIMM16; + + REG(RT) = ra * i; +} + +static void ppc_mullwx(UINT32 op) +{ + INT64 ra = (INT64)(INT32)REG(RA); + INT64 rb = (INT64)(INT32)REG(RB); + INT64 r; + + r = ra * rb; + REG(RT) = (UINT32)r; + + if( OEBIT ) { + XER &= ~XER_OV; + + if( r != (INT64)(INT32)r ) + XER |= XER_OV | XER_SO; + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_nandx(UINT32 op) +{ + REG(RA) = ~(REG(RS) & REG(RB)); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_negx(UINT32 op) +{ + REG(RT) = -(INT32)(REG(RA)); + + if( OEBIT ) { + if( REG(RT) == 0x80000000 ) + XER |= XER_OV | XER_SO; + else + XER &= ~XER_OV; + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_norx(UINT32 op) +{ + REG(RA) = ~(REG(RS) | REG(RB)); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_orx(UINT32 op) +{ + REG(RA) = REG(RS) | REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_orcx(UINT32 op) +{ + REG(RA) = REG(RS) | ~REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_ori(UINT32 op) +{ + REG(RA) = REG(RS) | UIMM16; +} + +static void ppc_oris(UINT32 op) +{ + REG(RA) = REG(RS) | (UIMM16 << 16); +} + +static void ppc_rfi(UINT32 op) +{ + UINT32 msr; + ppc.npc = ppc_get_spr(SPR_SRR0); + msr = ppc_get_spr(SPR_SRR1); + ppc_set_msr( msr ); + + ppc_change_pc(ppc.npc); +} + +static void ppc_rlwimix(UINT32 op) +{ + UINT32 r; + UINT32 mask = GET_ROTATE_MASK(MB, ME); + UINT32 rs = REG(RS); + int sh = SH; + + r = (rs << sh) | (rs >> (32-sh)); + REG(RA) = (REG(RA) & ~mask) | (r & mask); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_rlwinmx(UINT32 op) +{ + UINT32 r; + UINT32 mask = GET_ROTATE_MASK(MB, ME); + UINT32 rs = REG(RS); + int sh = SH; + + r = (rs << sh) | (rs >> (32-sh)); + REG(RA) = r & mask; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_rlwnmx(UINT32 op) +{ + UINT32 r; + UINT32 mask = GET_ROTATE_MASK(MB, ME); + UINT32 rs = REG(RS); + int sh = REG(RB) & 0x1f; + + r = (rs << sh) | (rs >> (32-sh)); + REG(RA) = r & mask; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_sc(UINT32 op) +{ + ppc603_exception(EXCEPTION_SYSTEM_CALL); +} + +static void ppc_slwx(UINT32 op) +{ + int sh = REG(RB) & 0x3f; + + if( sh > 31 ) { + REG(RA) = 0; + } + else { + REG(RA) = REG(RS) << sh; + } + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_srawx(UINT32 op) +{ + int sh = REG(RB) & 0x3f; + + XER &= ~XER_CA; + + if( sh > 31 ) { + if (REG(RS) & 0x80000000) + REG(RA) = 0xffffffff; + else + REG(RA) = 0; + if( REG(RA) ) + XER |= XER_CA; + } + else { + REG(RA) = (INT32)(REG(RS)) >> sh; + if( ((INT32)(REG(RS)) < 0) && (REG(RS) & BITMASK_0(sh)) ) + XER |= XER_CA; + } + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_srawix(UINT32 op) +{ + int sh = SH; + + XER &= ~XER_CA; + if( ((INT32)(REG(RS)) < 0) && (REG(RS) & BITMASK_0(sh)) ) + XER |= XER_CA; + + REG(RA) = (INT32)(REG(RS)) >> sh; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_srwx(UINT32 op) +{ + int sh = REG(RB) & 0x3f; + + if( sh > 31 ) { + REG(RA) = 0; + } + else { + REG(RA) = REG(RS) >> sh; + } + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_stb(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + WRITE8(ea, (UINT8)REG(RS)); +} + +static void ppc_stbu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + WRITE8(ea, (UINT8)REG(RS)); + REG(RA) = ea; +} + +static void ppc_stbux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + WRITE8(ea, (UINT8)REG(RS)); + REG(RA) = ea; +} + +static void ppc_stbx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + WRITE8(ea, (UINT8)REG(RS)); +} + +static void ppc_sth(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + WRITE16(ea, (UINT16)REG(RS)); +} + +static void ppc_sthbrx(UINT32 op) +{ + UINT32 ea; + UINT16 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = REG(RS); + WRITE16(ea, (UINT16)BYTE_REVERSE16(w)); +} + +static void ppc_sthu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + WRITE16(ea, (UINT16)REG(RS)); + REG(RA) = ea; +} + +static void ppc_sthux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + WRITE16(ea, (UINT16)REG(RS)); + REG(RA) = ea; +} + +static void ppc_sthx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + WRITE16(ea, (UINT16)REG(RS)); +} + +static void ppc_stmw(UINT32 op) +{ + UINT32 ea; + int r = RS; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + while( r <= 31 ) + { + WRITE32(ea, REG(r)); + ea += 4; + r++; + } +} + +static void ppc_stswi(UINT32 op) +{ + int n, r, i; + UINT32 ea = 0; + if( RA != 0 ) + ea = REG(RA); + + if( RB == 0 ) + n = 32; + else + n = RB; + + r = RT - 1; + i = 0; + + while(n > 0) + { + if (i == 0) { + r = (r + 1) % 32; + } + WRITE8(ea, (REG(r) >> (24-i)) & 0xff); + i += 8; + if (i == 32) { + i = 0; + } + ea++; + n--; + } +} + +static void ppc_stswx(UINT32 op) +{ + error("ppc: stswx unimplemented"); +} + +static void ppc_stw(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + WRITE32(ea, REG(RS)); +} + +static void ppc_stwbrx(UINT32 op) +{ + UINT32 ea; + UINT32 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = REG(RS); + WRITE32(ea, BYTE_REVERSE32(w)); +} + +static void ppc_stwcx_rc(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + /*if( ppc.reserved ) { + WRITE32(ea, REG(RS)); + + ppc.reserved = 0; + ppc.reserved_address = 0; + + CR(0) = 0x2; + if( XER & XER_SO ) + CR(0) |= 0x1; + } else*/ { + CR(0) = 0; + if( XER & XER_SO ) + CR(0) |= 0x1; + } +} + +static void ppc_stwu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + WRITE32(ea, REG(RS)); + REG(RA) = ea; +} + +static void ppc_stwux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + WRITE32(ea, REG(RS)); + REG(RA) = ea; +} + +static void ppc_stwx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + WRITE32(ea, REG(RS)); +} + +static void ppc_subfx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + REG(RT) = rb - ra; + + if( OEBIT ) { + SET_SUB_OV(REG(RT), rb, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_subfcx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + REG(RT) = rb - ra; + + SET_SUB_CA(REG(RT), rb, ra); + + if( OEBIT ) { + SET_SUB_OV(REG(RT), rb, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_subfex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 r; + + r = ~ra + carry; + REG(RT) = rb + r; + + SET_ADD_CA(r, ~ra, carry); /* step 1 carry */ + if( REG(RT) < r ) /* step 2 carry */ + XER |= XER_CA; + + if( OEBIT ) { + SET_SUB_OV(REG(RT), rb, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_subfic(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 ra = REG(RA); + + REG(RT) = i - ra; + + SET_SUB_CA(REG(RT), i, ra); +} + +static void ppc_subfmex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 r; + + r = ~ra + carry; + REG(RT) = r - 1; + + SET_SUB_CA(r, ~ra, carry); /* step 1 carry */ + if( REG(RT) < r ) + XER |= XER_CA; /* step 2 carry */ + + if( OEBIT ) { + SET_SUB_OV(REG(RT), -1, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_subfzex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + + REG(RT) = ~ra + carry; + + SET_ADD_CA(REG(RT), ~ra, carry); + + if( OEBIT ) { + SET_SUB_OV(REG(RT), 0, REG(RA)); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_sync(UINT32 op) +{ + +} + +static void ppc_tw(UINT32 op) +{ + int exception = 0; + INT32 a = REG(RA); + INT32 b = REG(RB); + int to = RT; + + if( (a < b) && (to & 0x10) ) { + exception = 1; + } + if( (a > b) && (to & 0x08) ) { + exception = 1; + } + if( (a == b) && (to & 0x04) ) { + exception = 1; + } + if( ((UINT32)a < (UINT32)b) && (to & 0x02) ) { + exception = 1; + } + if( ((UINT32)a > (UINT32)b) && (to & 0x01) ) { + exception = 1; + } + + if (exception) { + ppc603_exception(EXCEPTION_TRAP); + } +} + +static void ppc_twi(UINT32 op) +{ + int exception = 0; + INT32 a = REG(RA); + INT32 i = SIMM16; + int to = RT; + + if( (a < i) && (to & 0x10) ) { + exception = 1; + } + if( (a > i) && (to & 0x08) ) { + exception = 1; + } + if( (a == i) && (to & 0x04) ) { + exception = 1; + } + if( ((UINT32)a < (UINT32)i) && (to & 0x02) ) { + exception = 1; + } + if( ((UINT32)a > (UINT32)i) && (to & 0x01) ) { + exception = 1; + } + + if (exception) { + ppc603_exception(EXCEPTION_TRAP); + } +} + +static void ppc_xorx(UINT32 op) +{ + REG(RA) = REG(RS) ^ REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_xori(UINT32 op) +{ + REG(RA) = REG(RS) ^ UIMM16; +} + +static void ppc_xoris(UINT32 op) +{ + REG(RA) = REG(RS) ^ (UIMM16 << 16); +} + + + +static void ppc_invalid(UINT32 op) +{ + error("ppc: Invalid opcode %08X PC : %X, %08X", op, ppc.pc, ppc.npc); +} + + + +#define DOUBLE_SIGN (0x8000000000000000) +#define DOUBLE_EXP (0x7ff0000000000000) +#define DOUBLE_FRAC (0x000fffffffffffff) +#define DOUBLE_ZERO (0) + +/* + Floating point operations. +*/ + +INLINE int is_nan_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + +INLINE int is_qnan_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & 0x0007fffffffffff) == 0x000000000000000) && + ((x.id & 0x000800000000000) == 0x000800000000000) ); +} + +INLINE int is_snan_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) && + ((x.id & 0x0008000000000000) == DOUBLE_ZERO) ); +} + +INLINE int is_infinity_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & DOUBLE_FRAC) == DOUBLE_ZERO) ); +} + +INLINE int is_normalized_double(FPR x) +{ + UINT64 exp; + + exp = (x.id & DOUBLE_EXP) >> 52; + + return (exp >= 1) && (exp <= 2046); +} + +INLINE int is_denormalized_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == 0) && + ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + +INLINE int sign_double(FPR x) +{ + return ((x.id & DOUBLE_SIGN) != 0); +} + +INLINE INT64 round_to_nearest(FPR f) +{ + //return (INT64)(f.fd + 0.5); + if (f.fd >= 0) + { + return (INT64)(f.fd + 0.5); + } + else + { + return -(INT64)(-f.fd + 0.5); + } +} + +INLINE INT64 round_toward_zero(FPR f) +{ + return (INT64)(f.fd); +} + +INLINE INT64 round_toward_positive_infinity(FPR f) +{ + double r = ceil(f.fd); + return (INT64)(r); +} + +INLINE INT64 round_toward_negative_infinity(FPR f) +{ + double r = floor(f.fd); + return (INT64)(r); +} + + +INLINE void set_fprf(FPR f) +{ + UINT32 fprf; + + // see page 3-30, 3-31 + + if (is_qnan_double(f)) + { + fprf = 0x11; + } + else if (is_infinity_double(f)) + { + if (sign_double(f)) // -INF + fprf = 0x09; + else // +INF + fprf = 0x05; + } + else if (is_normalized_double(f)) + { + if (sign_double(f)) // -Normalized + fprf = 0x08; + else // +Normalized + fprf = 0x04; + } + else if (is_denormalized_double(f)) + { + if (sign_double(f)) // -Denormalized + fprf = 0x18; + else // +Denormalized + fprf = 0x14; + } + else // Zero + { + if (sign_double(f)) // -Zero + fprf = 0x12; + else // +Zero + fprf = 0x02; + } + + ppc.fpscr &= ~0x0001f000; + ppc.fpscr |= (fprf << 12); +} + + + +#define SET_VXSNAN(a, b) if (is_snan_double(a) || is_snan_double(b)) ppc.fpscr |= 0x80000000 +#define SET_VXSNAN_1(c) if (is_snan_double(c)) ppc.fpscr |= 0x80000000 + + + + +static void ppc_lfs(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); +} + +static void ppc_lfsu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); + + REG(a) = ea; +} + +static void ppc_lfd(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + FPR(t).id = READ64(ea); +} + +static void ppc_lfdu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 d = RD; + + ea += REG(a); + + FPR(d).id = READ64(ea); + + REG(a) = ea; +} + +static void ppc_stfs(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.f = (float)(FPR(t).fd); + WRITE32(ea, f.i); +} + +static void ppc_stfsu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.f = (float)(FPR(t).fd); + WRITE32(ea, f.i); + + REG(a) = ea; +} + +static void ppc_stfd(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + WRITE64(ea, FPR(t).id); +} + +static void ppc_stfdu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + + ea += REG(a); + + WRITE64(ea, FPR(t).id); + + REG(a) = ea; +} + +static void ppc_lfdux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 d = RD; + + ea += REG(a); + + FPR(d).id = READ64(ea); + + REG(a) = ea; +} + +static void ppc_lfdx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 d = RD; + + if(a) + ea += REG(a); + + FPR(d).id = READ64(ea); +} + +static void ppc_lfsux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); + + REG(a) = ea; +} + +static void ppc_lfsx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); +} + +static void ppc_mfsr(UINT32 op) +{ + UINT32 sr = (op >> 16) & 15; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + REG(t) = ppc.sr[sr]; +} + +static void ppc_mfsrin(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + REG(t) = ppc.sr[REG(b) >> 28]; +} + +static void ppc_mftb(UINT32 op) +{ + UINT32 x = SPRF; + + switch(x) + { + case 268: REG(RT) = (UINT32)(ppc_read_timebase()); break; + case 269: REG(RT) = (UINT32)(ppc_read_timebase() >> 32); break; + default: error("ppc: Invalid timebase register %d at %08X", x, ppc.pc); break; + } +} + +static void ppc_mtsr(UINT32 op) +{ + UINT32 sr = (op >> 16) & 15; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + ppc.sr[sr] = REG(t); +} + +static void ppc_mtsrin(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + ppc.sr[REG(b) >> 28] = REG(t); +} + +static void ppc_dcba(UINT32 op) +{ + /* TODO: Cache not emulated so this opcode doesn't need to be implemented */ +} + +static void ppc_stfdux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + + ea += REG(a); + + WRITE64(ea, FPR(t).id); + + REG(a) = ea; +} + +static void ppc_stfdx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + WRITE64(ea, FPR(t).id); +} + +static void ppc_stfiwx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + WRITE32(ea, (UINT32)FPR(t).id); +} + +static void ppc_stfsux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.f = (float)(FPR(t).fd); + WRITE32(ea, f.i); + + REG(a) = ea; +} + +static void ppc_stfsx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.f = (float)(FPR(t).fd); + + WRITE32(ea, f.i); +} + +static void ppc_tlbia(UINT32 op) +{ + /* TODO: TLB not emulated so this opcode doesn't need to implemented */ +} + +static void ppc_tlbie(UINT32 op) +{ + /* TODO: TLB not emulated so this opcode doesn't need to implemented */ +} + +static void ppc_tlbsync(UINT32 op) +{ + /* TODO: TLB not emulated so this opcode doesn't need to implemented */ +} + +static void ppc_eciwx(UINT32 op) +{ + ppc_unimplemented(op); +} + +static void ppc_ecowx(UINT32 op) +{ + ppc_unimplemented(op); +} + +static void ppc_fabsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).id = FPR(b).id & ~DOUBLE_SIGN; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_faddx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = FPR(a).fd + FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fcmpo(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = (RT >> 2); + UINT32 c; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + if(is_nan_double(FPR(a)) || is_nan_double(FPR(b))) + { + c = 1; /* OX */ + if(is_snan_double(FPR(a)) || is_snan_double(FPR(b))) { + ppc.fpscr |= 0x01000000; /* VXSNAN */ + + if(!(ppc.fpscr & 0x40000000) || is_qnan_double(FPR(a)) || is_qnan_double(FPR(b))) + ppc.fpscr |= 0x00080000; /* VXVC */ + } + } + else if(FPR(a).fd < FPR(b).fd){ + c = 8; /* FX */ + } + else if(FPR(a).fd > FPR(b).fd){ + c = 4; /* FEX */ + } + else { + c = 2; /* VX */ + } + + CR(t) = c; + + // TODO + //ppc.fpscr &= ~0x0001F000; + //ppc.fpscr |= (c << 12); +} + +static void ppc_fcmpu(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = (RT >> 2); + UINT32 c; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + if(is_nan_double(FPR(a)) || is_nan_double(FPR(b))) + { + c = 1; /* OX */ + if(is_snan_double(FPR(a)) || is_snan_double(FPR(b))) { + ppc.fpscr |= 0x01000000; /* VXSNAN */ + } + } + else if(FPR(a).fd < FPR(b).fd){ + c = 8; /* FX */ + } + else if(FPR(a).fd > FPR(b).fd){ + c = 4; /* FEX */ + } + else { + c = 2; /* VX */ + } + + CR(t) = c; + + // TODO + //ppc.fpscr &= ~0x0001F000; + //ppc.fpscr |= (c << 12); +} + +static void ppc_fctiwx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + INT64 r = 0; + + // TODO: fix FPSCR flags FX,VXSNAN,VXCVI + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + + switch(ppc.fpscr & 3) + { + case 0: r = (INT64)round_to_nearest(FPR(b)); break; + case 1: r = (INT64)round_toward_zero(FPR(b)); break; + case 2: r = (INT64)round_toward_positive_infinity(FPR(b)); break; + case 3: r = (INT64)round_toward_negative_infinity(FPR(b)); break; + } + + if(r > (INT64)((INT32)0x7FFFFFFF)) + { + FPR(t).id = 0x7FFFFFFF; + // FPSCR[FR] = 0 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + } + else if(FPR(b).fd < (INT64)((INT32)0x80000000)) + { + FPR(t).id = 0x80000000; + // FPSCR[FR] = 1 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + } + else + { + FPR(t).id = (UINT32)(r); + // FPSCR[FR] = t.iw > t.fd + // FPSCR[FI] = t.iw == t.fd + // FPSCR[XX] = ? + } + + // FPSCR[FPRF] = undefined (leave it as is) + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fctiwzx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + INT64 r; + + // TODO: fix FPSCR flags FX,VXSNAN,VXCVI + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + r = round_toward_zero(FPR(b)); + + if(r > (INT64)((INT32)0x7fffffff)) + { + FPR(t).id = 0x7fffffff; + // FPSCR[FR] = 0 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + + } + else if(r < (INT64)((INT32)0x80000000)) + { + FPR(t).id = 0x80000000; + // FPSCR[FR] = 1 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + } + else + { + FPR(t).id = (UINT32)r; + // FPSCR[FR] = t.iw > t.fd + // FPSCR[FI] = t.iw == t.fd + // FPSCR[XX] = ? + } + + // FPSCR[FPRF] = undefined (leave it as is) + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fdivx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = FPR(a).fd / FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmrx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).fd = FPR(b).fd; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnabsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).id = FPR(b).id | DOUBLE_SIGN; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnegx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).id = FPR(b).id ^ DOUBLE_SIGN; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_frspx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = (float)FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_frsqrtex(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = 1.0 / sqrt(FPR(b).fd); /* verify this */ + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsqrtx(UINT32 op) +{ + /* NOTE: PPC603e doesn't support this opcode */ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = (double)(sqrt(FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsubx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = FPR(a).fd - FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mffsx(UINT32 op) +{ + FPR(RT).id = (UINT32)ppc.fpscr; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsb0x(UINT32 op) +{ + UINT32 crbD; + + crbD = (op >> 21) & 0x1F; + + if (crbD != 1 && crbD != 2) // these bits cannot be explicitly cleared + ppc.fpscr &= ~(1 << (31 - crbD)); + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsb1x(UINT32 op) +{ + UINT32 crbD; + + crbD = (op >> 21) & 0x1F; + + if (crbD != 1 && crbD != 2) // these bits cannot be explicitly cleared + ppc.fpscr |= (1 << (31 - crbD)); + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsfx(UINT32 op) +{ + UINT32 b = RB; + UINT32 f = FM; + + f = ppc_field_xlat[FM]; + + ppc.fpscr &= (~f) | ~(FPSCR_FEX | FPSCR_VX); + ppc.fpscr |= (UINT32)(FPR(b).id) & ~(FPSCR_FEX | FPSCR_VX); + + // FEX, VX + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsfix(UINT32 op) +{ + UINT32 crfd = CRFD; + UINT32 imm = (op >> 12) & 0xF; + + /* + * According to the manual: + * + * If bits 0 and 3 of FPSCR are to be modified, they take the immediate + * value specified. Bits 1 and 2 (FEX and VX) are set according to the + * "usual rule" and not from IMM[1-2]. + * + * The "usual rule" is not emulated, so these bits simply aren't modified + * at all here. + */ + + crfd = (7 - crfd) * 4; // calculate LSB position of field + + if (crfd == 28) // field containing FEX and VX is special... + { // bits 1 and 2 of FPSCR must not be altered + ppc.fpscr &= 0x9fffffff; + ppc.fpscr |= (imm & 0x9fffffff); + } + + ppc.fpscr &= ~(0xf << crfd); // clear field + ppc.fpscr |= (imm << crfd); // insert new data + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mcrfs(UINT32 op) +{ + UINT32 crfs, f; + crfs = CRFA; + + f = ppc.fpscr >> ((7 - crfs) * 4); // get crfS field from FPSCR + f &= 0xf; + + switch(crfs) // determine which exception bits to clear in FPSCR + { + case 0: // FX, OX + ppc.fpscr &= ~0x90000000; + break; + case 1: // UX, ZX, XX, VXSNAN + ppc.fpscr &= ~0x0f000000; + break; + case 2: // VXISI, VXIDI, VXZDZ, VXIMZ + ppc.fpscr &= ~0x00F00000; + break; + case 3: // VXVC + ppc.fpscr &= ~0x00080000; + break; + case 5: // VXSOFT, VXSQRT, VXCVI + ppc.fpscr &= ~0x00000e00; + break; + default: + break; + } + + CR(CRFD) = f; +} + +static void ppc_faddsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = (float)(FPR(a).fd + FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fdivsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = (float)(FPR(a).fd / FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fresx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = 1.0 / FPR(b).fd; /* ??? */ + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsqrtsx(UINT32 op) +{ + /* NOTE: This opcode is not supported in PPC603e */ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = (float)(sqrt(FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsubsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = (float)(FPR(a).fd - FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmaddx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = ((FPR(a).fd * FPR(c).fd) + FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmsubx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = ((FPR(a).fd * FPR(c).fd) - FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmulx(UINT32 op) +{ + UINT32 c = RC; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(c)); + + FPR(t).fd = (FPR(a).fd * FPR(c).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmaddx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (-((FPR(a).fd * FPR(c).fd) + FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmsubx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (-((FPR(a).fd * FPR(c).fd) - FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fselx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).fd = (FPR(a).fd >= 0.0) ? FPR(c).fd : FPR(b).fd; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmaddsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)((FPR(a).fd * FPR(c).fd) + FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmsubsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)((FPR(a).fd * FPR(c).fd) - FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmulsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + //SET_VXSNAN(FPR(a), FPR(c)); + + FPR(t).fd = (float)(FPR(a).fd * FPR(c).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmaddsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)(-((FPR(a).fd * FPR(c).fd) + FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmsubsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + //SET_VXSNAN(FPR(a), FPR(b)); + //SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)(-((FPR(a).fd * FPR(c).fd) - FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} diff --git a/ppc_itp/ppc_ops.h b/ppc_itp/ppc_ops.h new file mode 100644 index 0000000..32d05a8 --- /dev/null +++ b/ppc_itp/ppc_ops.h @@ -0,0 +1,143 @@ +static PPC_OPCODE ppc_opcode_common[] = +{ + /*code subcode handler */ + { 31, 266, ppc_addx }, + { 31, 266 | 512, ppc_addx }, + { 31, 10, ppc_addcx }, + { 31, 10 | 512, ppc_addcx }, + { 31, 138, ppc_addex }, + { 31, 138 | 512, ppc_addex }, + { 14, -1, ppc_addi }, + { 12, -1, ppc_addic }, + { 13, -1, ppc_addic_rc }, + { 15, -1, ppc_addis }, + { 31, 234, ppc_addmex }, + { 31, 234 | 512, ppc_addmex }, + { 31, 202, ppc_addzex }, + { 31, 202 | 512, ppc_addzex }, + { 31, 28, ppc_andx }, + { 31, 28 | 512, ppc_andx }, + { 31, 60, ppc_andcx }, + { 28, -1, ppc_andi_rc }, + { 29, -1, ppc_andis_rc }, + { 18, -1, ppc_bx }, + { 16, -1, ppc_bcx }, + { 19, 528, ppc_bcctrx }, + { 19, 16, ppc_bclrx }, + { 31, 0, ppc_cmp }, + { 11, -1, ppc_cmpi }, + { 31, 32, ppc_cmpl }, + { 10, -1, ppc_cmpli }, + { 31, 26, ppc_cntlzw }, + { 19, 257, ppc_crand }, + { 19, 129, ppc_crandc }, + { 19, 289, ppc_creqv }, + { 19, 225, ppc_crnand }, + { 19, 33, ppc_crnor }, + { 19, 449, ppc_cror }, + { 19, 417, ppc_crorc }, + { 19, 193, ppc_crxor }, + { 31, 86, ppc_dcbf }, + { 31, 470, ppc_dcbi }, + { 31, 54, ppc_dcbst }, + { 31, 278, ppc_dcbt }, + { 31, 246, ppc_dcbtst }, + { 31, 1014, ppc_dcbz }, + { 31, 491, ppc_divwx }, + { 31, 491 | 512, ppc_divwx }, + { 31, 459, ppc_divwux }, + { 31, 459 | 512, ppc_divwux }, + { 31, 854, ppc_eieio }, + { 31, 284, ppc_eqvx }, + { 31, 954, ppc_extsbx }, + { 31, 922, ppc_extshx }, + { 31, 982, ppc_icbi }, + { 19, 150, ppc_isync }, + { 34, -1, ppc_lbz }, + { 35, -1, ppc_lbzu }, + { 31, 119, ppc_lbzux }, + { 31, 87, ppc_lbzx }, + { 42, -1, ppc_lha }, + { 43, -1, ppc_lhau }, + { 31, 375, ppc_lhaux }, + { 31, 343, ppc_lhax }, + { 31, 790, ppc_lhbrx }, + { 40, -1, ppc_lhz }, + { 41, -1, ppc_lhzu }, + { 31, 311, ppc_lhzux }, + { 31, 279, ppc_lhzx }, + { 46, -1, ppc_lmw }, + { 31, 597, ppc_lswi }, + { 31, 533, ppc_lswx }, + { 31, 20, ppc_lwarx }, + { 31, 534, ppc_lwbrx }, + { 32, -1, ppc_lwz }, + { 33, -1, ppc_lwzu }, + { 31, 55, ppc_lwzux }, + { 31, 23, ppc_lwzx }, + { 19, 0, ppc_mcrf }, + { 31, 512, ppc_mcrxr }, + { 31, 19, ppc_mfcr }, + { 31, 83, ppc_mfmsr }, + { 31, 339, ppc_mfspr }, + { 31, 144, ppc_mtcrf }, + { 31, 146, ppc_mtmsr }, + { 31, 467, ppc_mtspr }, + { 31, 75, ppc_mulhwx }, + { 31, 11, ppc_mulhwux }, + { 7, -1, ppc_mulli }, + { 31, 235, ppc_mullwx }, + { 31, 235 | 512, ppc_mullwx }, + { 31, 476, ppc_nandx }, + { 31, 104, ppc_negx }, + { 31, 104 | 512, ppc_negx }, + { 31, 124, ppc_norx }, + { 31, 444, ppc_orx }, + { 31, 412, ppc_orcx }, + { 24, -1, ppc_ori }, + { 25, -1, ppc_oris }, + { 19, 50, ppc_rfi }, + { 20, -1, ppc_rlwimix }, + { 21, -1, ppc_rlwinmx }, + { 23, -1, ppc_rlwnmx }, + { 17, -1, ppc_sc }, + { 31, 24, ppc_slwx }, + { 31, 792, ppc_srawx }, + { 31, 824, ppc_srawix }, + { 31, 536, ppc_srwx }, + { 38, -1, ppc_stb }, + { 39, -1, ppc_stbu }, + { 31, 247, ppc_stbux }, + { 31, 215, ppc_stbx }, + { 44, -1, ppc_sth }, + { 31, 918, ppc_sthbrx }, + { 45, -1, ppc_sthu }, + { 31, 439, ppc_sthux }, + { 31, 407, ppc_sthx }, + { 47, -1, ppc_stmw }, + { 31, 725, ppc_stswi }, + { 31, 661, ppc_stswx }, + { 36, -1, ppc_stw }, + { 31, 662, ppc_stwbrx }, + { 31, 150, ppc_stwcx_rc }, + { 37, -1, ppc_stwu }, + { 31, 183, ppc_stwux }, + { 31, 151, ppc_stwx }, + { 31, 40, ppc_subfx }, + { 31, 40 | 512, ppc_subfx }, + { 31, 8, ppc_subfcx }, + { 31, 8 | 512, ppc_subfcx }, + { 31, 136, ppc_subfex }, + { 31, 136 | 512, ppc_subfex }, + { 8, -1, ppc_subfic }, + { 31, 232, ppc_subfmex }, + { 31, 232 | 512, ppc_subfmex }, + { 31, 200, ppc_subfzex }, + { 31, 200 | 512, ppc_subfzex }, + { 31, 598, ppc_sync }, + { 31, 4, ppc_tw }, + { 3, -1, ppc_twi }, + { 31, 316, ppc_xorx }, + { 26, -1, ppc_xori }, + { 27, -1, ppc_xoris } +}; diff --git a/unzip/unzip.c b/unzip/unzip.c new file mode 100644 index 0000000..609c44c --- /dev/null +++ b/unzip/unzip.c @@ -0,0 +1,1298 @@ +/* unzip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read unzip.h for more info +*/ + + +#include // these 2 lines added by Bart Trzynadlowski +#include "unzip.h" // (Nov. 7, 2001) + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +const char unz_copyright[] = + " unzip 0.15 Copyright 1998 Gilles Vollant "; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte(fin,pi) + FILE *fin; + int *pi; +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir(fin) + FILE *fin; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen (path) + const char *path; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ +/* int err=UNZ_OK; */ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/unzip/unzip.h b/unzip/unzip.h new file mode 100644 index 0000000..c7ba82a --- /dev/null +++ b/unzip/unzip.h @@ -0,0 +1,274 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/win32/dx9_renderer.c b/win32/dx9_renderer.c new file mode 100644 index 0000000..d80ef38 --- /dev/null +++ b/win32/dx9_renderer.c @@ -0,0 +1,1712 @@ +/******************************************************************/ +/* DirectX 9 Renderer */ +/******************************************************************/ + +#include "model3.h" +#include +#include +#include + +#define EXTERNAL_SHADERS 0 + +static float min_z; +static float max_z; + + +#if EXTERNAL_SHADERS + +static LPCTSTR vs_filename = "vertex_shader.vs"; +static LPCTSTR ps_filename = "pixel_shader.ps"; +static LPCTSTR vs2d_filename = "vertex_shader_2d.vs"; +static LPCTSTR ps2d_filename = "pixel_shader_2d.ps"; + +#else + +#include "shaders.h" + +#endif + + +D3DXMATRIX d3d_matrix_stack_get_top(void); +void d3d_matrix_stack_init(void); + +typedef struct +{ + float x; + float y; + float width; + float height; +} VIEWPORT_PARAMS; + +typedef struct +{ + D3DXVECTOR4 sun_vector; + D3DXVECTOR4 sun_params; +} LIGHTING_PARAMS; + +#define MAX_VIEWPORTS 32 +#define MAX_LIGHTS 32 + +static int current_viewport; +static int current_light; +static int num_viewports; +static int num_lights; + +static VIEWPORT_PARAMS viewport_params[MAX_VIEWPORTS]; +static LIGHTING_PARAMS lighting_params[MAX_LIGHTS]; + + +#define MESH_STATIC 0 +#define MESH_DYNAMIC 1 + +typedef struct +{ + D3DMATRIX transform; + D3DMATRIX normal; + + int mesh_index; + int viewport; + int lighting; +} MESH; + +typedef struct +{ + int vb_index; + int num_vertices; + int vb_index_alpha; + int num_vertices_alpha; +} MESH_CACHE; + +#define DYNAMIC_VB_SIZE 180000 +#define STATIC_VB_SIZE 1000000 + +#define NUM_DYNAMIC_MESHES 2048 +#define NUM_STATIC_MESHES 32768 + +#define DYNAMIC_MESH_BUFFER_SIZE 2048 +#define STATIC_MESH_BUFFER_SIZE 65536 + +typedef struct +{ + float x, y, z; + float u, v; + float nx, ny, nz; + float tx, ty, twidth, theight; + D3DCOLOR color, color2; +} VERTEX; + +D3DVERTEXELEMENT9 vertex_decl[] = +{ + {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + {0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, + {0, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, + {0, 48, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, + {0, 52, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, + D3DDECL_END() +}; + + + +typedef struct +{ + float x, y, z, w; + float u, v; +} VERTEX_2D; + +const DWORD VERTEX2D_FVF = (D3DFVF_XYZRHW | D3DFVF_TEX1 ); + +D3DVERTEXELEMENT9 vertex_decl_2d[] = +{ + {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + D3DDECL_END() +}; + + + +static LPDIRECT3D9 d3d; +static LPDIRECT3DDEVICE9 device; + +static D3DCAPS9 device_caps; + +static LPDIRECT3DTEXTURE9 texture; +static LPDIRECT3DVERTEXBUFFER9 dynamic_vb; +static LPDIRECT3DVERTEXBUFFER9 static_vb; +static LPDIRECT3DVERTEXBUFFER9 dynamic_vb_alpha; +static LPDIRECT3DVERTEXBUFFER9 static_vb_alpha; +static LPDIRECT3DVERTEXSHADER9 vshader; +static LPDIRECT3DPIXELSHADER9 pshader; +static LPDIRECT3DVERTEXDECLARATION9 vertex_declaration; + +static LPDIRECT3DTEXTURE9 texture_2d[4]; +static LPDIRECT3DTEXTURE9 palette_2d; +static LPDIRECT3DTEXTURE9 priority_2d[4]; +static LPDIRECT3DVERTEXBUFFER9 vb_2d; +static LPDIRECT3DVERTEXSHADER9 vshader_2d; +static LPDIRECT3DPIXELSHADER9 pshader_2d; +static LPDIRECT3DVERTEXDECLARATION9 vertex_declaration_2d; + +static LPD3DXMATRIXSTACK matrix_stack; + +static LPDIRECT3DTEXTURE9 lightgun_cursor; + +static LPD3DXFONT font; + +static D3DMATRIX world_matrix; +static D3DMATRIX view_matrix; +static D3DMATRIX projection_matrix; + +static D3DVIEWPORT9 viewport; + +static char num_bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + +static HWND main_window; +static HFONT hfont; + +static UINT32 matrix_start; + +static MESH_CACHE *static_mesh_cache; +static MESH_CACHE *dynamic_mesh_cache; + +static int static_mesh_cache_top = 0; +static int dynamic_mesh_cache_top = 0; + +static int dynamic_mesh_cache_vertex_top = 0; +static int dynamic_mesh_cache_vertex_top_alpha = 0; +static int static_mesh_cache_vertex_top = 0; +static int static_mesh_cache_vertex_top_alpha = 0; + +static MESH *static_mesh_buffer; +static int static_mesh_buffer_top = 0; +static MESH *dynamic_mesh_buffer; +static int dynamic_mesh_buffer_top = 0; + +static int listdone = 0; + +static D3DXVECTOR4 sun_vector; +static D3DXVECTOR4 sun_params; + +static BOOL traverse_node(UINT32); +static BOOL traverse_list(UINT32); +static BOOL render_scene(void); +static UINT32* get_address(UINT32); + + +static UINT16 *static_mesh_index; + + +static void d3d_shutdown(void) +{ + if(d3d) { + IDirect3D9_Release(d3d); + d3d = NULL; + } +} + +BOOL d3d_pre_init(void) +{ + HRESULT hr; + D3DDISPLAYMODE d3ddm; + D3DADAPTER_IDENTIFIER9 adapter_identifier; + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + if (!d3d) + { + message(0, "Direct3DCreate9 failed.\n"); + return FALSE; + } + + hr = IDirect3D9_GetAdapterDisplayMode(d3d, D3DADAPTER_DEFAULT, &d3ddm); + if (FAILED(hr)) + { + message(0, "d3d->GetAdapterDisplayMode failed.\n"); + return FALSE; + } + + hr = IDirect3D9_GetDeviceCaps(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &device_caps); + if (FAILED(hr)) + { + message(0, "d3d->GetDeviceCaps failed.\n"); + return FALSE; + } + + hr = IDirect3D9_GetAdapterIdentifier(d3d, D3DADAPTER_DEFAULT, 0, &adapter_identifier); + if (FAILED(hr)) + { + message(0, "d3d->GetAdapterIdentifier failed.\n"); + return FALSE; + } + + message(0, "Video card: %s", adapter_identifier.Description); + + if (device_caps.VertexShaderVersion < D3DVS_VERSION(3,0)) + { + message(0, "The video card doesn't support Vertex Shader 3.0\n"); + return FALSE; + } + if (device_caps.PixelShaderVersion < D3DPS_VERSION(3,0)) + { + message(0, "The video card doesn't support Pixel Shader 3.0\n"); + return FALSE; + } + + return TRUE; +} + +BOOL d3d_init(HWND main_window) +{ + D3DPRESENT_PARAMETERS d3dpp; + LPD3DXBUFFER vsh, psh, errors; + HRESULT hr; + DWORD flags = 0; + int width, height; + int i; + + if (m3_config.fullscreen) + { + width = m3_config.width; + height = m3_config.height; + } + else + { + width = 496; + height = 384; + } + + // Check if we have a valid display mode + if (width == 0 || height == 0) + return FALSE; + + memset(&d3dpp, 0, sizeof(d3dpp)); + d3dpp.Windowed = m3_config.fullscreen ? FALSE : TRUE; + d3dpp.SwapEffect = m3_config.stretch ? D3DSWAPEFFECT_COPY : D3DSWAPEFFECT_FLIP; + d3dpp.BackBufferWidth = width; + d3dpp.BackBufferHeight = height; + d3dpp.BackBufferCount = m3_config.stretch ? 1 : 2; + d3dpp.hDeviceWindow = main_window; + d3dpp.PresentationInterval = m3_config.fullscreen ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8; + + if (device_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) + { + flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; + } + else + { + flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window, flags, &d3dpp, &device); + if(FAILED(hr)) + { + return FALSE; + } + + // create vertex buffers for dynamic vertex data + hr = IDirect3DDevice9_CreateVertexBuffer(device, + DYNAMIC_VB_SIZE * sizeof(VERTEX), D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &dynamic_vb, NULL); + if (FAILED(hr)) + { + message(0, "d3d->CreateVertexBuffer failed\n"); + return FALSE; + } + hr = IDirect3DDevice9_CreateVertexBuffer(device, + DYNAMIC_VB_SIZE * sizeof(VERTEX), D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &dynamic_vb_alpha, NULL); + if (FAILED(hr)) + { + message(0, "d3d->CreateVertexBuffer failed\n"); + return FALSE; + } + + // create vertex buffers for static vertex data + hr = IDirect3DDevice9_CreateVertexBuffer(device, + STATIC_VB_SIZE * sizeof(VERTEX), 0, 0, D3DPOOL_MANAGED, &static_vb, NULL); + if (FAILED(hr)) + { + message(0, "d3d->CreateVertexBuffer failed\n"); + return FALSE; + } + hr = IDirect3DDevice9_CreateVertexBuffer(device, + STATIC_VB_SIZE * sizeof(VERTEX), 0, 0, D3DPOOL_MANAGED, &static_vb_alpha, NULL); + if (FAILED(hr)) + { + message(0, "d3d->CreateVertexBuffer failed\n"); + return FALSE; + } + +#if EXTERNAL_SHADERS + // create vertex shader + hr = D3DXAssembleShaderFromFile(vs_filename, NULL, NULL, 0, &vsh, &errors); + if (FAILED(hr)) + { + message(0, "Direct3D error: %s", errors->lpVtbl->GetBufferPointer(errors)); + return FALSE; + } + hr = IDirect3DDevice9_CreateVertexShader(device, (DWORD*)vsh->lpVtbl->GetBufferPointer(vsh), &vshader); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreateVertexShader failed."); + return FALSE; + } + + // create pixel shader + hr = D3DXAssembleShaderFromFile(ps_filename, NULL, NULL, 0, &psh, &errors); + if (FAILED(hr)) + { + message(0, "Direct3D error: %s", errors->lpVtbl->GetBufferPointer(errors)); + return FALSE; + } + hr = IDirect3DDevice9_CreatePixelShader(device, (DWORD*)psh->lpVtbl->GetBufferPointer(psh), &pshader); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreatePixelShader failed."); + return FALSE; + } +#else + // create vertex shader + hr = IDirect3DDevice9_CreateVertexShader(device, (DWORD*)vertex_shader_source, &vshader); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreateVertexShader failed."); + return FALSE; + } + + // create pixel shader + hr = IDirect3DDevice9_CreatePixelShader(device, (DWORD*)pixel_shader_source, &pshader); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreatePixelShader failed."); + return FALSE; + } +#endif + + // create vertex declarations + hr = IDirect3DDevice9_CreateVertexDeclaration(device, vertex_decl, &vertex_declaration); + if (FAILED(hr)) + { + message(0, "IDirect3DDevice9_CreateVertexDeclaration failed."); + return FALSE; + } + + // create textures + hr = IDirect3DDevice9_CreateTexture(device, 2048, 4096, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture, NULL); + if (FAILED(hr)) + { + message(0, "IDirect3DDevice9_CreateTexture failed."); + return FALSE; + } + + dynamic_mesh_buffer = (MESH*)malloc(sizeof(MESH) * DYNAMIC_MESH_BUFFER_SIZE); + static_mesh_buffer = (MESH*)malloc(sizeof(MESH) * STATIC_MESH_BUFFER_SIZE); + + dynamic_mesh_cache = (MESH_CACHE*)malloc(sizeof(MESH_CACHE) * NUM_DYNAMIC_MESHES); + static_mesh_cache = (MESH_CACHE*)malloc(sizeof(MESH_CACHE) * NUM_STATIC_MESHES); + + static_mesh_index = (UINT16*)malloc(sizeof(UINT16) * 16777216); + for (i=0; i < 16777216; i++) + { + static_mesh_index[i] = 0xffff; + } + + { + ///////////////////////////// + // 2D layers // + ///////////////////////////// + + VERTEX_2D *vb; + + // create vertex shader and pixel shader for 2D +#if EXTERNAL_SHADERS + // create vertex shader + hr = D3DXAssembleShaderFromFile(vs2d_filename, NULL, NULL, 0, &vsh, &errors); + if (FAILED(hr)) + { + message(0, "Direct3D error: %s", errors->lpVtbl->GetBufferPointer(errors)); + return FALSE; + } + hr = IDirect3DDevice9_CreateVertexShader(device, (DWORD*)vsh->lpVtbl->GetBufferPointer(vsh), &vshader_2d); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreateVertexShader failed."); + return FALSE; + } + + // create pixel shader + hr = D3DXAssembleShaderFromFile(ps2d_filename, NULL, NULL, 0, &psh, &errors); + if (FAILED(hr)) + { + message(0, "Direct3D error: %s", errors->lpVtbl->GetBufferPointer(errors)); + return FALSE; + } + hr = IDirect3DDevice9_CreatePixelShader(device, (DWORD*)psh->lpVtbl->GetBufferPointer(psh), &pshader_2d); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreatePixelShader failed."); + return FALSE; + } +#else + // create vertex shader + hr = IDirect3DDevice9_CreateVertexShader(device, (DWORD*)vertex_shader_2d_source, &vshader_2d); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreateVertexShader failed."); + return FALSE; + } + + // create pixel shader + hr = IDirect3DDevice9_CreatePixelShader(device, (DWORD*)pixel_shader_2d_source, &pshader_2d); + if (FAILED(hr)) + { + message(0, "Direct3D error: IDirect3DDevice9_CreatePixelShader failed."); + return FALSE; + } +#endif + + // create vertex declarations + hr = IDirect3DDevice9_CreateVertexDeclaration(device, vertex_decl, &vertex_declaration_2d); + if (FAILED(hr)) + { + message(0, "IDirect3DDevice9_CreateVertexDeclaration failed."); + return FALSE; + } + + // create textures for 2d layers + for (i=0; i < 4; i++) + { + hr = IDirect3DDevice9_CreateTexture(device, + 512, 512, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8L8, D3DPOOL_DEFAULT, &texture_2d[i], NULL); + if (FAILED(hr)) + { + message(0, "IDirect3DDevice9_CreateTexture failed."); + return FALSE; + } + + // priority + hr = IDirect3DDevice9_CreateTexture(device, + 1, 512, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &priority_2d[i], NULL); + if (FAILED(hr)) + { + message(0, "IDirect3DDevice9_CreateTexture failed."); + return FALSE; + } + } + + // create texture for palette + hr = IDirect3DDevice9_CreateTexture(device, + 256, 256, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &palette_2d, NULL); + if (FAILED(hr)) + { + message(0, "IDirect3DDevice9_CreateTexture failed."); + return FALSE; + } + + + + // create vertex buffer for 2d layers + hr = IDirect3DDevice9_CreateVertexBuffer(device, 4 * sizeof(VERTEX_2D), 0, 0, D3DPOOL_MANAGED, &vb_2d, NULL); + if (FAILED(hr)) + { + message(0, "d3d->CreateVertexBuffer failed\n"); + return FALSE; + } + + // fill in the vertex data + IDirect3DVertexBuffer9_Lock(vb_2d, 0, 0, (void **)&vb, D3DLOCK_DISCARD); + + vb[0].x = 0.0f; vb[0].y = 0.0f; vb[0].z = 1.0f; vb[0].w = 1.0f; + vb[0].u = 0.0f; vb[0].v = 0.0f; + vb[1].x = 512.0f; vb[1].y = 0.0f; vb[1].z = 1.0f; vb[1].w = 1.0f; + vb[1].u = 1.0f; vb[1].v = 0.0f; + vb[2].x = 512.0f; vb[2].y = 512.0f; vb[2].z = 1.0f; vb[2].w = 1.0f; + vb[2].u = 1.0f; vb[2].v = 1.0f; + vb[3].x = 0.0f; vb[3].y = 512.0f; vb[3].z = 1.0f; vb[3].w = 1.0f; + vb[3].u = 0.0f; vb[3].v = 1.0f; + + IDirect3DVertexBuffer9_Unlock(vb_2d); + } + + D3DXCreateMatrixStack(0, &matrix_stack); + d3d_matrix_stack_init(); + + + // Create font for the on-screen display + hfont = CreateFont( 14, 0, // Width, Height + 0, 0, // Escapement, Orientation + FW_BOLD, // Font weight + FALSE, FALSE, // Italic, underline + FALSE, // Strikeout + ANSI_CHARSET, // Charset + OUT_DEFAULT_PRECIS, // Precision + CLIP_DEFAULT_PRECIS, // Clip precision + DEFAULT_QUALITY, // Output quality + DEFAULT_PITCH | // Pitch and family + FF_DONTCARE, + "Terminal" ); + if (hfont == NULL) + { + message(0, "Direct3D error: Couldn't create font."); + return FALSE; + } + + // Create D3D font + hr = D3DXCreateFont(device, 14, 0, FW_BOLD, 1, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Terminal", &font); + if (FAILED(hr)) + { + message(0, "Direct3D error: D3DXCreateFont failed."); + return FALSE; + } + + atexit(d3d_shutdown); + + // set minimum and maximum Z + if (m3_config.step == 0x10) + { + min_z = 10.0f; + max_z = 500000.0f; + } + else + { + min_z = 0.1f; + max_z = 100000.0f; + } + + return TRUE; +} + +static void set_viewport(int x, int y, int width, int height) +{ + D3DVIEWPORT9 viewport; + + memset(&viewport, 0, sizeof(D3DVIEWPORT9)); + viewport.X = x; + viewport.Y = y; + viewport.Width = width; + viewport.Height = height; + viewport.MinZ = min_z; + viewport.MaxZ = max_z; + + IDirect3DDevice9_SetViewport(device, &viewport); +} + +void osd_renderer_draw_layer(int layer, UINT32 color_offset, int x, int y, BOOL top) +{ + int i; + D3DXVECTOR4 scroll_pos; + float co[4]; + co[0] = 0.0f; + co[1] = (((float)((color_offset >> 16) & 0xff) / 255.0f) - 0.5f) * 2.0f; + co[2] = (((float)((color_offset >> 8) & 0xff) / 255.0f) - 0.5f) * 2.0f; + co[3] = (((float)((color_offset >> 0) & 0xff) / 255.0f) - 0.5f) * 2.0f; + + scroll_pos.x = (float)(x) / 512.0f; + scroll_pos.y = (float)(y) / 512.0f; + scroll_pos.z = top ? 1.0f : 0.0f; + + set_viewport(0, 0, 496, 384); + + IDirect3DDevice9_BeginScene(device); + + IDirect3DDevice9_SetStreamSourceFreq(device, 0, 1); + IDirect3DDevice9_SetStreamSource(device, 0, vb_2d, 0, sizeof(VERTEX_2D)); + IDirect3DDevice9_SetStreamSourceFreq(device, 1, 1); + IDirect3DDevice9_SetStreamSource(device, 1, NULL, 0, NULL); + + IDirect3DDevice9_SetFVF(device, VERTEX2D_FVF); +// IDirect3DDevice9_SetVertexDeclaration(device, vertex_declaration_2d); + IDirect3DDevice9_SetVertexShader(device, vshader_2d); + IDirect3DDevice9_SetPixelShader(device, pshader_2d); + + // set color offset + IDirect3DDevice9_SetPixelShaderConstantF(device, 8, (float *)co, 1); + IDirect3DDevice9_SetPixelShaderConstantF(device, 9, (float *)&scroll_pos, 1); + + IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE); + IDirect3DDevice9_SetRenderState(device, D3DRS_FILLMODE, D3DFILL_SOLID); + + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHATESTENABLE, TRUE); + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHAREF, (DWORD)0x00000000); + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); + + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(device, 1, D3DSAMP_MINFILTER, D3DTEXF_NONE); + IDirect3DDevice9_SetSamplerState(device, 1, D3DSAMP_MAGFILTER, D3DTEXF_NONE); + IDirect3DDevice9_SetSamplerState(device, 1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(device, 1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(device, 2, D3DSAMP_MINFILTER, D3DTEXF_NONE); + IDirect3DDevice9_SetSamplerState(device, 2, D3DSAMP_MAGFILTER, D3DTEXF_NONE); + IDirect3DDevice9_SetSamplerState(device, 2, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + IDirect3DDevice9_SetSamplerState(device, 2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + IDirect3DDevice9_SetTexture(device, 0, texture_2d[layer]); + IDirect3DDevice9_SetTexture(device, 1, palette_2d); + IDirect3DDevice9_SetTexture(device, 2, priority_2d[layer]); + + IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLEFAN, 0, 2); + + IDirect3DDevice9_EndScene(device); +} + +void osd_renderer_blit(void) +{ + if (m3_config.stretch) + { + RECT src_rect = {0, 0, 496, 384}; + IDirect3DDevice9_Present(device, &src_rect, NULL, NULL, NULL); + } + else + { + IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + } +} + +void osd_renderer_clear(BOOL fbuf, BOOL zbuf) +{ + int flags = 0; + + set_viewport(0, 0, m3_config.width, m3_config.height); + + if (fbuf) + { + flags |= D3DCLEAR_TARGET; + } + if (zbuf) + { + flags |= D3DCLEAR_ZBUFFER; + } + + IDirect3DDevice9_Clear(device, 0, NULL, flags, 0x00000000, 1.0f, 0); +} + +void osd_renderer_get_layer_buffer(int layer_num, UINT8 **buffer, int *pitch) +{ + D3DLOCKED_RECT locked_rect; + HRESULT hr; + + *buffer = NULL; + *pitch = 0; + + hr = IDirect3DTexture9_LockRect(texture_2d[layer_num], 0, &locked_rect, NULL, D3DLOCK_DISCARD); + if (!FAILED(hr)) + { + *buffer = (UINT8 *)locked_rect.pBits; + *pitch = locked_rect.Pitch / 2; + } +} + +void osd_renderer_free_layer_buffer(UINT layer_num) +{ + IDirect3DTexture9_UnlockRect(texture_2d[layer_num], 0); +} + +void osd_renderer_get_palette_buffer(UINT32 **buffer, int *width, int *pitch) +{ + D3DLOCKED_RECT locked_rect; + HRESULT hr; + + *buffer = NULL; + *pitch = 0; + *width = 0; + + hr = IDirect3DTexture9_LockRect(palette_2d, 0, &locked_rect, NULL, D3DLOCK_DISCARD); + if (!FAILED(hr)) + { + *buffer = (UINT32*)locked_rect.pBits; + *pitch = locked_rect.Pitch / 4; + *width = 256; + } +} + +void osd_renderer_free_palette_buffer(void) +{ + IDirect3DTexture9_UnlockRect(palette_2d, 0); +} + +void osd_renderer_get_priority_buffer(int layer_num, UINT8 **buffer, int *pitch) +{ + D3DLOCKED_RECT locked_rect; + HRESULT hr; + + *buffer = NULL; + *pitch = 0; + + hr = IDirect3DTexture9_LockRect(priority_2d[layer_num], 0, &locked_rect, NULL, D3DLOCK_DISCARD); + if (!FAILED(hr)) + { + *buffer = (UINT8*)locked_rect.pBits; + *pitch = locked_rect.Pitch; + } +} + +void osd_renderer_free_priority_buffer(int layer_num) +{ + IDirect3DTexture9_UnlockRect(priority_2d[layer_num], 0); +} + +void osd_renderer_draw_text(int x, int y, const char* string, DWORD color, BOOL shadow) +{ + RECT rect = { x, y, 496-1, 384-1 }; + RECT rect_s = { x+1, y+1, 496-1, 384-1 }; + if (shadow) + { + font->lpVtbl->DrawText(font, NULL, string, -1, &rect_s, 0, 0xFF000000); + } + + font->lpVtbl->DrawText(font, NULL, string, -1, &rect, 0, color); +} + + +/* + * void osd_renderer_set_coordinate_system(const MATRIX m); + * + * Applies the coordinate system matrix and makes adjustments so that the + * Model 3 coordinate system is properly handled. + * + * Parameters: + * m = Matrix. + */ + +void osd_renderer_set_coordinate_system( const MATRIX m ) +{ + memcpy( &view_matrix, m, sizeof(MATRIX) ); + view_matrix._22 = -view_matrix._22; +} + +static void cache_model(VERTEX *vb, VERTEX *vb_alpha, UINT32 *src, UINT32 address, int *verts, int *verts_alpha) +{ + float fixed_point_scale; + VERTEX vertex[4]; + VERTEX prev_vertex[4]; + int end, index, vb_index, vb_index_alpha; + int polygon_index = 0; + float uv_scale; + + int polygon = 0; + + int normal_num = 0; + + *verts = 0; + *verts_alpha = 0; + + //UINT32 *src = get_address( address ); + + if(src == NULL) + return FALSE; + + if(m3_config.step == 0x10) + fixed_point_scale = 32768.0f; + else + fixed_point_scale = 524288.0f; + + memset(prev_vertex, 0, sizeof(prev_vertex)); + end = 0; + index = 0; + vb_index = 0; + vb_index_alpha = 0; + + do { + UINT32 header[7]; + UINT32 entry[16]; + D3DCOLOR color, color2; + int transparency; + int i, num_vertices, num_old_vertices; + int v2, v; + int texture_format; + int texture_x, texture_y, tex_width, tex_height; + float nx, ny, nz; + float dot; + int polygon_id; + + for( i=0; i<7; i++) { + header[i] = src[index]; + index++; + } + + uv_scale = (header[1] & 0x40) ? 1.0f : 8.0f; + + polygon_id = (header[0] >> 10) & 0x3fff; + + if (polygon == 0 && (header[0] & 0xf) != 0) + return FALSE; + + if (header[6] == 0 /*|| header[0] & 0x300*/) + return FALSE; + + if ((header[0] & 0x300) == 0x300) + { + //printf("Polygon = %08X %08X %08X %08X %08X %08X %08X (address = %08X)\n", header[0], header[1], header[2], header[3], header[4], header[5], header[6], address); + } + + // Check if this is the last polygon + if(header[1] & 0x4) + end = 1; + + transparency = ((header[6] >> 18) & 0x1F) << 3; + if (header[6] & 0x800000) + { + color = 0xFF000000 | ((header[4] >> 8) & 0xffffff); + } + else + { + color = (transparency << 24) | ((header[4] >> 8) & 0xffffff); + } + + if (header[6] & 0x10000) + { + color2 = 0xffff0000 | (((header[6] >> 11) & 0x1F) << 3) << 16; + } + else + { + color2 = 0; + } + + if (header[6] & 0x4000000) + { + // texture enable + color2 |= 0x0000ff00; + } + + texture_x = 32 * (((header[4] & 0x1F) << 1) | ((header[5] >> 7) & 0x1)); + texture_y = 32 * ((header[5] & 0x1F) | ((header[4] >> 1) & 0x20)); + tex_width = 32 << ((header[3] >> 3) & 0x7); + tex_height = 32 << (header[3] & 0x7); + + texture_format = ((header[6] >> 7) & 0x7) ? 0 : 1; + if (texture_format == 0) texture_y += 2048; + + // Polygon normal + // Assuming 2.22 fixed-point. Is this correct ? + nx = (float)((int)header[1] >> 8) / 4194304.0f; + ny = (float)((int)header[2] >> 8) / 4194304.0f; + nz = (float)((int)header[3] >> 8) / 4194304.0f; + + // If bit 0x40 set this is a quad, otherwise a triangle + if(header[0] & 0x40) + num_vertices = 4; + else + num_vertices = 3; + + // How many vertices are reused + num_old_vertices = num_bits[header[0] & 0xF]; + + // Load reused vertices + v2 = 0; + for( v=0; v<4; v++) { + if( header[0] & (1 << v) ) { + memcpy( &vertex[v2], &prev_vertex[v], sizeof(VERTEX) ); + //vertex[v2].nx = prev_vertex[v].nx; + //vertex[v2].ny = prev_vertex[v].ny; + //vertex[v2].nz = prev_vertex[v].nz; + vertex[v2].color = color; + vertex[v2].color2 = color2; + vertex[v2].tx = texture_x; + vertex[v2].ty = texture_y; + vertex[v2].twidth = tex_width; + vertex[v2].theight = tex_height; + v2++; + } + } + + // Load vertex data + for( i=0; i<(num_vertices - num_old_vertices) * 4; i++) { + entry[i] = src[index]; + index++; + } + + // Load new vertices + for( v=0; v < (num_vertices - num_old_vertices); v++) { + int ix, iy, iz; + UINT16 tx,ty; + int xsize, ysize; + int v_index = v * 4; + + ix = entry[v_index]; + iy = entry[v_index + 1]; + iz = entry[v_index + 2]; + + if ((ix & 0xf0000000) == 0x70000000 || + (iy & 0xf0000000) == 0x70000000 || + (iz & 0xf0000000) == 0x70000000) + return FALSE; + + vertex[v2].x = (float)(ix) / fixed_point_scale; + vertex[v2].y = (float)(iy) / fixed_point_scale; + vertex[v2].z = (float)(iz) / fixed_point_scale; + + tx = (UINT16)((entry[v_index + 3] >> 16) & 0xFFFF); + ty = (UINT16)(entry[v_index + 3] & 0xFFFF); + xsize = 32 << ((header[3] >> 3) & 0x7); + ysize = 32 << (header[3] & 0x7); + + // Convert texture coordinates from 13.3 fixed-point to float + // Tex coords need to be divided by texture size because D3D wants them in + // range 0...1 + vertex[v2].u = ((float)(tx) / uv_scale) / (float)xsize; + vertex[v2].v = ((float)(ty) / uv_scale) / (float)ysize; + vertex[v2].nx = nx; + vertex[v2].ny = ny; + vertex[v2].nz = nz; + vertex[v2].color = color; + vertex[v2].color2 = color2; + vertex[v2].tx = texture_x; + vertex[v2].ty = texture_y; + vertex[v2].twidth = tex_width; + vertex[v2].theight = tex_height; + v2++; + + if (header[0] & 0x300) + { + //printf(" Vert: %08X %08X %08X %08X\n", entry[v_index+0], entry[v_index+1], entry[v_index+2], entry[v_index+3]); + } + } + + { + D3DXVECTOR3 e1, e2, cross, n; + e1.x = vertex[1].x - vertex[0].x; + e1.y = vertex[1].y - vertex[0].y; + e1.z = vertex[1].z - vertex[0].z; + e2.x = vertex[2].x - vertex[0].x; + e2.y = vertex[2].y - vertex[0].y; + e2.z = vertex[2].z - vertex[0].z; + + n.x = nx; + n.y = ny; + n.z = nz; + + D3DXVec3Cross(&cross, &e2, &e1); + D3DXVec3Normalize(&cross, &cross); + dot = D3DXVec3Dot(&n, &cross); + } + + // Transparent polygons + // Translucent texture (ARGB4444) + if((header[6] & 0x800000) == 0 || header[6] & 0x1 /* || header[6] & 0x80000000*/) + { + if (dot >= 0) + { + memcpy(&vb_alpha[vb_index_alpha+0], &vertex[0], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+1], &vertex[1], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+2], &vertex[2], sizeof(VERTEX)); + } + else + { + memcpy(&vb_alpha[vb_index_alpha+0], &vertex[2], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+1], &vertex[1], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+2], &vertex[0], sizeof(VERTEX)); + } + vb_index_alpha += 3; + + if (num_vertices > 3) + { + if (dot >= 0) + { + memcpy(&vb_alpha[vb_index_alpha+0], &vertex[0], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+1], &vertex[2], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+2], &vertex[3], sizeof(VERTEX)); + } + else + { + memcpy(&vb_alpha[vb_index_alpha+0], &vertex[3], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+1], &vertex[2], sizeof(VERTEX)); + memcpy(&vb_alpha[vb_index_alpha+2], &vertex[0], sizeof(VERTEX)); + } + vb_index_alpha += 3; + } + } + else + { + if (dot >= 0) + { + memcpy(&vb[vb_index+0], &vertex[0], sizeof(VERTEX)); + memcpy(&vb[vb_index+1], &vertex[1], sizeof(VERTEX)); + memcpy(&vb[vb_index+2], &vertex[2], sizeof(VERTEX)); + } + else + { + memcpy(&vb[vb_index+0], &vertex[2], sizeof(VERTEX)); + memcpy(&vb[vb_index+1], &vertex[1], sizeof(VERTEX)); + memcpy(&vb[vb_index+2], &vertex[0], sizeof(VERTEX)); + } + vb_index += 3; + + if (num_vertices > 3) + { + if (dot >= 0) + { + memcpy(&vb[vb_index+0], &vertex[0], sizeof(VERTEX)); + memcpy(&vb[vb_index+1], &vertex[2], sizeof(VERTEX)); + memcpy(&vb[vb_index+2], &vertex[3], sizeof(VERTEX)); + } + else + { + memcpy(&vb[vb_index+0], &vertex[3], sizeof(VERTEX)); + memcpy(&vb[vb_index+1], &vertex[2], sizeof(VERTEX)); + memcpy(&vb[vb_index+2], &vertex[0], sizeof(VERTEX)); + } + vb_index += 3; + } + } + + + // Copy current vertex as previous vertex + memcpy(prev_vertex, vertex, sizeof(VERTEX) * 4); + + polygon++; + + } while(end == 0); + + *verts = vb_index / 3; + *verts_alpha = vb_index_alpha / 3; +} + +void osd_renderer_draw_model(UINT32 *mem, UINT32 address, int dynamic) +{ + int num_triangles, num_triangles_alpha; + VERTEX *vb, *vb_alpha; + D3DMATRIX world_view_proj, world_view; + D3DMATRIX matrix = d3d_matrix_stack_get_top(); + + // Make the world-view matrix + //D3DXMatrixMultiply(&world_view, &matrix, &view_matrix); + D3DXMatrixTranspose(&world_view, &matrix); + + // Make the world-view-projection matrix + D3DXMatrixMultiply(&world_view_proj, &matrix, &view_matrix); + D3DXMatrixMultiply(&world_view_proj, &world_view_proj, &projection_matrix); + D3DXMatrixTranspose(&world_view_proj, &world_view_proj); + + if (dynamic) + { + int vert_index = dynamic_mesh_cache_vertex_top; + int vert_index_alpha = dynamic_mesh_cache_vertex_top_alpha; + + IDirect3DVertexBuffer9_Lock(dynamic_vb, 0, 0, (void **)&vb, D3DLOCK_DISCARD); + IDirect3DVertexBuffer9_Lock(dynamic_vb_alpha, 0, 0, (void **)&vb_alpha, D3DLOCK_DISCARD); + cache_model(&vb[vert_index], &vb_alpha[vert_index_alpha], mem, address, &num_triangles, &num_triangles_alpha); + IDirect3DVertexBuffer9_Unlock(dynamic_vb_alpha); + IDirect3DVertexBuffer9_Unlock(dynamic_vb); + + dynamic_mesh_cache[dynamic_mesh_cache_top].vb_index = vert_index; + dynamic_mesh_cache[dynamic_mesh_cache_top].vb_index_alpha = vert_index_alpha; + dynamic_mesh_cache[dynamic_mesh_cache_top].num_vertices = num_triangles * 3; + dynamic_mesh_cache[dynamic_mesh_cache_top].num_vertices_alpha = num_triangles_alpha * 3; + + dynamic_mesh_cache_vertex_top += num_triangles * 3; + dynamic_mesh_cache_vertex_top_alpha += num_triangles_alpha * 3; + + memcpy(&dynamic_mesh_buffer[dynamic_mesh_buffer_top].normal, &world_view, sizeof(D3DMATRIX)); + memcpy(&dynamic_mesh_buffer[dynamic_mesh_buffer_top].transform, &world_view_proj, sizeof(D3DMATRIX)); + + dynamic_mesh_buffer[dynamic_mesh_buffer_top].lighting = current_light; + dynamic_mesh_buffer[dynamic_mesh_buffer_top].viewport = current_viewport; + + dynamic_mesh_buffer[dynamic_mesh_buffer_top].mesh_index = dynamic_mesh_cache_top; + + dynamic_mesh_cache_top++; + if (dynamic_mesh_cache_top >= NUM_DYNAMIC_MESHES) + { + printf("dynamic mesh cache overflow!\n"); + exit(1); + } + + dynamic_mesh_buffer_top++; + if (dynamic_mesh_buffer_top >= DYNAMIC_MESH_BUFFER_SIZE) + { + printf("dynamic mesh buffer overflow!\n"); + exit(1); + } + + if (dynamic_mesh_cache_vertex_top >= DYNAMIC_VB_SIZE) + { + printf("dynamic vertex cache overflow!\n"); + exit(1); + } + if (dynamic_mesh_cache_vertex_top_alpha >= DYNAMIC_VB_SIZE) + { + printf("dynamic vertex cache alpha overflow!\n"); + exit(1); + } + } + else + { + UINT16 mesh_index = static_mesh_index[address & 0xffffff]; + + if (mesh_index == 0xffff) + { + // cache new mesh + int vert_index = static_mesh_cache_vertex_top; + int vert_index_alpha = static_mesh_cache_vertex_top_alpha; + + int voffset = vert_index * sizeof(VERTEX); + int voffset_alpha = vert_index_alpha * sizeof(VERTEX); + int vsize = 10000 * sizeof(VERTEX); + + IDirect3DVertexBuffer9_Lock(static_vb, voffset, vsize, (void **)&vb, 0); + IDirect3DVertexBuffer9_Lock(static_vb_alpha, voffset_alpha, vsize, (void **)&vb_alpha, 0); + cache_model(&vb[0], &vb_alpha[0], mem, address, &num_triangles, &num_triangles_alpha); + IDirect3DVertexBuffer9_Unlock(static_vb_alpha); + IDirect3DVertexBuffer9_Unlock(static_vb); + + static_mesh_cache[static_mesh_cache_top].vb_index = vert_index; + static_mesh_cache[static_mesh_cache_top].vb_index_alpha = vert_index_alpha; + static_mesh_cache[static_mesh_cache_top].num_vertices = num_triangles * 3; + static_mesh_cache[static_mesh_cache_top].num_vertices_alpha = num_triangles_alpha * 3; + + static_mesh_cache_vertex_top += num_triangles * 3; + static_mesh_cache_vertex_top_alpha += num_triangles_alpha * 3; + + static_mesh_index[address & 0xffffff] = static_mesh_cache_top; + mesh_index = static_mesh_cache_top; + + static_mesh_cache_top++; + if (static_mesh_cache_top >= NUM_STATIC_MESHES) + { + printf("static mesh cache overflow!\n"); + exit(1); + } + + if (static_mesh_cache_vertex_top >= STATIC_VB_SIZE) + { + printf("static vertex cache overflow!\n"); + exit(1); + } + if (static_mesh_cache_vertex_top_alpha >= STATIC_VB_SIZE) + { + printf("static vertex cache alpha overflow!\n"); + exit(1); + } + } + + memcpy(&static_mesh_buffer[static_mesh_buffer_top].normal, &world_view, sizeof(D3DMATRIX)); + memcpy(&static_mesh_buffer[static_mesh_buffer_top].transform, &world_view_proj, sizeof(D3DMATRIX)); + + static_mesh_buffer[static_mesh_buffer_top].lighting = current_light; + static_mesh_buffer[static_mesh_buffer_top].viewport = current_viewport; + + static_mesh_buffer[static_mesh_buffer_top].mesh_index = mesh_index; + + static_mesh_buffer_top++; + if (static_mesh_buffer_top >= STATIC_MESH_BUFFER_SIZE) + { + printf("static mesh buffer overflow!\n"); + exit(1); + } + } +} + + +void osd_renderer_begin_3d_scene(void) +{ + dynamic_mesh_buffer_top = 0; + static_mesh_buffer_top = 0; + + dynamic_mesh_cache_top = 0; + dynamic_mesh_cache_vertex_top = 0; + dynamic_mesh_cache_vertex_top_alpha = 0; + + num_lights = 0; + num_viewports = 0; +} + +void osd_renderer_end_3d_scene(void) +{ + int i; + int end = 0; + int index = 0; + float mipmap_lod_bias; + + int selected_viewport = -1; + int selected_lighting = -1; + + IDirect3DDevice9_BeginScene(device); + + IDirect3DDevice9_SetVertexDeclaration(device, vertex_declaration); + IDirect3DDevice9_SetVertexShader(device, vshader); + IDirect3DDevice9_SetPixelShader(device, pshader); + IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(device, D3DRS_FILLMODE, D3DFILL_SOLID); + IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_USEW); + + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHATESTENABLE, FALSE); + + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, FALSE); +// IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); +// IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(device, D3DRS_ZWRITEENABLE, TRUE); + + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAXMIPLEVEL, 0); + //IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + + //mipmap_lod_bias = -4.0f; + //IDirect3DDevice9_SetSamplerState( device, 0, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)(&mipmap_lod_bias)); + + IDirect3DDevice9_SetTexture(device, 0, texture); + + IDirect3DDevice9_SetStreamSourceFreq(device, 0, 1); + IDirect3DDevice9_SetStreamSource(device, 0, static_vb, 0, sizeof(VERTEX)); + + set_viewport(0, 0, 496, 384); + + // render static meshes + for (i=0; i < static_mesh_buffer_top; i++) + { + D3DMATRIX *transform, *normal; + int num_triangles, vb_index; + + int mesh_index = static_mesh_buffer[i].mesh_index; + vb_index = static_mesh_cache[mesh_index].vb_index; + num_triangles = static_mesh_cache[mesh_index].num_vertices / 3; + + if (num_triangles > 0) + { + if (selected_viewport != static_mesh_buffer[i].viewport) + { + D3DVIEWPORT9 vp; + selected_viewport = static_mesh_buffer[i].viewport; + vp.X = viewport_params[selected_viewport].x; + vp.Y = viewport_params[selected_viewport].y; + vp.Width = viewport_params[selected_viewport].width; + vp.Height = viewport_params[selected_viewport].height; + vp.MinZ = min_z; + vp.MaxZ = max_z; + IDirect3DDevice9_SetViewport(device, &vp); + } + + transform = &static_mesh_buffer[i].transform; + normal = &static_mesh_buffer[i].normal; + + IDirect3DDevice9_SetVertexShaderConstantF(device, 0, (float*)transform, 4); + IDirect3DDevice9_SetVertexShaderConstantF(device, 4, (float*)normal, 4); + + if (selected_lighting != static_mesh_buffer[i].lighting) + { + selected_lighting = static_mesh_buffer[i].lighting; + IDirect3DDevice9_SetVertexShaderConstantF(device, 16, (float*)&lighting_params[selected_lighting].sun_vector, 1); + IDirect3DDevice9_SetVertexShaderConstantF(device, 17, (float*)&lighting_params[selected_lighting].sun_params, 1); + } + + IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLELIST, vb_index, num_triangles); + } + } + + IDirect3DDevice9_SetStreamSourceFreq(device, 0, 1); + IDirect3DDevice9_SetStreamSource(device, 0, dynamic_vb, 0, sizeof(VERTEX)); + + // render dynamic meshes + for (i=0; i < dynamic_mesh_buffer_top; i++) + { + D3DMATRIX *transform, *normal; + int num_triangles, vb_index; + + int mesh_index = dynamic_mesh_buffer[i].mesh_index; + vb_index = dynamic_mesh_cache[mesh_index].vb_index; + num_triangles = dynamic_mesh_cache[mesh_index].num_vertices / 3; + + if (num_triangles > 0) + { + + if (selected_viewport != dynamic_mesh_buffer[i].viewport) + { + D3DVIEWPORT9 vp; + selected_viewport = dynamic_mesh_buffer[i].viewport; + vp.X = viewport_params[selected_viewport].x; + vp.Y = viewport_params[selected_viewport].y; + vp.Width = viewport_params[selected_viewport].width; + vp.Height = viewport_params[selected_viewport].height; + vp.MinZ = min_z; + vp.MaxZ = max_z; + IDirect3DDevice9_SetViewport(device, &vp); + } + + transform = &dynamic_mesh_buffer[i].transform; + normal = &dynamic_mesh_buffer[i].normal; + + IDirect3DDevice9_SetVertexShaderConstantF(device, 0, (float*)transform, 4); + IDirect3DDevice9_SetVertexShaderConstantF(device, 4, (float*)normal, 4); + + if (selected_lighting != dynamic_mesh_buffer[i].lighting) + { + selected_lighting = dynamic_mesh_buffer[i].lighting; + IDirect3DDevice9_SetVertexShaderConstantF(device, 16, (float*)&lighting_params[selected_lighting].sun_vector, 1); + IDirect3DDevice9_SetVertexShaderConstantF(device, 17, (float*)&lighting_params[selected_lighting].sun_params, 1); + } + + IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLELIST, vb_index, num_triangles); + } + } + + // render alpha polys + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(device, D3DRS_ZWRITEENABLE, FALSE); + + IDirect3DDevice9_SetStreamSourceFreq(device, 0, 1); + IDirect3DDevice9_SetStreamSource(device, 0, dynamic_vb_alpha, 0, sizeof(VERTEX)); + + // render dynamic meshes + //for (i=dynamic_mesh_buffer_top-1; i >= 0; i--) + for (i=0; i < dynamic_mesh_buffer_top; i++) + { + D3DMATRIX *transform, *normal; + int num_triangles, vb_index; + + int mesh_index = dynamic_mesh_buffer[i].mesh_index; + vb_index = dynamic_mesh_cache[mesh_index].vb_index_alpha; + num_triangles = dynamic_mesh_cache[mesh_index].num_vertices_alpha / 3; + + if (num_triangles > 0) + { + if (selected_viewport != dynamic_mesh_buffer[i].viewport) + { + D3DVIEWPORT9 vp; + selected_viewport = dynamic_mesh_buffer[i].viewport; + vp.X = viewport_params[selected_viewport].x; + vp.Y = viewport_params[selected_viewport].y; + vp.Width = viewport_params[selected_viewport].width; + vp.Height = viewport_params[selected_viewport].height; + vp.MinZ = min_z; + vp.MaxZ = max_z; + IDirect3DDevice9_SetViewport(device, &vp); + } + + transform = &dynamic_mesh_buffer[i].transform; + normal = &dynamic_mesh_buffer[i].normal; + + IDirect3DDevice9_SetVertexShaderConstantF(device, 0, (float*)transform, 4); + IDirect3DDevice9_SetVertexShaderConstantF(device, 4, (float*)normal, 4); + + if (selected_lighting != dynamic_mesh_buffer[i].lighting) + { + selected_lighting = dynamic_mesh_buffer[i].lighting; + IDirect3DDevice9_SetVertexShaderConstantF(device, 16, (float*)&lighting_params[selected_lighting].sun_vector, 1); + IDirect3DDevice9_SetVertexShaderConstantF(device, 17, (float*)&lighting_params[selected_lighting].sun_params, 1); + } + + IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLELIST, vb_index, num_triangles); + } + } + + IDirect3DDevice9_SetStreamSourceFreq(device, 0, 1); + IDirect3DDevice9_SetStreamSource(device, 0, static_vb_alpha, 0, sizeof(VERTEX)); + + // render static meshes + //for (i=static_mesh_buffer_top-1; i >= 0; i--) + for (i=0; i < static_mesh_buffer_top; i++) + { + D3DMATRIX *transform, *normal; + int num_triangles, vb_index; + + int mesh_index = static_mesh_buffer[i].mesh_index; + vb_index = static_mesh_cache[mesh_index].vb_index_alpha; + num_triangles = static_mesh_cache[mesh_index].num_vertices_alpha / 3; + + if (num_triangles > 0) + { + if (selected_viewport != static_mesh_buffer[i].viewport) + { + D3DVIEWPORT9 vp; + selected_viewport = static_mesh_buffer[i].viewport; + vp.X = viewport_params[selected_viewport].x; + vp.Y = viewport_params[selected_viewport].y; + vp.Width = viewport_params[selected_viewport].width; + vp.Height = viewport_params[selected_viewport].height; + vp.MinZ = min_z; + vp.MaxZ = max_z; + IDirect3DDevice9_SetViewport(device, &vp); + } + + transform = &static_mesh_buffer[i].transform; + normal = &static_mesh_buffer[i].normal; + + IDirect3DDevice9_SetVertexShaderConstantF(device, 0, (float*)transform, 4); + IDirect3DDevice9_SetVertexShaderConstantF(device, 4, (float*)normal, 4); + + if (selected_lighting != static_mesh_buffer[i].lighting) + { + selected_lighting = static_mesh_buffer[i].lighting; + IDirect3DDevice9_SetVertexShaderConstantF(device, 16, (float*)&lighting_params[selected_lighting].sun_vector, 1); + IDirect3DDevice9_SetVertexShaderConstantF(device, 17, (float*)&lighting_params[selected_lighting].sun_params, 1); + } + + IDirect3DDevice9_DrawPrimitive(device, D3DPT_TRIANGLELIST, vb_index, num_triangles); + } + } + + IDirect3DDevice9_EndScene(device); +} + +void osd_renderer_set_light( int light_num, LIGHT* param ) +{ + switch(param->type) + { + case LIGHT_PARALLEL: + lighting_params[num_lights].sun_vector.x = -param->u * view_matrix._11; + lighting_params[num_lights].sun_vector.y = param->v * view_matrix._22; + lighting_params[num_lights].sun_vector.z = -param->w * view_matrix._33; + lighting_params[num_lights].sun_vector.w = 1.0f; + + lighting_params[num_lights].sun_params.x = param->diffuse_intensity; + lighting_params[num_lights].sun_params.y = param->ambient_intensity; + break; + + default: + error("Direct3D error: Unsupported light type: %d",param->type); + } + + current_light = num_lights; + + num_lights++; + if (num_lights >= MAX_LIGHTS) + { + error("Too many lights!"); + } +} + +void osd_renderer_set_viewport(const VIEWPORT* vp) +{ + float fov = D3DXToRadian( (float)(vp->up + vp->down) ); + float aspect_ratio = (float)((float)vp->width / (float)vp->height); + + float x = vp->x; + float y = vp->y; + float w = vp->width; + float h = vp->height; + + viewport_params[num_viewports].x = x; + viewport_params[num_viewports].y = y; + viewport_params[num_viewports].width = w; + viewport_params[num_viewports].height = h; + + current_viewport = num_viewports; + + num_viewports++; + if (num_viewports >= MAX_VIEWPORTS) + { + error("Too many viewports!"); + } + + D3DXMatrixPerspectiveFovLH(&projection_matrix, fov, aspect_ratio, min_z, max_z); +} + +//////////////////////// +// Matrix Stack // +//////////////////////// + +static D3DMATRIX matrix_to_d3d( const MATRIX m ) +{ + D3DMATRIX c; + memcpy( &c, m, sizeof(MATRIX) ); + + return c; +} + +static int stack_ptr = 0; + +static void d3d_matrix_stack_init(void) +{ + matrix_stack->lpVtbl->LoadIdentity(matrix_stack); +} + +static D3DXMATRIX d3d_matrix_stack_get_top(void) +{ + D3DXMATRIX *m = matrix_stack->lpVtbl->GetTop(matrix_stack); + return *m; +} + +/* + * void osd_renderer_push_matrix(void); + * + * Pushes a matrix on to the stack. The matrix pushed is the former top of the + * stack. + */ + +void osd_renderer_push_matrix(void) +{ + stack_ptr++; + matrix_stack->lpVtbl->Push(matrix_stack); + + if (stack_ptr >= 256) + { + error("Matrix stack overflow\n"); + } +} + +/* + * void osd_renderer_pop_matrix(void); + * + * Pops a matrix off the top of the stack. + */ + +void osd_renderer_pop_matrix(void) +{ + stack_ptr--; + if( stack_ptr >= 0) + matrix_stack->lpVtbl->Pop(matrix_stack); +} + +/* + * void osd_renderer_multiply_matrix(MATRIX m); + * + * Multiplies the top of the matrix stack by the specified matrix + * + * Parameters: + * m = Matrix to multiply. + */ + +void osd_renderer_multiply_matrix( MATRIX m ) +{ + D3DMATRIX x = matrix_to_d3d( m ); + matrix_stack->lpVtbl->MultMatrixLocal(matrix_stack, &x ); +} + +/* + * void osd_renderer_translate_matrix(float x, float y, float z); + * + * Translates the top of the matrix stack. + * + * Parameters: + * x = Translation along X axis. + * y = Y axis. + * z = Z axis. + */ + +void osd_renderer_translate_matrix( float x, float y, float z ) +{ + //stack->lpVtbl->TranslateLocal(stack, x, y, z ); + D3DMATRIX t; + t._11 = 1.0f; t._12 = 0.0f; t._13 = 0.0f; t._14 = 0.0f; + t._21 = 0.0f; t._22 = 1.0f; t._23 = 0.0f; t._24 = 0.0f; + t._31 = 0.0f; t._32 = 0.0f; t._33 = 1.0f; t._34 = 0.0f; + t._41 = x; t._42 = y; t._43 = z; t._44 = 1.0f; + matrix_stack->lpVtbl->MultMatrixLocal(matrix_stack,&t); +} + +// Mipmap starting positions for each level +static const int mipmap_xpos[] = +{ 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 }; +static const int mipmap_ypos[] = +{ 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023, 0 }; + +void renderer_upload_texture(int x, int y, int u, int v, int width, int height, void *data, int mip_level) +{ + HRESULT hr; + int i, j; + D3DLOCKED_RECT rect; + UINT16 *s = (UINT16*)data; + UINT32 *d; + int pitch; + RECT texture_rect; + + if (mip_level > 3) + return; + + /*hr = IDirect3DTexture9_LockRect(texture, 0, &rect, NULL, 0); + d = (UINT32*)rect.pBits; + pitch = rect.Pitch / 4; + + for (j=y; j < y+height; j++) + { + int index = j * pitch; + int u = x; + for (i=x; i < x+width; i++) + { + UINT16 c = s[(j * 2048) + u]; + int r = ((c >> 10) & 0x1f) << 3; + int g = ((c >> 5) & 0x1f) << 3; + int b = ((c >> 0) & 0x1f) << 3; + d[index+i] = 0xff000000 | (r << 16) | (g << 8) | (b); + u++; + } + } + + for (j=y; j < y+height; j++) + { + int index = (j+2048) * pitch; + int u = x; + for (i=x; i < x+width; i++) + { + UINT16 c = s[(j * 2048) + u]; + int r = ((c >> 12) & 0xf) << 4; + int g = ((c >> 8) & 0xf) << 4; + int b = ((c >> 4) & 0xf) << 4; + int a = ((c >> 0) & 0xf) << 4; + d[index+i] = (a << 24) | (r << 16) | (g << 8) | (b); + u++; + } + } + + IDirect3DTexture9_UnlockRect(texture, 0);*/ + + u >>= mip_level; + v >>= mip_level; + width >>= mip_level; + height >>= mip_level; + + texture_rect.left = u; + texture_rect.top = v; + texture_rect.right = u + width; + texture_rect.bottom = v + height; + + hr = IDirect3DTexture9_LockRect(texture, mip_level, &rect, &texture_rect, 0); + if (!FAILED(hr)) + { + d = (UINT32*)rect.pBits; + pitch = rect.Pitch / 4; + + for (j=0; j < height; j++) + { + int index = j * pitch; + for (i=0; i < width; i++) + { + UINT16 c = s[((j+y) * 2048) + x + i]; + int r = ((c >> 10) & 0x1f) << 3; + int g = ((c >> 5) & 0x1f) << 3; + int b = ((c >> 0) & 0x1f) << 3; + int a = (c & 0x8000) ? 0 : 0xff; + d[index+i] = (a << 24) | (r << 16) | (g << 8) | (b); + } + } + } + IDirect3DTexture9_UnlockRect(texture, mip_level); + + texture_rect.left = u; + texture_rect.top = v + (2048 >> mip_level); + texture_rect.right = u + width; + texture_rect.bottom = v + (2048 >> mip_level) + height; + + hr = IDirect3DTexture9_LockRect(texture, mip_level, &rect, &texture_rect, 0); + if (!FAILED(hr)) + { + d = (UINT32*)rect.pBits; + pitch = rect.Pitch / 4; + for (j=0; j < height; j++) + { + int index = j * pitch; + for (i=0; i < width; i++) + { + UINT16 c = s[((j+y) * 2048) + x + i]; + int r = ((c >> 12) & 0xf) << 4; + int g = ((c >> 8) & 0xf) << 4; + int b = ((c >> 4) & 0xf) << 4; + int a = ((c >> 0) & 0xf) << 4; + d[index+i] = (a << 24) | (r << 16) | (g << 8) | (b); + } + } + } + IDirect3DTexture9_UnlockRect(texture, mip_level); +} + +void osd_renderer_invalidate_textures(UINT x, UINT y, int u, int v, UINT w, UINT h, UINT8 *texture_sheet, int miplevel) +{ + renderer_upload_texture(x, y, u, v, w, h, texture_sheet, miplevel); +} \ No newline at end of file diff --git a/win32/dx_render.h b/win32/dx_render.h new file mode 100644 index 0000000..4352af2 --- /dev/null +++ b/win32/dx_render.h @@ -0,0 +1,38 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * win32/dx_render.h + * + * DirectX9 Renderer interface + */ + +#include "d3d9.h" +#include "d3dx9.h" + +#define RGB_REG 0xFFFF0000 +#define RGB_GREEN 0xFF00FF00 +#define RGB_BLUE 0xFF0000FF +#define RGB_YELLOW 0xFFFFFF00 +#define RGB_CYAN 0xFF00FFFF + +BOOL d3d_init(HWND); +BOOL d3d_pre_init(void); +void d3d_shutdown(void); +D3DXMATRIX d3d_matrix_stack_get_top(void); +void d3d_matrix_stack_init(void); \ No newline at end of file diff --git a/win32/osd.h b/win32/osd.h new file mode 100644 index 0000000..c068194 --- /dev/null +++ b/win32/osd.h @@ -0,0 +1,84 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * win32/osd.h + * + * Win32 OSD header: Defines everything an OSD header needs to provide and + * includes some Win32-specific files. + */ + +#ifndef INCLUDED_WIN32_OSD_H +#define INCLUDED_WIN32_OSD_H + +/******************************************************************/ +/* Win32-Specific Includes */ +/******************************************************************/ + +#define WIN32_LEAN_AND_MEAN +#include + +/******************************************************************/ +/* OSD Definitions */ +/******************************************************************/ + +#ifdef _MSC_VER +#define INLINE static _inline +#endif + +#ifdef __GCC__ +#define INLINE static __inline__ +#endif + +/******************************************************************/ +/* OSD Fundamental Data Types */ +/******************************************************************/ + +typedef unsigned int FLAGS; // for storage of bit flags + +#ifdef __GCC__ + +typedef int BOOL; // 0 (false) or non-zero (true) + +typedef signed int INT; // optimal signed integer +typedef unsigned int UINT; // optimal unsigned integer +typedef signed char CHAR; // signed character (for text) +typedef unsigned char UCHAR; // unsigned character + +typedef signed char INT8; +typedef unsigned char UINT8; +typedef signed short INT16; +typedef unsigned short UINT16; +typedef signed int INT32; +typedef unsigned int UINT32; + +#ifdef _MSC_VER // Microsoft VisualC++ (for versions 6.0 or older, non-C99) +typedef signed __int64 INT64; +typedef unsigned __int64 UINT64; +#else // assume a C99-compliant compiler +typedef signed long long INT64; +typedef unsigned long long UINT64; +#endif + +#endif + +typedef float FLOAT32; // single precision (32-bit) +typedef double FLOAT64; // double precision (64-bit) + +#endif // INCLUDED_WIN32_OSD_H + diff --git a/win32/pixel_shader.ps b/win32/pixel_shader.ps new file mode 100644 index 0000000..c536d72 --- /dev/null +++ b/win32/pixel_shader.ps @@ -0,0 +1,57 @@ +ps_3_0 + +; input declarations +dcl_color0 v0.xyzw +dcl_texcoord0 v1.xyzw +dcl_texcoord1 v2.xyzw +dcl_texcoord2 v3.xyzw +dcl_color1 v4.xyzw + +dcl_2d s0 + +; constants +def c0, 1.0f, 0.0f, 0.0f, 0.5f +def c1, 0.00048828125f, 0.000244140625f, 0.0f, 0.0f + + + +rcp r30, v2.z ; calculate 1/width +rcp r31, v2.w ; calculate 1/height + +mov r31.xy, c0.yy ; r31.xy <- 0,0 \ hopefully co-issue... +mov r31.z, r30.z ; / + +add r1.xyzw, v1.xyxy, r31.yyzy ; texel[0][0], texel[1][0] +add r2.xyzw, v1.xyxy, r31.ywzw ; texel[0][1], texel[1][1] +frc r1.xyzw, r1.xyzw +frc r2.xyzw, r2.xyzw +mul r3, r1, v2.zwzw ; mul by width, height +mul r4, r2, v2.zwzw ; mul by width, height +add r10, r3, v2.xyxy ; add tex base +add r11, r4, v2.xyxy ; add tex base +mul r10, r10, c1.xyxy ; div by 2048 +mul r11, r11, c1.xyxy ; div by 2048 + +frc r18, r3 + +texld r5, r10.xy, s0 +texld r6, r10.zw, s0 +texld r7, r11.xy, s0 +texld r8, r11.zw, s0 + +lrp r12, r18.xxxx, r6, r5 +lrp r13, r18.xxxx, r8, r7 +lrp r15, r18.yyyy, r13, r12 + +;if_lt v0.a, c0.x ; if polygon alpha is enabled use that instead of texture alpha +; mov r15.a, v0.a +;endif + +if_ne v4.x, c0.y ; if v4.x == 0 -> color, if v4.x != -> texture + mul_sat r15, v0, r15 ; modulate with color +else + mov r15, v0 +endif +;mov r15, v0 + +mov oC0, r15 \ No newline at end of file diff --git a/win32/pixel_shader_2d.ps b/win32/pixel_shader_2d.ps new file mode 100644 index 0000000..bcfd213 --- /dev/null +++ b/win32/pixel_shader_2d.ps @@ -0,0 +1,38 @@ +ps_3_0 + +; parameters +; c8 = color offset +; c9 = (X,Y) scroll position, (Z) 0 = rendering background, 1 = rendering foreground + +; input declarations +dcl_color v0.xyzw +dcl_texcoord0 v1.xy + +dcl_2d s0 +dcl_2d s1 +dcl_2d s2 + +def c0, 1.0, 0.0, 1.0f, 1.0f +def c1, 0.5, 0.0, 0.0, 0.0 + +add r5, v1.xy, c9.xy ; add scroll position +frc r5, r5 ; wrap + +texld r0, r5, s0 + +texld r10, v1, s2 ; load priority value +mov r11.r, c9.z + +mov r1.xy, r0.ga +texld r2, r1, s1 + +add r2.rgb, r2.rgb, c8.yzw +min r2, r2, c0.xxxx ; clamp to 1.0 +max r2, r2, c0.yyyy ; clamp to 0.0 + +if_eq r11.r, c0.y ; invert priority if rendering foreground + sub r10.r, c0.x, r10.r +endif +mul r2.a, r2.a, r10.r ; multiply alpha with priority + +mov oC0, r2 \ No newline at end of file diff --git a/win32/shaders.h b/win32/shaders.h new file mode 100644 index 0000000..dcdffe7 --- /dev/null +++ b/win32/shaders.h @@ -0,0 +1,106 @@ +unsigned char pixel_shader_source[524] = +{ + 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90, + 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, + 0x05, 0x00, 0x01, 0x80, 0x02, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x80, + 0x03, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x01, 0x80, 0x04, 0x00, 0x0F, 0x90, + 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0F, 0xA0, 0x51, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x3A, + 0x00, 0x00, 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, + 0x1E, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xAA, 0x90, 0x06, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x0F, 0x80, + 0x02, 0x00, 0xFF, 0x90, 0x01, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x03, 0x80, 0x00, 0x00, 0x55, 0xA0, + 0x01, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x04, 0x80, 0x1E, 0x00, 0xAA, 0x80, 0x02, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x0F, 0x80, 0x01, 0x00, 0x44, 0x90, 0x1F, 0x00, 0x65, 0x80, 0x02, 0x00, 0x00, 0x03, + 0x02, 0x00, 0x0F, 0x80, 0x01, 0x00, 0x44, 0x90, 0x1F, 0x00, 0xED, 0x80, 0x13, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x80, 0x13, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0F, 0x80, + 0x02, 0x00, 0xE4, 0x80, 0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x80, + 0x02, 0x00, 0xEE, 0x90, 0x05, 0x00, 0x00, 0x03, 0x04, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80, + 0x02, 0x00, 0xEE, 0x90, 0x02, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, + 0x02, 0x00, 0x44, 0x90, 0x02, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x0F, 0x80, 0x04, 0x00, 0xE4, 0x80, + 0x02, 0x00, 0x44, 0x90, 0x05, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x0F, 0x80, 0x0A, 0x00, 0xE4, 0x80, + 0x01, 0x00, 0x44, 0xA0, 0x05, 0x00, 0x00, 0x03, 0x0B, 0x00, 0x0F, 0x80, 0x0B, 0x00, 0xE4, 0x80, + 0x01, 0x00, 0x44, 0xA0, 0x13, 0x00, 0x00, 0x02, 0x12, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, + 0x42, 0x00, 0x00, 0x03, 0x05, 0x00, 0x0F, 0x80, 0x0A, 0x00, 0x54, 0x80, 0x00, 0x08, 0xE4, 0xA0, + 0x42, 0x00, 0x00, 0x03, 0x06, 0x00, 0x0F, 0x80, 0x0A, 0x00, 0xFE, 0x80, 0x00, 0x08, 0xE4, 0xA0, + 0x42, 0x00, 0x00, 0x03, 0x07, 0x00, 0x0F, 0x80, 0x0B, 0x00, 0x54, 0x80, 0x00, 0x08, 0xE4, 0xA0, + 0x42, 0x00, 0x00, 0x03, 0x08, 0x00, 0x0F, 0x80, 0x0B, 0x00, 0xFE, 0x80, 0x00, 0x08, 0xE4, 0xA0, + 0x12, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x0F, 0x80, 0x12, 0x00, 0x00, 0x80, 0x06, 0x00, 0xE4, 0x80, + 0x05, 0x00, 0xE4, 0x80, 0x12, 0x00, 0x00, 0x04, 0x0D, 0x00, 0x0F, 0x80, 0x12, 0x00, 0x00, 0x80, + 0x08, 0x00, 0xE4, 0x80, 0x07, 0x00, 0xE4, 0x80, 0x12, 0x00, 0x00, 0x04, 0x0F, 0x00, 0x0F, 0x80, + 0x12, 0x00, 0x55, 0x80, 0x0D, 0x00, 0xE4, 0x80, 0x0C, 0x00, 0xE4, 0x80, 0x29, 0x00, 0x05, 0x02, + 0x04, 0x00, 0x00, 0x90, 0x00, 0x00, 0x55, 0xA0, 0x05, 0x00, 0x00, 0x03, 0x0F, 0x00, 0x1F, 0x80, + 0x00, 0x00, 0xE4, 0x90, 0x0F, 0x00, 0xE4, 0x80, 0x2A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, + 0x0F, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xE4, 0x90, 0x2B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, + 0x00, 0x08, 0x0F, 0x80, 0x0F, 0x00, 0xE4, 0x80, 0xFF, 0xFF, 0x00, 0x00, +}; + +unsigned char pixel_shader_2d_source[324] = +{ + 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90, + 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0x90, 0x1F, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0F, 0xA0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, + 0x01, 0x08, 0x0F, 0xA0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x02, 0x08, 0x0F, 0xA0, + 0x51, 0x00, 0x00, 0x05, 0x00, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0F, 0xA0, + 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x03, 0x05, 0x00, 0x0F, 0x80, 0x01, 0x00, 0x54, 0x90, 0x09, 0x00, 0x54, 0xA0, + 0x13, 0x00, 0x00, 0x02, 0x05, 0x00, 0x0F, 0x80, 0x05, 0x00, 0xE4, 0x80, 0x42, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x0F, 0x80, 0x05, 0x00, 0xE4, 0x80, 0x00, 0x08, 0xE4, 0xA0, 0x42, 0x00, 0x00, 0x03, + 0x0A, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x90, 0x02, 0x08, 0xE4, 0xA0, 0x01, 0x00, 0x00, 0x02, + 0x0B, 0x00, 0x01, 0x80, 0x09, 0x00, 0xAA, 0xA0, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x03, 0x80, + 0x00, 0x00, 0xFD, 0x80, 0x42, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0F, 0x80, 0x01, 0x00, 0xE4, 0x80, + 0x01, 0x08, 0xE4, 0xA0, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x07, 0x80, 0x02, 0x00, 0xA4, 0x80, + 0x08, 0x00, 0xF9, 0xA0, 0x0A, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80, + 0x00, 0x00, 0x00, 0xA0, 0x0B, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80, + 0x00, 0x00, 0x55, 0xA0, 0x29, 0x00, 0x02, 0x02, 0x0B, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0xA0, + 0x02, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0xA0, 0x0A, 0x00, 0x00, 0x81, + 0x2B, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x02, 0x00, 0x08, 0x80, 0x02, 0x00, 0xFF, 0x80, + 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0F, 0x80, 0x02, 0x00, 0xE4, 0x80, + 0xFF, 0xFF, 0x00, 0x00, +}; + +unsigned char vertex_shader_source[500] = +{ + 0x00, 0x03, 0xFE, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90, + 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, + 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x80, + 0x03, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x80, 0x04, 0x00, 0x0F, 0x90, + 0x1F, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x80, 0x05, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, + 0x0A, 0x00, 0x01, 0x80, 0x06, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0xE0, + 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, + 0x05, 0x00, 0x01, 0x80, 0x03, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x80, + 0x04, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x01, 0x80, 0x05, 0x00, 0x0F, 0xE0, + 0x51, 0x00, 0x00, 0x05, 0x80, 0x00, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, + 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x01, 0x80, + 0x00, 0x00, 0xE4, 0x90, 0x00, 0x00, 0xE4, 0xA0, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x02, 0x80, + 0x00, 0x00, 0xE4, 0x90, 0x01, 0x00, 0xE4, 0xA0, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x04, 0x80, + 0x00, 0x00, 0xE4, 0x90, 0x02, 0x00, 0xE4, 0xA0, 0x09, 0x00, 0x00, 0x03, 0x14, 0x00, 0x08, 0x80, + 0x00, 0x00, 0xE4, 0x90, 0x03, 0x00, 0xE4, 0xA0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xE0, + 0x14, 0x00, 0xE4, 0x80, 0x17, 0x00, 0x00, 0x03, 0x04, 0x00, 0x07, 0x80, 0x05, 0x00, 0xE4, 0x90, + 0x04, 0x00, 0xE4, 0xA0, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0F, 0x80, 0x10, 0x00, 0xE4, 0xA1, + 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x04, 0x00, 0xE4, 0x80, 0x02, 0x00, 0xE4, 0x80, + 0x0B, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x80, 0x00, 0x00, 0xA0, + 0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x11, 0x00, 0x00, 0xA0, + 0x02, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x11, 0x00, 0x55, 0xA0, + 0x0A, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0F, 0x80, 0x03, 0x00, 0xE4, 0x80, 0x80, 0x00, 0x55, 0xA0, + 0x29, 0x00, 0x05, 0x02, 0x06, 0x00, 0x00, 0x90, 0x80, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x02, + 0x03, 0x00, 0x07, 0x80, 0x06, 0x00, 0x00, 0x90, 0x2B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, + 0x03, 0x00, 0x08, 0x80, 0x80, 0x00, 0xFF, 0xA0, 0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0F, 0xE0, + 0x01, 0x00, 0xE4, 0x90, 0x03, 0x00, 0xE4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x0F, 0x80, + 0x02, 0x00, 0xE4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x08, 0x80, 0x14, 0x00, 0xFF, 0x80, + 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0F, 0xE0, 0x0A, 0x00, 0xE4, 0x80, 0x01, 0x00, 0x00, 0x02, + 0x03, 0x00, 0x0F, 0xE0, 0x03, 0x00, 0xE4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x0F, 0xE0, + 0x04, 0x00, 0xE4, 0x90, 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0xE0, 0x06, 0x00, 0x55, 0x90, + 0xFF, 0xFF, 0x00, 0x00, +}; + +unsigned char vertex_shader_2d_source[80] = +{ + 0x00, 0x03, 0xFE, 0xFF, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0x90, + 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0F, 0x90, 0x1F, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0F, 0xE0, 0x1F, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x0F, 0xE0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xE4, 0x90, + 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0F, 0xE0, 0x01, 0x00, 0xE4, 0x90, 0xFF, 0xFF, 0x00, 0x00, +}; \ No newline at end of file diff --git a/win32/vertex_shader.vs b/win32/vertex_shader.vs new file mode 100644 index 0000000..083187c --- /dev/null +++ b/win32/vertex_shader.vs @@ -0,0 +1,71 @@ +vs_3_0 + +; parameters +; c0...c3 world-view-projection matrix +; c4...c7 world-view matrix +; c16 sun light vector +; c17 sun ambient, diffuse intensity + +; input declarations +dcl_position v0 +dcl_color0 v1 +dcl_texcoord0 v2 +dcl_texcoord1 v3 +dcl_texcoord2 v4 +dcl_normal v5 +dcl_color1 v6 + +; output declarations +dcl_position o0.xyzw +dcl_color0 o1.xyzw +dcl_texcoord0 o2.xyzw +dcl_texcoord1 o3.xyzw +dcl_texcoord2 o4.xyzw +dcl_color1 o5.xyzw + +; constants +def c128, 0.0f, 1.0f, 0.5f, 1.0f + +; transform position to projection space +;dp4 o0.x, v0, c0 +;dp4 o0.y, v0, c1 +;dp4 o0.z, v0, c2 +;dp4 o0.w, v0, c3 +dp4 r20.x, v0, c0 +dp4 r20.y, v0, c1 +dp4 r20.z, v0, c2 +dp4 r20.w, v0, c3 + +mov o0, r20 + +; calculate parallel lighting +m3x3 r4.xyz, v5, c4 ; transform N + +mov r2, -c16 +dp3 r3, r4, r2 ; N dot L +max r3, r3, c128.xxxx ; clamp negative values to 0 + +mul r3, r3, c17.xxxx ; scale with diffuse intensity +add r3, r3, c17.yyyy ; add ambient intensity + +min r3, r3, c128.yyyy + +if_ne v6.xxxx, c128.xxxx ; if v6.x == 0 -> apply lighting, if v6.x != 0 -> self-luminance +mov r3.xyz, v6.xxx ; self-luminance +endif + +mov r3.w, c128.w ; multiply alpha with 1 + +mul o1, v1, r3 ; modulate and write color +;mov o1, r3 + +; move texture parameters +mov r10,v2 +mov r10.w, r20.w +mov o2, r10 +;mov o2, v2 +mov o3, v3 +mov o4, v4 + +; parameters (X=texture enable) +mov o5.x, v6.g \ No newline at end of file diff --git a/win32/vertex_shader_2d.vs b/win32/vertex_shader_2d.vs new file mode 100644 index 0000000..1bd70da --- /dev/null +++ b/win32/vertex_shader_2d.vs @@ -0,0 +1,14 @@ +vs_3_0 + +; input declarations +dcl_position v0 +dcl_texcoord0 v1 + +; output declarations +dcl_position o0.xyzw +dcl_texcoord0 o1.xyzw + + + +mov o0, v0 +mov o1, v1 \ No newline at end of file diff --git a/win32/win_gl.c b/win32/win_gl.c new file mode 100644 index 0000000..eb1bc1a --- /dev/null +++ b/win32/win_gl.c @@ -0,0 +1,181 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * win32/win_gl.c + * + * Win32 OpenGL support. All of this will have to be rewritten to support + * run-time mode changes and fullscreen modes. + * + * The only osd_renderer function implemented here is osd_renderer_blit(). + */ + +#include "model3.h" +#include "osd_common/osd_gl.h" +#include +#include +#include + +/* + * Window Context + */ + +static HGLRC hrc = 0; // OpenGL rendering context +static HDC hdc = 0; // GDI device context +static HINSTANCE hinstance; // application instance +extern HWND main_window; // window handle + +/* + * void win_gl_init(UINT xres, UINT yres); + * + * Sets the rendering mode and initializes OpenGL. + * + * Parameters: + * xres = Horizontal resolution in pixels. + * yres = Vertical resolution. + */ + +void win_gl_init(UINT xres, UINT yres) +{ + GLuint pixel_format; + static PIXELFORMATDESCRIPTOR pfd = // must this be static? + { + sizeof(PIXELFORMATDESCRIPTOR), // size of structure + 1, // version (must be 1) + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, // RGBA pixels + 32, // color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // ignore shift bit + 0, // no accumulation buffer + 0, 0, 0, 0, // accumulation bits ignored + 24, // 24-bit z-buffer + 0, // no stencil buffer + 0, // no auxilliary buffer + PFD_MAIN_PLANE, // main drawing layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + + /* + * Get window instance + */ + + hinstance = GetModuleHandle(NULL); // get window instance + + /* + * Get device context and find a pixel format + */ + + if (!(hdc = GetDC(main_window))) + osd_error("Unable to create an OpenGL device context."); + + if (!(pixel_format = ChoosePixelFormat(hdc, &pfd))) // find matching pixel format + osd_error("Unable to find the required pixel format."); + + if (!SetPixelFormat(hdc, pixel_format, &pfd)) + osd_error("Unable to set the required pixel format."); + + /* + * Get the rendering context and perform some GL initialization + */ + + if (!(hrc = wglCreateContext(hdc))) + osd_error("Unable to create an OpenGL rendering context."); + + if (!wglMakeCurrent(hdc, hrc)) + osd_error("Unable to activate the OpenGL rendering context."); + + /* + * Check for mirrored texture repeat extension + */ + + if (osd_gl_check_extension("GL_ARB_texture_mirrored_repeat")) + osd_error("Your OpenGL implementation does not support mirrored texture repeating!"); + if (osd_gl_check_extension("GL_ARB_texture_env_combine")) + osd_error("Your OpenGL implementation does not support texture combiner operations!"); + if (osd_gl_check_extension("GL_EXT_texture_lod_bias")) + osd_error("Your OpenGL implementation does not support texture LOD bias selection!"); + if (osd_gl_check_extension("GL_ARB_vertex_buffer_object")) + osd_error("Your OpenGL implementation does not support vertex buffer objects!"); + + /* + * Initialize GL engine + */ + + osd_gl_set_mode(xres, yres); +} + +/* + * void win_gl_shutdown(void); + * + * Shuts down the rendering mode mode meaning it releases the rendering and + * device contexts. + */ + +void win_gl_shutdown(void) +{ + osd_gl_unset_mode(); + + /* + * If there is a rendering context, release it + */ + + if (hrc) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hrc); + } + + /* + * If there is a device context, release it + */ + + if (hdc) + ReleaseDC(main_window, hdc); +} + +/* + * void osd_renderer_blit(void); + * + * Swaps the buffers to display what has been rendered in the last frame. + */ + +void osd_renderer_blit(void) +{ + SwapBuffers(hdc); +} + +/* + * void * osd_gl_get_proc_address(const char *); + * + * Calls wglGetProcAddress. + */ + +void * osd_gl_get_proc_address(const CHAR * id) +{ + void * ptr = wglGetProcAddress(id); + + if (ptr == NULL) + error("GL proc %s not found!\n", id); + else + message(0, "found GL proc %s!", id); + + return ptr; +} diff --git a/win32/win_gl.h b/win32/win_gl.h new file mode 100644 index 0000000..efa8949 --- /dev/null +++ b/win32/win_gl.h @@ -0,0 +1,13 @@ +/* + * win32/win_gl.h + * + * Windows OpenGL header. + */ + +#ifndef INCLUDED_WIN32_WIN_GL_H +#define INCLUDED_WIN32_WIN_GL_H + +extern void win_gl_init(UINT, UINT); +extern void win_gl_shutdown(void); + +#endif // INCLUDED_WIN32_WIN_GL_H diff --git a/win32/win_input.c b/win32/win_input.c new file mode 100644 index 0000000..1c7c031 --- /dev/null +++ b/win32/win_input.c @@ -0,0 +1,319 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/******************************************************************/ +/* DirectX 9 Input */ +/******************************************************************/ + +#include "MODEL3.H" +#include + +static LPDIRECTINPUT8 dinput; +static LPDIRECTINPUTDEVICE8 keyboard; +static LPDIRECTINPUTDEVICE8 mouse; + +static CHAR keyboard_buffer[256]; +static DIMOUSESTATE mouse_state; + +extern HWND main_window; + +static OSD_CONTROLS controls; + +void osd_input_init(void) +{ + HINSTANCE hinstance; + HRESULT hr; + + atexit(osd_input_shutdown); + + hinstance = GetModuleHandle(NULL); + hr = DirectInput8Create( hinstance, DIRECTINPUT_VERSION, &IID_IDirectInput8, + (void**)&dinput, NULL ); + if(FAILED(hr)) + error("DirectInput8Create failed."); + + // Create keyboard device + hr = IDirectInput8_CreateDevice( dinput, &GUID_SysKeyboard, &keyboard, NULL ); + if(FAILED(hr)) + error("IDirectInput8_CreateDevice failed."); + + hr = IDirectInputDevice8_SetDataFormat( keyboard, &c_dfDIKeyboard ); + if(FAILED(hr)) + error("IDirectInputDevice8_SetDataFormat failed."); + + hr = IDirectInputDevice8_SetCooperativeLevel( keyboard, main_window, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); + if(FAILED(hr)) + error("IDirectInputDevice8_SetCooperativeLevel failed."); + + if(keyboard) + IDirectInputDevice8_Acquire( keyboard ); + + // Create mouse device + hr = IDirectInput8_CreateDevice( dinput, &GUID_SysMouse, &mouse, NULL ); + if(FAILED(hr)) + error("IDirectInput8_CreateDevice failed."); + + hr = IDirectInputDevice8_SetDataFormat( mouse, &c_dfDIMouse ); + if(FAILED(hr)) + error("IDirectInputDevice8_SetDataFormat failed."); + + hr = IDirectInputDevice8_SetCooperativeLevel( mouse, main_window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE ); + if(FAILED(hr)) + error("IDirectInputDevice8_SetCooperativeLevel failed."); +} + +void osd_input_shutdown(void) +{ + if(dinput) { + if(keyboard) { + IDirectInputDevice8_Unacquire( keyboard ); + IDirectInputDevice8_Release( keyboard ); + keyboard = NULL; + } + if(mouse) { + IDirectInputDevice8_Unacquire( mouse ); + IDirectInputDevice8_Release( mouse ); + mouse = NULL; + } + IDirectInput8_Release( dinput ); + dinput = NULL; + } +} + +static void input_update(void) +{ + /* updates the input buffer */ + if(dinput) { + // Get keyboard state + IDirectInputDevice8_GetDeviceState( keyboard, sizeof(keyboard_buffer), &keyboard_buffer ); + // Get mouse state + IDirectInputDevice8_Acquire( mouse ); + IDirectInputDevice8_GetDeviceState( mouse, sizeof(mouse_state), &mouse_state ); + } +} + +static BOOL keyboard_get_key(UINT8 key) +{ + if(keyboard_buffer[key] & 0x80) + return TRUE; + else + return FALSE; +} + +static BOOL mouse_get_button(UINT8 button) +{ + if(mouse_state.rgbButtons[button] & 0x80) + return TRUE; + else + return FALSE; +} + +static void mouse_get_position(INT32* xposition, INT32* yposition) +{ + POINT mouse_pos; + + GetCursorPos( &mouse_pos ); + ScreenToClient( main_window, &mouse_pos ); + + *xposition = mouse_pos.x + (400 - (MODEL3_SCREEN_WIDTH / 2)); + *yposition = mouse_pos.y + (272 - (MODEL3_SCREEN_HEIGHT / 2)); +} + +OSD_CONTROLS* osd_input_update_controls(void) +{ + INT32 mouse_x, mouse_y; + input_update(); + + controls.game_controls[0] = 0xFF; + controls.game_controls[1] = 0xFF; + controls.system_controls[0] = 0xFF; + controls.system_controls[1] = 0xFF; + + // Lightgun + if(mouse_get_button(0)) + controls.game_controls[0] &= ~0x01; + + if(mouse_get_button(1)) + controls.gun_acquired[0] = TRUE; + else + controls.gun_acquired[0] = FALSE; + + mouse_get_position(&mouse_x, &mouse_y); + controls.gun_x[0] = mouse_x; + controls.gun_y[0] = mouse_y; + + // Game controls + if(keyboard_get_key(DIK_A)) + controls.game_controls[0] &= ~0x01; + if(keyboard_get_key(DIK_S)) + controls.game_controls[0] &= ~0x02; + if(keyboard_get_key(DIK_D)) + controls.game_controls[0] &= ~0x04; + if(keyboard_get_key(DIK_F)) + controls.game_controls[0] &= ~0x08; + if(keyboard_get_key(DIK_G)) + controls.game_controls[0] &= ~0x80; + if(keyboard_get_key(DIK_H)) + controls.game_controls[0] &= ~0x40; + + if(keyboard_get_key(DIK_Q)) + controls.game_controls[0] &= ~0x80; + if(keyboard_get_key(DIK_W)) + controls.game_controls[0] &= ~0x40; + if(keyboard_get_key(DIK_E)) + controls.game_controls[0] &= ~0x20; + if(keyboard_get_key(DIK_R)) + controls.game_controls[0] &= ~0x10; + if(keyboard_get_key(DIK_T)) + controls.game_controls[1] &= ~0x80; + if(keyboard_get_key(DIK_Y)) + controls.game_controls[1] &= ~0x40; + if(keyboard_get_key(DIK_U)) + controls.game_controls[1] &= ~0x20; + if(keyboard_get_key(DIK_I)) + controls.game_controls[1] &= ~0x10; + + if(keyboard_get_key(DIK_Z)) // VON2, shot trigger 1 + controls.game_controls[0] &= ~0x01; + if(keyboard_get_key(DIK_X)) // VON2, shot trigger 2 + controls.game_controls[1] &= ~0x01; + if(keyboard_get_key(DIK_C)) // VON2, turbo 1 + controls.game_controls[0] &= ~0x02; + if(keyboard_get_key(DIK_V)) // VON2, turbo 2 + controls.game_controls[1] &= ~0x02; + + /*if(keyboard_get_key(DIK_UP) || keyboard_get_key(DIK_NUMPAD8)) { + controls.game_controls[0] &= ~0x20; // VON2, forward + controls.game_controls[1] &= ~0x20; + } + if(keyboard_get_key(DIK_DOWN) || keyboard_get_key(DIK_NUMPAD2)) { + controls.game_controls[0] &= ~0x10; // VON2, backward + controls.game_controls[1] &= ~0x10; + } + if(keyboard_get_key(DIK_LEFT) || keyboard_get_key(DIK_NUMPAD4)) { + controls.game_controls[0] &= ~0x10; // VON2, turn left + controls.game_controls[1] &= ~0x20; + } + if(keyboard_get_key(DIK_RIGHT) || keyboard_get_key(DIK_NUMPAD6)) { + controls.game_controls[0] &= ~0x20; // VON2, turn right + controls.game_controls[1] &= ~0x10; + }*/ + if(keyboard_get_key(DIK_NUMPAD1)) {// VON2, strafe left + controls.game_controls[0] &= ~0x80; + controls.game_controls[1] &= ~0x80; + } + if(keyboard_get_key(DIK_NUMPAD3)) {// VON2, strafe right + controls.game_controls[0] &= ~0x40; + controls.game_controls[1] &= ~0x40; + } + if(keyboard_get_key(DIK_NUMPAD5)) {// VON2, jump + controls.game_controls[0] &= ~0x80; + controls.game_controls[1] &= ~0x40; + } + + // System controls + if(keyboard_get_key(DIK_F1)) { // Test button + controls.system_controls[0] &= ~0x04; + controls.system_controls[1] &= ~0x04; + } + if(keyboard_get_key(DIK_F2)) { // Service button + controls.system_controls[0] &= ~0x08; + controls.system_controls[1] &= ~0x80; + } + if(keyboard_get_key(DIK_F3)) { // Start button + controls.system_controls[0] &= ~0x10; + } + if(keyboard_get_key(DIK_F4)) { // Coin #1 + controls.system_controls[0] &= ~0x01; + } + + // Steering Wheel +#if 0 + if(keyboard_get_key(DIK_LEFT)) + controls.steering -= 32; + if(keyboard_get_key(DIK_RIGHT)) + controls.steering += 32; + + if(controls.steering > 0) { + controls.steering -= 16; + if(controls.steering < 0) + controls.steering = 0; + } else { + controls.steering += 16; + if(controls.steering > 0) + controls.steering = 0; + } + + if(controls.steering < -128) + controls.steering = -128; + if(controls.steering > 127) + controls.steering = 127; + + if(keyboard_get_key(DIK_UP)) + controls.acceleration += 32; + else + controls.acceleration -= 16; + + if(controls.acceleration < 0) + controls.acceleration = 0; + if(controls.acceleration > 0xFF) + controls.acceleration = 0xFF; + + if(keyboard_get_key(DIK_DOWN)) + controls.brake += 32; + else + controls.brake -= 16; + + if(controls.brake < 0) + controls.brake = 0; + if(controls.brake > 0xFF) + controls.brake = 0xFF; +#else + + /* SWT Force Feedback joystick */ + if(keyboard_get_key(DIK_UP)) + controls.steering -= 16; + if(keyboard_get_key(DIK_DOWN)) + controls.steering += 16; + + if(controls.steering < -128) + controls.steering = -128; + if(controls.steering > 127) + controls.steering = 127; + + if(keyboard_get_key(DIK_RIGHT)) { + controls.acceleration += 16; + controls.brake -= 16; + } + if(keyboard_get_key(DIK_LEFT)) { + controls.brake += 16; + controls.acceleration -= 16; + } + + if(controls.acceleration < 0) + controls.acceleration = 0; + if(controls.acceleration > 0xFF) + controls.acceleration = 0xFF; + if(controls.brake < 0) + controls.brake = 0; + if(controls.brake > 0xFF) + controls.brake = 0xFF; +#endif + + return &controls; +} diff --git a/win32/win_main.c b/win32/win_main.c new file mode 100644 index 0000000..74265a9 --- /dev/null +++ b/win32/win_main.c @@ -0,0 +1,463 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/******************************************************************/ +/* Windows Main */ +/******************************************************************/ + +#include "model3.h" +#ifdef RENDERER_D3D +#include "dx_render.h" +#else // RENDERER_GL +#include "win_gl.h" +#endif + +#define XRES (496) +#define YRES (384) + +static CHAR app_title[] = "Supermodel"; +static CHAR app_version[] = "1.0"; +static CHAR class_name[] = "MODEL3"; + +static CHAR CONFIG_FILE[] = "config.xml"; + +HWND main_window; + +// Window Procedure prototype +static LRESULT CALLBACK win_window_proc(HWND, UINT, WPARAM, LPARAM); + +static BOOL win_register_class(void) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)win_window_proc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = NULL; + wcex.hIconSm = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = class_name; + + if (FAILED(RegisterClassEx(&wcex))) // MinGW: "comparison is always false due to limited range of data" + return FALSE; + + return TRUE; +} + +static BOOL win_create_window(UINT xres, UINT yres) +{ + DWORD frame_width, frame_height, caption_height; + int width, height, window_width, window_height; + + window_width = xres; + window_height = yres; + + frame_width = GetSystemMetrics(SM_CXSIZEFRAME); + frame_height = GetSystemMetrics(SM_CYSIZEFRAME); + caption_height = GetSystemMetrics(SM_CYCAPTION); + + width = (window_width - 1) + (frame_width * 2); + height = (window_height - 1) + (frame_height * 2) + caption_height; + + main_window = CreateWindow(class_name, + app_title, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | // required for OpenGL + WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, // Window X & Y coords + width - 1, height - 1, // Width & Height + NULL, NULL, // Parent Window & Menu + GetModuleHandle(NULL), NULL ); + + if (!main_window) + return FALSE; + + return TRUE; +} + +/* + * NOTE: This should actually return an error if something goes wrong, but + * it doesn't matter now. This stuff probably needs to be rewritten anyway ;) + */ +static void win_destroy(void) +{ +#ifdef RENDERER_D3D + d3d_shutdown(); +#else // RENDERER_GL + win_gl_shutdown(); +#endif + DestroyWindow(main_window); + UnregisterClass(class_name, GetModuleHandle(NULL)); +} + +void *malloc_exec(int length) +{ + void *ptr; + ptr = VirtualAlloc(NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + if (ptr == NULL) + { + error("malloc_exec %d failed\n", length); + } + + return ptr; +} + +void free_exec(void *ptr) +{ + if (VirtualFree(ptr, 0, MEM_RELEASE) == FALSE) + { + error("free_exec failed\n"); + } +} + +BOOL check_cpu_features(void) +{ + BOOL features_ok = TRUE; + char cpuname[256]; + UINT32 cpu_version; + UINT32 cpu_features; + + memset(cpuname, 0, sizeof(cpuname)); + + __asm + { + // get cpu name string + mov eax, 0x80000002 + cpuid + mov dword ptr [cpuname+0 ], eax + mov dword ptr [cpuname+4 ], ebx + mov dword ptr [cpuname+8 ], ecx + mov dword ptr [cpuname+12 ], edx + mov eax, 0x80000003 + cpuid + mov dword ptr [cpuname+16 ], eax + mov dword ptr [cpuname+20 ], ebx + mov dword ptr [cpuname+24 ], ecx + mov dword ptr [cpuname+28 ], edx + mov eax, 0x80000004 + cpuid + mov dword ptr [cpuname+32 ], eax + mov dword ptr [cpuname+36 ], ebx + mov dword ptr [cpuname+40 ], ecx + mov dword ptr [cpuname+44 ], edx + + // get cpu version and features + mov eax, 1 + cpuid + mov [cpu_version], eax + mov [cpu_features], edx + } + message(0, "CPU: %s", cpuname); + if ((cpu_features & (1 << 15)) == 0) + { + message(0, "CPU doesn't support Conditional Move/Compare instructions"); + features_ok = FALSE; + } + if ((cpu_features & (1 << 23)) == 0) + { + message(0, "CPU doesn't support MMX instructions"); + features_ok = FALSE; + } + if ((cpu_features & (1 << 25)) == 0) + { + message(0, "CPU doesn't support SSE instructions"); + features_ok = FALSE; + } + if ((cpu_features & (1 << 26)) == 0) + { + message(0, "CPU doesn't support SSE2 instructions"); + features_ok = FALSE; + } + + if (features_ok == FALSE) + { + message(0, "The CPU doesn't meet the requirements, the program will not run further."); + } + return features_ok; +} + +int main(int argc, char *argv[]) +{ + MSG msg; + BOOL quit = FALSE, do_fps; + INT64 freq, time_start, time_end; + char title[256]; + double fps = 0.0; + int frame = 0; + + if(argc < 2) { + // Show usage + printf("ERROR: not enough arguments.\n\n"); + printf("Usage: m3.exe [romset]\n"); + return 0; + } + + message(0, "%s v%s\n", app_title, app_version); + + if (check_cpu_features() == FALSE) + { + exit(1); + } + + if (d3d_pre_init() == FALSE) + { + message(0, "The video card doesn't meet the requirements, the program will not run further."); + exit(1); + } + + message(0, ""); + + // Load config + + if (parse_config(CONFIG_FILE) == FALSE) + { + exit(1); + } + m3_config.layer_enable = 0xF; + + // Parse command-line + + strncpy(m3_config.game_id, argv[1], 8); + m3_config.game_id[8] = '\0'; // in case game name was 8 or more chars + + if (stricmp(m3_config.game_id, "lostwsga") == 0) + { + m3_config.has_lightgun = TRUE; + } + + // Some initialization + + if (!win_register_class()) + { + message(0, "win_register_class failed."); + exit(1); + } + if (!win_create_window(XRES, YRES)) + { + message(0, "win_create_window failed."); + exit(1); + } + + if (model3_load() == FALSE) + { + message(0, "ROM loading failed"); + exit(1); + } + model3_init(); + model3_reset(); + + if (!d3d_init(main_window)) + { + message(0, "d3d_init failed."); + exit(1); + } + + if (osd_input_init() == FALSE) + { + exit(1); + } + + // Set window title to show the game name + sprintf(title, "%s: %s", app_title, m3_config.game_name); + SetWindowText(main_window, title); + + // Now that everything works, we can show the window + + ShowWindow(main_window, SW_SHOWNORMAL); + SetForegroundWindow(main_window); + SetFocus(main_window); + UpdateWindow(main_window); + + if (m3_config.fullscreen && !m3_config.has_lightgun) + { + ShowCursor(FALSE); + } + + if(QueryPerformanceFrequency((LARGE_INTEGER *)&freq)) + do_fps = TRUE; + else + do_fps = FALSE; + + memset(&msg, 0, sizeof(MSG)); + while (quit == FALSE) + { + //QueryPerformanceCounter((LARGE_INTEGER *)&time_start); + + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + quit = TRUE; + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + model3_run_frame(); + frame++; + + // gather profiler stats + + //QueryPerformanceCounter((LARGE_INTEGER *)&time_end); + if (frame >= 5) + { + frame = 0; + QueryPerformanceCounter((LARGE_INTEGER *)&time_end); + fps = 5.0 / ((double)(time_end - time_start) / freq); + + time_start = time_end; + } + + if (m3_config.show_fps) + { + //fps = 1.0 / ((double)(time_end - time_start) / freq); + sprintf(title, "FPS: %.3f", fps); + osd_renderer_draw_text(2, 2, title, 0xffff0000, TRUE); + } + + //osd_renderer_draw_text(2, 2, title, 0x00ff0000, TRUE); + + osd_renderer_blit(); + +#ifdef _PROFILE_ + profile_print(prof); + + printf(prof); +#endif + } + + //for (i = 0; i < 32; i += 4) + // printf("R%d=%08X\tR%d=%08X\tR%d=%08X\tR%d=%08X\n", + // i + 0, ppc_get_reg(PPC_REG_R0 + i + 0), + // i + 1, ppc_get_reg(PPC_REG_R0 + i + 1), + // i + 2, ppc_get_reg(PPC_REG_R0 + i + 2), + // i + 3, ppc_get_reg(PPC_REG_R0 + i + 3)); + exit(0); +} + +void osd_warning() +{ + +} + +void osd_error(CHAR * string) +{ + printf("ERROR: %s\n",string); + exit(0); +} + +static LRESULT CALLBACK win_window_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + CHAR fname[13]; + static UINT xres = 496, yres = 384; + + switch(message) + { + case WM_DESTROY: + { + PostQuitMessage(0); + break; + } + + case WM_KEYDOWN: + { + switch (wParam) + { + default: + break; + + case '7': + m3_config.layer_enable ^= 1; + break; + case '8': + m3_config.layer_enable ^= 2; + break; + case '9': + m3_config.layer_enable ^= 4; + break; + case '0': + m3_config.layer_enable ^= 8; + break; + case 0x36: + m3_config.layer_enable = 0xF; + break; + case VK_ESCAPE: + DestroyWindow(hWnd); + break; + /*case VK_F7: + strncpy(fname, m3_config.game_id, 8); + fname[8] = '\0'; + strcat(fname, ".sta"); + model3_save_state(fname); + break; + case VK_F8: + strncpy(fname, m3_config.game_id, 8); + fname[8] = '\0'; + strcat(fname, ".sta"); + model3_load_state(fname); + break;*/ + } + break; + } + + case WM_KEYUP: + { + switch (wParam) + { + default: + break; + + case VK_F11: + { + if (m3_config.fps_limit) + { + m3_config.fps_limit = FALSE; + } + else + { + m3_config.fps_limit = TRUE; + } + break; + } + case VK_F12: + { + if (m3_config.show_fps) + { + m3_config.show_fps = FALSE; + } + else + { + m3_config.show_fps = TRUE; + } + break; + } + break; + } + } + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} diff --git a/win32/win_xinput.c b/win32/win_xinput.c new file mode 100644 index 0000000..9a37a84 --- /dev/null +++ b/win32/win_xinput.c @@ -0,0 +1,463 @@ +/* + * Sega Model 3 Emulator + * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program (license.txt); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/******************************************************************/ +/* XInput for Xbox360 controller */ +/******************************************************************/ + +#include "MODEL3.H" +#include +#include + +static LPDIRECTINPUT8 dinput; +static LPDIRECTINPUTDEVICE8 keyboard; +static LPDIRECTINPUTDEVICE8 mouse; + +static CHAR keyboard_buffer[256]; +static DIMOUSESTATE mouse_state; + +extern HWND main_window; + +static OSD_CONTROLS controls; + +static int xbox_controllers[4]; + + +static int analog_axis[8]; +static BOOL button_state[16]; + +static struct +{ + BOOL up, down, left, right; +} joystick[4]; + +BOOL osd_input_init(void) +{ + HINSTANCE hinstance; + HRESULT hr; + + DWORD result; + XINPUT_STATE state; + + atexit(osd_input_shutdown); + + hinstance = GetModuleHandle(NULL); + hr = DirectInput8Create( hinstance, DIRECTINPUT_VERSION, &IID_IDirectInput8, + (void**)&dinput, NULL ); + if (FAILED(hr)) + { + message(0, "DirectInput8Create failed."); + return FALSE; + } + + // Create keyboard device + hr = IDirectInput8_CreateDevice( dinput, &GUID_SysKeyboard, &keyboard, NULL ); + if (FAILED(hr)) + { + message(0, "IDirectInput8_CreateDevice failed."); + return FALSE; + } + + hr = IDirectInputDevice8_SetDataFormat( keyboard, &c_dfDIKeyboard ); + if (FAILED(hr)) + { + message(0, "IDirectInputDevice8_SetDataFormat failed."); + return FALSE; + } + + hr = IDirectInputDevice8_SetCooperativeLevel( keyboard, main_window, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); + if (FAILED(hr)) + { + message(0, "IDirectInputDevice8_SetCooperativeLevel failed."); + return FALSE; + } + + if (keyboard) + { + IDirectInputDevice8_Acquire( keyboard ); + } + + // Create mouse device + hr = IDirectInput8_CreateDevice( dinput, &GUID_SysMouse, &mouse, NULL ); + if (FAILED(hr)) + { + message(0, "IDirectInput8_CreateDevice failed."); + return FALSE; + } + + hr = IDirectInputDevice8_SetDataFormat( mouse, &c_dfDIMouse ); + if (FAILED(hr)) + { + message(0, "IDirectInputDevice8_SetDataFormat failed."); + return FALSE; + } + + hr = IDirectInputDevice8_SetCooperativeLevel( mouse, main_window, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE ); + if (FAILED(hr)) + { + message(0, "IDirectInputDevice8_SetCooperativeLevel failed."); + return FALSE; + } + + // Init Xbox360 controllers + ZeroMemory(&state, sizeof(XINPUT_STATE)); + + // Simply get the state of the controller from XInput. + result = XInputGetState(0, &state); + + if (result == ERROR_SUCCESS) + { + // Controller is connected + xbox_controllers[0] = 1; + message(0, "Xbox360 controller found!"); + } + else + { + // Controller is not connected + xbox_controllers[0] = 0; + } + + return TRUE; +} + +void osd_input_shutdown(void) +{ + if(dinput) + { + if(keyboard) + { + IDirectInputDevice8_Unacquire( keyboard ); + IDirectInputDevice8_Release( keyboard ); + keyboard = NULL; + } + if(mouse) + { + IDirectInputDevice8_Unacquire( mouse ); + IDirectInputDevice8_Release( mouse ); + mouse = NULL; + } + IDirectInput8_Release( dinput ); + dinput = NULL; + } +} + +static void input_update(void) +{ + /* updates the input buffer */ + if(dinput) + { + // Get keyboard state + IDirectInputDevice8_GetDeviceState( keyboard, sizeof(keyboard_buffer), &keyboard_buffer ); + // Get mouse state + IDirectInputDevice8_Acquire( mouse ); + IDirectInputDevice8_GetDeviceState( mouse, sizeof(mouse_state), &mouse_state ); + } +} + +static BOOL keyboard_get_key(UINT8 key) +{ + if (keyboard_buffer[key] & 0x80) + { + return TRUE; + } + else + { + return FALSE; + } +} + +static BOOL mouse_get_button(UINT8 button) +{ + if (mouse_state.rgbButtons[button] & 0x80) + { + return TRUE; + } + else + { + return FALSE; + } +} + +static void mouse_get_position(INT32* xposition, INT32* yposition) +{ + POINT mouse_pos; + + GetCursorPos( &mouse_pos ); + ScreenToClient( main_window, &mouse_pos ); + + *xposition = mouse_pos.x; + *yposition = mouse_pos.y; +} + +static void update_controls_keyboard(void) +{ + memset(button_state, 0, sizeof(button_state)); + memset(joystick, 0, sizeof(joystick)); + + if (keyboard_get_key(DIK_A)) button_state[0] = 1; + if (keyboard_get_key(DIK_S)) button_state[1] = 1; + if (keyboard_get_key(DIK_D)) button_state[2] = 1; + if (keyboard_get_key(DIK_F)) button_state[3] = 1; + if (keyboard_get_key(DIK_Z)) button_state[4] = 1; + if (keyboard_get_key(DIK_X)) button_state[5] = 1; + if (keyboard_get_key(DIK_C)) button_state[6] = 1; + if (keyboard_get_key(DIK_V)) button_state[7] = 1; + + if (keyboard_get_key(DIK_LEFT)) joystick[0].left = TRUE; + if (keyboard_get_key(DIK_RIGHT)) joystick[0].right = TRUE; + if (keyboard_get_key(DIK_UP)) joystick[0].up = TRUE; + if (keyboard_get_key(DIK_DOWN)) joystick[0].down = TRUE; + + if (keyboard_get_key(DIK_LEFT)) analog_axis[0] -= 16; + if (keyboard_get_key(DIK_RIGHT)) analog_axis[0] += 16; + if (keyboard_get_key(DIK_UP)) analog_axis[1] -= 16; + if (keyboard_get_key(DIK_DOWN)) analog_axis[1] += 16; + + if (analog_axis[0] < -128) analog_axis[0] = -128; + if (analog_axis[0] > 127) analog_axis[0] = 127; + if (analog_axis[1] < -128) analog_axis[1] = -128; + if (analog_axis[1] > 127) analog_axis[1] = 127; +} + +static void update_controls_xbox(void) +{ + XINPUT_STATE state; + DWORD res; + + memset(button_state, 0, sizeof(button_state)); + memset(analog_axis, 0, sizeof(analog_axis)); + memset(joystick, 0, sizeof(joystick)); + + res = XInputGetState(0, &state); + if (res == ERROR_SUCCESS) + { + // Zero value if thumbsticks are within the dead zone + if ((state.Gamepad.sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && + state.Gamepad.sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)) + { + state.Gamepad.sThumbLX = 0; + } + if ((state.Gamepad.sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && + state.Gamepad.sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)) + { + + state.Gamepad.sThumbLY = 0; + } + + if ((state.Gamepad.sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && + state.Gamepad.sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)) + { + state.Gamepad.sThumbRX = 0; + } + if ((state.Gamepad.sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && + state.Gamepad.sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)) + { + state.Gamepad.sThumbRY = 0; + } + + + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) button_state[0] = TRUE; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) button_state[1] = TRUE; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) button_state[2] = TRUE; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) button_state[3] = TRUE; + + if (state.Gamepad.sThumbLX < 0) joystick[0].left = TRUE; + if (state.Gamepad.sThumbLX > 0) joystick[0].right = TRUE; + if (state.Gamepad.sThumbLY < 0) joystick[0].up = TRUE; + if (state.Gamepad.sThumbLY > 0) joystick[0].down = TRUE; + + analog_axis[0] = state.Gamepad.sThumbLX / 256; + analog_axis[1] = state.Gamepad.sThumbLY / 256; + analog_axis[2] = state.Gamepad.bRightTrigger; + analog_axis[3] = state.Gamepad.bLeftTrigger; + analog_axis[4] = state.Gamepad.sThumbRX; + analog_axis[5] = state.Gamepad.sThumbRY; + } +} + +static int get_analog_axis(GAME_ANALOG axis) +{ + switch (axis) + { + case ANALOG_AXIS_1: return analog_axis[0]; + case ANALOG_AXIS_2: return analog_axis[1]; + case ANALOG_AXIS_3: return analog_axis[2]; + case ANALOG_AXIS_4: return analog_axis[3]; + case ANALOG_AXIS_5: return analog_axis[4]; + case ANALOG_AXIS_6: return analog_axis[5]; + case ANALOG_AXIS_7: return analog_axis[6]; + case ANALOG_AXIS_8: return analog_axis[7]; + } + + return 0; +} + +static BOOL is_button_pressed(GAME_BUTTON button) +{ + switch (button) + { + case P1_BUTTON_1: return button_state[0]; + case P1_BUTTON_2: return button_state[1]; + case P1_BUTTON_3: return button_state[2]; + case P1_BUTTON_4: return button_state[3]; + case P1_BUTTON_5: return button_state[4]; + case P1_BUTTON_6: return button_state[5]; + case P1_BUTTON_7: return button_state[6]; + case P1_BUTTON_8: return button_state[7]; + case P2_BUTTON_1: return button_state[8]; + case P2_BUTTON_2: return button_state[9]; + case P2_BUTTON_3: return button_state[10]; + case P2_BUTTON_4: return button_state[11]; + case P2_BUTTON_5: return button_state[12]; + case P2_BUTTON_6: return button_state[13]; + case P2_BUTTON_7: return button_state[14]; + case P2_BUTTON_8: return button_state[15]; + case P1_JOYSTICK_UP: return joystick[0].up; + case P1_JOYSTICK_DOWN: return joystick[0].down; + case P1_JOYSTICK_LEFT: return joystick[0].left; + case P1_JOYSTICK_RIGHT: return joystick[0].right; + } + + return FALSE; +} + +OSD_CONTROLS* osd_input_update_controls(void) +{ + int i; + INT32 mouse_x, mouse_y; + input_update(); + + controls.game_controls[0] = 0xFF; + controls.game_controls[1] = 0xFF; + controls.system_controls[0] = 0xFF; + controls.system_controls[1] = 0xFF; + + // Lightgun + if(mouse_get_button(0)) + controls.game_controls[0] &= ~0x01; + + if(mouse_get_button(1)) + controls.gun_acquired[0] = TRUE; + else + controls.gun_acquired[0] = FALSE; + + mouse_get_position(&mouse_x, &mouse_y); + if (!m3_config.fullscreen) + { + controls.gun_x[0] = mouse_x + (400 - (MODEL3_SCREEN_WIDTH / 2)); + controls.gun_y[0] = mouse_y + (272 - (MODEL3_SCREEN_HEIGHT / 2)); + } + else + { + if (m3_config.stretch) + { + mouse_x = (mouse_x * 496) / m3_config.width; + mouse_y = (mouse_y * 384) / m3_config.height; + } + + controls.gun_x[0] = mouse_x + (400 - (MODEL3_SCREEN_WIDTH / 2)); + controls.gun_y[0] = mouse_y + (272 - (MODEL3_SCREEN_HEIGHT / 2)); + } + + // Game controls + if (xbox_controllers[0]) + { + update_controls_xbox(); + } + else + { + update_controls_keyboard(); + } + + // update button states + for (i=0; i < 16; i++) + { + if (m3_config.controls.button[i].enabled) + { + if (is_button_pressed(m3_config.controls.button[i].mapping)) + { + int set = m3_config.controls.button[i].control_set; + controls.game_controls[set] &= ~m3_config.controls.button[i].control_bit; + } + } + } + + // update analog controls + for (i=0; i < 8; i++) + { + if (m3_config.controls.analog_axis[i].enabled) + { + int value = get_analog_axis(m3_config.controls.analog_axis[i].mapping); + value += m3_config.controls.analog_axis[i].center; + controls.analog_axis[i] = value; + } + } + + // Lightgun hack for Star Wars Trilogy + if (stricmp(m3_config.game_id, "swtrilgy") == 0) + { + mouse_get_position(&mouse_x, &mouse_y); + + mouse_x = (mouse_x * 256) / ((m3_config.fullscreen) ? m3_config.width : 496); + mouse_y = (mouse_y * 256) / ((m3_config.fullscreen) ? m3_config.height : 384); + + controls.analog_axis[0] = mouse_y; + controls.analog_axis[1] = mouse_x; + + if (mouse_get_button(1)) + controls.game_controls[0] &= ~0x01; + if (mouse_get_button(0)) + controls.game_controls[0] &= ~0x20; + } + + // System controls + if (keyboard_get_key(DIK_F1)) // Service button + { + controls.system_controls[0] &= ~0x08; + } + if (keyboard_get_key(DIK_F2)) // Test button + { + controls.system_controls[0] &= ~0x04; + } + if (keyboard_get_key(DIK_F3)) // Service button B + { + controls.system_controls[1] &= ~0x40; + } + if (keyboard_get_key(DIK_F4)) // Test button B + { + controls.system_controls[1] &= ~0x80; + } + if (keyboard_get_key(DIK_1)) // Start button 1 + { + controls.system_controls[0] &= ~0x10; + } + if (keyboard_get_key(DIK_2)) // Start button 2 + { + controls.system_controls[0] &= ~0x20; + } + if (keyboard_get_key(DIK_5)) // Coin #1 + { + controls.system_controls[0] &= ~0x01; + } + if (keyboard_get_key(DIK_6)) // Coin #2 + { + controls.system_controls[0] &= ~0x02; + } + + return &controls; +} diff --git a/zlib/ChangeLog b/zlib/ChangeLog new file mode 100644 index 0000000..e68e07b --- /dev/null +++ b/zlib/ChangeLog @@ -0,0 +1,722 @@ + + ChangeLog file for zlib + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occuring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/zlib/FAQ b/zlib/FAQ new file mode 100644 index 0000000..b638815 --- /dev/null +++ b/zlib/FAQ @@ -0,0 +1,315 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://www.zlib.org which may have more recent information. +The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. + See the file win32/DLL_FAQ.txt in the zlib distribution. + Pointers to the precompiled DLL are found in the zlib web site at + http://www.zlib.org. + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://www.winimage.com/zLibDll/ + * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm + * contrib/visual-basic.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR + + Make sure that before the call of compress, the length of the compressed + buffer is equal to the total size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR + + Before making the call, make sure that avail_in and avail_out are not + zero. When setting the parameter flush equal to Z_FINISH, also make sure + that avail_out is big enough to allow processing all pending input. + Note that a Z_BUF_ERROR is not fatal--another call to deflate() or + inflate() can be made with more input or output space. A Z_BUF_ERROR + may in fact be unavoidable depending on how the functions are used, since + it is not possible to tell whether or not there is more output pending + when strm.avail_out returns with zero. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h for the moment, and Francis S. Lin has converted it to a + web page zlib.html. Volunteers to transform this to Unix-style man pages, + please contact Jean-loup Gailly (jloup@gzip.org). Examples of zlib usage + are in the files example.c and minigzip.c. + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple + package. zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of + zlib. Please try to reproduce the problem with a small program and send + the corresponding source to us at zlib@gzip.org . Do not send + multi-megabyte data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + See the directory contrib/minizip in the zlib distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + make clean + ./configure -s + make + +14. How do I install a shared zlib library on Unix? + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to it. + +15. I have a question about OttoPDF + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site Joel Hainley jhainley@myndkryme.com. + +16. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip + formats use the same compressed data format internally, but have different + headers and trailers around the compressed data. + +17. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about + a single file, such as the name and last modification date. The zlib + format on the other hand was designed for in-memory and communication + channel applications, and has a much more compact header and trailer and + uses a faster integrity check than gzip. + +18. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode + the gzip format using inflateInit2(). Read zlib.h for more details. + + Note that you cannot specify special gzip header contents (e.g. a file + name or modification date), nor will inflate tell you what was in the + gzip header. If you need to customize the header or see what's in it, + you can use the raw deflate and inflate operations and the crc32() + function and roll your own gzip encoding and decoding. Read the gzip + RFC 1952 for details of the header and trailer format. + +19. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's Init functions allow + for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +20. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +21. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +22. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +23. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +24. Will zlib work on a 64-bit machine? + + It should. It has been tested on 64-bit machines, and has no dependence + on any data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +25. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format + than does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +26. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically + use Z_FULL_FLUSH, carefully write all the pending data at those points, + and keep an index of those locations, then you can start decompression + at those points. You have to be careful to not use Z_FULL_FLUSH too + often, since it can significantly degrade compression. + +27. Does zlib work on MVS, OS/390, CICS, etc.? + + We don't know for sure. We have heard occasional reports of success on + these systems. If you do use it on one of these, please provide us with + a report, instructions, and patches that we can reference when we get + these questions. Thanks. + +28. Is there some simpler, easier to read version of inflate I can look at + to understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +29. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +30. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit + only if the compiler's "long" type is 32 bits. If the compiler's "long" + type is 64 bits, then the limit is 16 exabytes. + +31. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib + is compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of a 4K string space, other than the caller of + gzprintf() assuring that the output will not exceed 4K. On the other + hand, if zlib is compiled to use snprintf() or vsnprintf(), which should + normally be the case, then there is no vulnerability. The ./configure + script will display warnings if an insecure variation of sprintf() will + be used by gzprintf(). Also the zlibCompileFlags() function will return + information on what variant of sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability. + +32. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://www.zlib.org/ + +33. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pendantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly. So now, we simply make sure that the code always + works. + +34. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +35. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very weak + and can be broken with freely available programs. To get strong encryption, + use gpg ( http://www.gnupg.org/ ) which already includes zlib compression. + For PKZIP compatible "encryption", look at http://www.info-zip.org/ + +36. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion + with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specficiation in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +37. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. + In any case, the compression improvements are so modest compared to other + more modern approaches, that it's not worth the effort to implement. + +38. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/zlib/INDEX b/zlib/INDEX new file mode 100644 index 0000000..378b684 --- /dev/null +++ b/zlib/INDEX @@ -0,0 +1,48 @@ +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile makefile for Unix (generated by configure) +Makefile.in makefile for Unix (template for configure) +README guess what +algorithm.txt description of the (de)compression algorithm +configure configure script for Unix +zconf.in.h template for zconf.h (used by configure) + +msdos/ makefiles for MSDOS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +win32/ makefiles for Windows + + zlib public header files (must be kept): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzio.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs: +example.c +minigzip.c + + unsupported contribution by third parties +See contrib/README.contrib diff --git a/zlib/Makefile b/zlib/Makefile new file mode 100644 index 0000000..13a9fd6 --- /dev/null +++ b/zlib/Makefile @@ -0,0 +1,154 @@ +# Makefile for zlib +# Copyright (C) 1995-2003 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +LIBS=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.1 +SHAREDLIBM=libz.so.1 + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example$(EXE) minigzip$(EXE) + +check: test +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIBV): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + +example$(EXE): example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip$(EXE): minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi + -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi + -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + (ldconfig || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(man3dir) + chmod 644 $(man3dir)/zlib.3 +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(man3dir); rm -f zlib.3 + +mostlyclean: clean +clean: + rm -f *.o *~ example$(EXE) minigzip$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + +maintainer-clean: distclean +distclean: clean + cp -p Makefile.in Makefile + cp -p zconf.in.h zconf.h + rm -f .DS_Store + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/Makefile.in b/zlib/Makefile.in new file mode 100644 index 0000000..13a9fd6 --- /dev/null +++ b/zlib/Makefile.in @@ -0,0 +1,154 @@ +# Makefile for zlib +# Copyright (C) 1995-2003 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +LIBS=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.1 +SHAREDLIBM=libz.so.1 + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example$(EXE) minigzip$(EXE) + +check: test +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIBV): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + +example$(EXE): example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip$(EXE): minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi + -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi + -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + (ldconfig || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(man3dir) + chmod 644 $(man3dir)/zlib.3 +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(man3dir); rm -f zlib.3 + +mostlyclean: clean +clean: + rm -f *.o *~ example$(EXE) minigzip$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + +maintainer-clean: distclean +distclean: clean + cp -p Makefile.in Makefile + cp -p zconf.in.h zconf.h + rm -f .DS_Store + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/README b/zlib/README new file mode 100644 index 0000000..718aab2 --- /dev/null +++ b/zlib/README @@ -0,0 +1,126 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.1 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install" For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or +descrip.mms. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.1 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/zlib/adler32.c b/zlib/adler32.c new file mode 100644 index 0000000..dd6d60f --- /dev/null +++ b/zlib/adler32.c @@ -0,0 +1,74 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/zlib/algorithm.txt b/zlib/algorithm.txt new file mode 100644 index 0000000..9f6b068 --- /dev/null +++ b/zlib/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend two much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://www.ietf.org/rfc/rfc1951.txt diff --git a/zlib/amiga/Makefile.pup b/zlib/amiga/Makefile.pup new file mode 100644 index 0000000..8deb7c8 --- /dev/null +++ b/zlib/amiga/Makefile.pup @@ -0,0 +1,66 @@ +# Amiga powerUP (TM) Makefile +# makefile for libpng and SAS C V6.58/7.00 PPC compiler +# Copyright (C) 1998 by Andreas R. Kleinert + +LIBNAME = libzip.a + +CC = scppc +CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \ + OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER +AR = ppc-amigaos-ar cr +RANLIB = ppc-amigaos-ranlib +LD = ppc-amigaos-ld -r +LDFLAGS = -o +LDLIBS = LIB:scppc.a LIB:end.o +RM = delete quiet + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +$(LIBNAME): $(OBJS) + $(AR) $@ $(OBJS) + -$(RANLIB) $@ + +example: example.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +minigzip: minigzip.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +mostlyclean: clean +clean: + $(RM) *.o example minigzip $(LIBNAME) foo.gz + +zip: + zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \ + descrip.mms *.[ch] + +tgz: + cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \ + zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/amiga/Makefile.sas b/zlib/amiga/Makefile.sas new file mode 100644 index 0000000..1cbd7ce --- /dev/null +++ b/zlib/amiga/Makefile.sas @@ -0,0 +1,65 @@ +# SMakefile for zlib +# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly +# Osma Ahvenlampi +# Amiga, SAS/C 6.56 & Smake + +CC=sc +CFLAGS=OPT +#CFLAGS=OPT CPU=68030 +#CFLAGS=DEBUG=LINE +LDFLAGS=LIB z.lib + +SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \ + NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \ + DEF=POSTINC + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: SCOPTIONS example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +install: z.lib + copy clone zlib.h zconf.h INCLUDE: + copy clone z.lib LIB: + +z.lib: $(OBJS) + oml z.lib r $(OBJS) + +example: example.o z.lib + $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS) + +minigzip: minigzip.o z.lib + $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS) + +mostlyclean: clean +clean: + -delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS + +SCOPTIONS: Makefile.sas + copy to $@ 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/zlib/configure b/zlib/configure new file mode 100644 index 0000000..872cd08 --- /dev/null +++ b/zlib/configure @@ -0,0 +1,445 @@ +#!/bin/sh +# configure script for zlib. This script is needed only if +# you wish to build a shared library and your system supports them, +# of if you need special compiler, flags or install directory. +# Otherwise, you can just use directly "make test; make install" +# +# To create a shared library, use "configure --shared"; by default a static +# library is created. If the primitive shared library support provided here +# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) +# LDSHARED is the command to be used to create a shared library + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +LIBS=libz.a +LDFLAGS="-L. ${LIBS}" +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h` +VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h` +VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h` +AR=${AR-"ar rc"} +RANLIB=${RANLIB-"ranlib"} +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=0 +gcc=0 +old_cc="$CC" +old_cflags="$CFLAGS" + +while test $# -ge 1 +do +case "$1" in + -h* | --h*) + echo 'usage:' + echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]' + echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]' + exit 0;; + -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;; + -p* | --p*) prefix="$2"; shift; shift;; + -e* | --e*) exec_prefix="$2"; shift; shift;; + -l* | --l*) libdir="$2"; shift; shift;; + -i* | --i*) includedir="$2"; shift; shift;; + -s* | --s*) shared=1; shift;; + *) echo "unknown option: $1"; echo "$0 --help for help"; exit 1;; + esac +done + +test=ztest$$ +cat > $test.c </dev/null; then + CC="$cc" + SFLAGS=${CFLAGS-"-fPIC -O3"} + CFLAGS="$cflags" + case `(uname -s || echo unknown) 2>/dev/null` in + Linux | linux | GNU | GNU/*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"};; + CYGWIN* | Cygwin* | cygwin* ) + EXE='.exe';; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"};; + HP-UX*) LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + shared_ext='.sl' + SHAREDLIB='libz.sl';; + Darwin*) shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name /usr/lib/$SHAREDLIBV -compatibility_version $VER2 -current_version $VER"} + libdir='/usr/lib' + includedir='/usr/include';; + *) LDSHARED=${LDSHARED-"$cc -shared"};; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + case `(uname -sr || echo unknown) 2>/dev/null` in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + shared_ext='.sl' + SHAREDLIB='libz.sl';; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared"};; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared"};; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR="cc -A";; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};; + SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."} + CFLAGS=${CFLAGS-"-fast -xcg89"} + LDSHARED=${LDSHARED-"cc -G"};; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"};; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + OpenUNIX\ 5) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc -G"};; + # send working options for other systems to support@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"};; + esac +fi + +SHAREDLIB=${SHAREDLIB-"libz$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"} + +if test $shared -eq 1; then + echo Checking for shared library support... + # we must test in two steps (cc then ld), required at least on SunOS 4.x + if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" && + test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then + CFLAGS="$SFLAGS" + LIBS="$SHAREDLIBV" + echo Building shared library $SHAREDLIBV with $CC. + elif test -z "$old_cc" -a -z "$old_cflags"; then + echo No shared library support. + shared=0; + else + echo 'No shared library support; try without defining CC and CFLAGS' + shared=0; + fi +fi +if test $shared -eq 0; then + LDSHARED="$CC" + echo Building static library $LIBS version $VER with $CC. +else + LDFLAGS="-L. ${SHAREDLIBV}" +fi + +cat > $test.c < +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + sed < zconf.in.h "/HAVE_UNISTD_H/s%0%1%" > zconf.h + echo "Checking for unistd.h... Yes." +else + cp -p zconf.in.h zconf.h + echo "Checking for unistd.h... No." +fi + +cat > $test.c < +#include +#include "zconf.h" + +int main() +{ +#ifndef STDC + choke me +#endif + + return 0; +} +EOF + +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()" + + cat > $test.c < +#include + +int mytest(char *fmt, ...) +{ + char buf[20]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for vsnprintf() in stdio.h... Yes." + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return n; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of vsnprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_vsnprintf_void" + echo "Checking for return value of vsnprintf()... No." + echo " WARNING: apparently vsnprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + CFLAGS="$CFLAGS -DNO_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... No." + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + n = vsprintf(buf, fmt, ap); + va_end(ap); + return n; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of vsprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_vsprintf_void" + echo "Checking for return value of vsprintf()... No." + echo " WARNING: apparently vsprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +else + echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()" + + cat >$test.c < + +int mytest() +{ + char buf[20]; + + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for snprintf() in stdio.h... Yes." + + cat >$test.c < + +int mytest() +{ + char buf[20]; + + return snprintf(buf, sizeof(buf), "%s", "foo"); +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of snprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_snprintf_void" + echo "Checking for return value of snprintf()... No." + echo " WARNING: apparently snprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + CFLAGS="$CFLAGS -DNO_snprintf" + echo "Checking for snprintf() in stdio.h... No." + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c < + +int mytest() +{ + char buf[20]; + + return sprintf(buf, "%s", "foo"); +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of sprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_sprintf_void" + echo "Checking for return value of sprintf()... No." + echo " WARNING: apparently sprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +fi + +cat >$test.c < +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for errno.h... Yes." +else + echo "Checking for errno.h... No." + CFLAGS="$CFLAGS -DNO_ERRNO_H" +fi + +cat > $test.c < +#include +#include +caddr_t hello() { + return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0); +} +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DUSE_MMAP" + echo Checking for mmap support... Yes. +else + echo Checking for mmap support... No. +fi + +CPP=${CPP-"$CC -E"} +case $CFLAGS in + *ASMV*) + if test "`nm $test.o | grep _hello`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. + else + echo Checking for underline in external names... Yes. + fi;; +esac + +rm -f $test.[co] $test $test$shared_ext + +# udpate Makefile +sed < Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^CPP *=/s#=.*#=$CPP# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^LIBS *=/s#=.*#=$LIBS# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" > Makefile diff --git a/zlib/contrib/README.contrib b/zlib/contrib/README.contrib new file mode 100644 index 0000000..9b628cf --- /dev/null +++ b/zlib/contrib/README.contrib @@ -0,0 +1,70 @@ +All files under this contrib directory are UNSUPPORTED. There were +provided by users of zlib and were not tested by the authors of zlib. +Use at your own risk. Please contact the authors of the contributions +for help about these, not the zlib authors. Thanks. + + +ada/ by Dmitriy Anisimkov + Support for Ada + See http://zlib-ada.sourceforge.net/ + +asm586/ +asm686/ by Brian Raiter + asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax + See http://www.muppetlabs.com/~breadbox/software/assembly.html + +blast/ by Mark Adler + Decompressor for output of PKWare Data Compression Library (DCL) + +delphi/ by Cosmin Truta + Support for Delphi and C++ Builder + +gzappend/ by Mark Adler + append to a gzip file -- illustrates the use of Z_BLOCK + +infback9/ by Mark Adler + Unsupported diffs to infback to decode the deflate64 format + +inflate86/ by Chris Anderson + Tuned x86 gcc asm code to replace inflate_fast() + +iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + +iostream2/ by Tyge Løvset + Another C++ I/O streams interface + +iostream3/ by Ludwig Schwardt + and Kevin Ruland + Yet another C++ I/O streams interface + +masm686/ by Dan Higdon + and Chuck Walbourn + asm code for Pentium Pro/PII, using the MASM syntax + +masmx86/ by Gilles Vollant + x86 asm code to replace longest_match() and inflate_fast(), + for Visual C++ and MASM + +minizip/ by Gilles Vollant + Mini zip and unzip based on zlib + See http://www.winimage.com/zLibDll/unzip.html + +pascal/ by Bob Dellaca et al. + Support for Pascal + +puff/ by Mark Adler + Small, low memory usage inflate. Also serves to provide an + unambiguous description of the deflate format. + +testzlib/ by Gilles Vollant + Example of the use of zlib + +untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + +visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB + +vstudio/ by Gilles Vollant + Building zlib with Visual Studio .NET diff --git a/zlib/contrib/ada/mtest.adb b/zlib/contrib/ada/mtest.adb new file mode 100644 index 0000000..6025446 --- /dev/null +++ b/zlib/contrib/ada/mtest.adb @@ -0,0 +1,153 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- Continuous test for ZLib multithreading. If the test is fail +-- Wou should provide thread safe allocation routines for the Z_Stream. +-- +-- $Id: mtest.adb,v 1.2 2003/08/12 12:11:05 vagul Exp $ + +with ZLib; +with Ada.Streams; +with Ada.Numerics.Discrete_Random; +with Ada.Text_IO; +with Ada.Exceptions; +with Ada.Task_Identification; + +procedure MTest is + use Ada.Streams; + use ZLib; + + Stop : Boolean := False; + + pragma Atomic (Stop); + + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + task type Test_Task; + + task body Test_Task is + Buffer : Stream_Element_Array (1 .. 100_000); + Gen : Random_Elements.Generator; + + Buffer_First : Stream_Element_Offset; + Compare_First : Stream_Element_Offset; + + Deflate : Filter_Type; + Inflate : Filter_Type; + + procedure Further (Item : in Stream_Element_Array); + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + ------------- + -- Further -- + ------------- + + procedure Further (Item : in Stream_Element_Array) is + + procedure Compare (Item : in Stream_Element_Array); + + ------------- + -- Compare -- + ------------- + + procedure Compare (Item : in Stream_Element_Array) is + Next_First : Stream_Element_Offset := Compare_First + Item'Length; + begin + if Buffer (Compare_First .. Next_First - 1) /= Item then + raise Program_Error; + end if; + + Compare_First := Next_First; + end Compare; + + procedure Compare_Write is new ZLib.Write (Write => Compare); + begin + Compare_Write (Inflate, Item, No_Flush); + end Further; + + ----------------- + -- Read_Buffer -- + ----------------- + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset) + is + Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First; + Next_First : Stream_Element_Offset; + begin + if Item'Length <= Buff_Diff then + Last := Item'Last; + + Next_First := Buffer_First + Item'Length; + + Item := Buffer (Buffer_First .. Next_First - 1); + + Buffer_First := Next_First; + else + Last := Item'First + Buff_Diff; + Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last); + Buffer_First := Buffer'Last + 1; + end if; + end Read_Buffer; + + procedure Translate is new Generic_Translate + (Data_In => Read_Buffer, + Data_Out => Further); + + begin + Random_Elements.Reset (Gen); + + Buffer := (others => 20); + + Main : loop + for J in Buffer'Range loop + Buffer (J) := Random_Elements.Random (Gen); + + Deflate_Init (Deflate); + Inflate_Init (Inflate); + + Buffer_First := Buffer'First; + Compare_First := Buffer'First; + + Translate (Deflate); + + if Compare_First /= Buffer'Last + 1 then + raise Program_Error; + end if; + + Ada.Text_IO.Put_Line + (Ada.Task_Identification.Image + (Ada.Task_Identification.Current_Task) + & Stream_Element_Offset'Image (J) + & ZLib.Count'Image (Total_Out (Deflate))); + + Close (Deflate); + Close (Inflate); + + exit Main when Stop; + end loop; + end loop Main; + exception + when E : others => + Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E)); + Stop := True; + end Test_Task; + + Test : array (1 .. 4) of Test_Task; + + pragma Unreferenced (Test); + +begin + null; +end MTest; diff --git a/zlib/contrib/ada/read.adb b/zlib/contrib/ada/read.adb new file mode 100644 index 0000000..1e81d6f --- /dev/null +++ b/zlib/contrib/ada/read.adb @@ -0,0 +1,151 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: read.adb,v 1.7 2003/08/12 12:12:35 vagul Exp $ + +-- Test/demo program for the generic read interface. + +with Ada.Numerics.Discrete_Random; +with Ada.Streams; +with Ada.Text_IO; + +with ZLib; + +procedure Read is + + use Ada.Streams; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Stream_Element_Offset := 100_000; + + Continuous : constant Boolean := False; + -- If this constant is True, the test would be repeated again and again, + -- with increment File_Size for every iteration. + + Header : constant ZLib.Header_Type := ZLib.Default; + -- Do not use Header other than Default in ZLib versions 1.1.4 and older. + + Init_Random : constant := 8; + -- We are using the same random sequence, in case of we catch bug, + -- so we would be able to reproduce it. + + -- End -- + + Pack_Size : Stream_Element_Offset; + Offset : Stream_Element_Offset; + + Filter : ZLib.Filter_Type; + + subtype Visible_Symbols + is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is new + Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Period : constant Stream_Element_Offset := 200; + -- Period constant variable for random generator not to be very random. + -- Bigger period, harder random. + + Read_Buffer : Stream_Element_Array (1 .. 2048); + Read_First : Stream_Element_Offset; + Read_Last : Stream_Element_Offset; + + procedure Reset; + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Read + -- reading data from the File_In. + + procedure Read is new ZLib.Read (Read, Read_Buffer, Read_First, Read_Last); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Last := Stream_Element_Offset'Min + (Item'Last, + Item'First + File_Size - Offset); + + for J in Item'First .. Last loop + if J < Item'First + Period then + Item (J) := Random_Elements.Random (Gen); + else + Item (J) := Item (J - Period); + end if; + + Offset := Offset + 1; + end loop; + end Read; + + ----------- + -- Reset -- + ----------- + + procedure Reset is + begin + Random_Elements.Reset (Gen, Init_Random); + Pack_Size := 0; + Offset := 1; + Read_First := Read_Buffer'Last + 1; + end Reset; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter, + Level, + Header => Header); + + Reset; + + Ada.Text_IO.Put + (Stream_Element_Offset'Image (File_Size) & " ->"); + + loop + declare + Buffer : Stream_Element_Array (1 .. 1024); + Last : Stream_Element_Offset; + begin + Read (Filter, Buffer, Last); + + Pack_Size := Pack_Size + Last - Buffer'First + 1; + + exit when Last < Buffer'Last; + end; + end loop; + + Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size)); + + ZLib.Close (Filter); + end loop; + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Read; diff --git a/zlib/contrib/ada/readme.txt b/zlib/contrib/ada/readme.txt new file mode 100644 index 0000000..1953253 --- /dev/null +++ b/zlib/contrib/ada/readme.txt @@ -0,0 +1,52 @@ + + ZLib for Ada thick binding (ZLib.Ada) + Release 1.2 + +ZLib.Ada is a thick binding interface to the popular ZLib data +compression library, available at http://www.gzip.org/zlib/. +It provides Ada-style access to the ZLib C library. + + + Here are the main changes since ZLib.Ada 1.1: + +- The default header type has a name "Default" now. Auto is used only for + automatic GZip/ZLib header detection. + +- Added test for multitasking mtest.adb. + +- Added GNAT project file zlib.gpr. + + + How to build ZLib.Ada under GNAT + +You should have the ZLib library already build on your computer, before +building ZLib.Ada. Make the directory of ZLib.Ada sources current and +issue the command: + + gnatmake test -largs -L -lz + +Or use the GNAT project file build for GNAT 3.15 or later: + + gnatmake -Pzlib.gpr -L + + + How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2 + +1. Make a project with all *.ads and *.adb files from the distribution. +2. Build the libz.a library from the ZLib C sources. +3. Rename libz.a to z.lib. +4. Add the library z.lib to the project. +5. Add the libc.lib library from the ObjectAda distribution to the project. +6. Build the executable using test.adb as a main procedure. + + + How to use ZLib.Ada + +The source files test.adb and read.adb are small demo programs that show +the main functionality of ZLib.Ada. + +The routines from the package specifications are commented. + + +Homepage: http://zlib-ada.sourceforge.net/ +Author: Dmitriy Anisimkov diff --git a/zlib/contrib/ada/test.adb b/zlib/contrib/ada/test.adb new file mode 100644 index 0000000..193f1f0 --- /dev/null +++ b/zlib/contrib/ada/test.adb @@ -0,0 +1,463 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: test.adb,v 1.17 2003/08/12 12:13:30 vagul Exp $ + +-- The program has a few aims. +-- 1. Test ZLib.Ada95 thick binding functionality. +-- 2. Show the example of use main functionality of the ZLib.Ada95 binding. +-- 3. Build this program automatically compile all ZLib.Ada95 packages under +-- GNAT Ada95 compiler. + +with ZLib.Streams; +with Ada.Streams.Stream_IO; +with Ada.Numerics.Discrete_Random; + +with Ada.Text_IO; + +with Ada.Calendar; + +procedure Test is + + use Ada.Streams; + use Stream_IO; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Count := 100_000; + Continuous : constant Boolean := False; + + Header : constant ZLib.Header_Type := ZLib.Default; + -- ZLib.None; + -- ZLib.Auto; + -- ZLib.GZip; + -- Do not use Header other then Default in ZLib versions 1.1.4 + -- and older. + + Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy; + Init_Random : constant := 10; + + -- End -- + + In_File_Name : constant String := "testzlib.in"; + -- Name of the input file + + Z_File_Name : constant String := "testzlib.zlb"; + -- Name of the compressed file. + + Out_File_Name : constant String := "testzlib.out"; + -- Name of the decompressed file. + + File_In : File_Type; + File_Out : File_Type; + File_Back : File_Type; + File_Z : ZLib.Streams.Stream_Type; + + Filter : ZLib.Filter_Type; + + Time_Stamp : Ada.Calendar.Time; + + procedure Generate_File; + -- Generate file of spetsified size with some random data. + -- The random data is repeatable, for the good compression. + + procedure Compare_Streams + (Left, Right : in out Root_Stream_Type'Class); + -- The procedure compearing data in 2 streams. + -- It is for compare data before and after compression/decompression. + + procedure Compare_Files (Left, Right : String); + -- Compare files. Based on the Compare_Streams. + + procedure Copy_Streams + (Source, Target : in out Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024); + -- Copying data from one stream to another. It is for test stream + -- interface of the library. + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- reading data from the File_In. + + procedure Data_Out (Item : in Stream_Element_Array); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- writing data to the File_Out. + + procedure Stamp; + -- Store the timestamp to the local variable. + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count); + -- Print the time statistic with the message. + + procedure Translate is new ZLib.Generic_Translate + (Data_In => Data_In, + Data_Out => Data_Out); + -- This procedure is moving data from File_In to File_Out + -- with compression or decompression, depend on initialization of + -- Filter parameter. + + ------------------- + -- Compare_Files -- + ------------------- + + procedure Compare_Files (Left, Right : String) is + Left_File, Right_File : File_Type; + begin + Open (Left_File, In_File, Left); + Open (Right_File, In_File, Right); + Compare_Streams (Stream (Left_File).all, Stream (Right_File).all); + Close (Left_File); + Close (Right_File); + end Compare_Files; + + --------------------- + -- Compare_Streams -- + --------------------- + + procedure Compare_Streams + (Left, Right : in out Ada.Streams.Root_Stream_Type'Class) + is + Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#); + Left_Last, Right_Last : Stream_Element_Offset; + begin + loop + Read (Left, Left_Buffer, Left_Last); + Read (Right, Right_Buffer, Right_Last); + + if Left_Last /= Right_Last then + Ada.Text_IO.Put_Line ("Compare error :" + & Stream_Element_Offset'Image (Left_Last) + & " /= " + & Stream_Element_Offset'Image (Right_Last)); + + raise Constraint_Error; + + elsif Left_Buffer (0 .. Left_Last) + /= Right_Buffer (0 .. Right_Last) + then + Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal."); + raise Constraint_Error; + + end if; + + exit when Left_Last < Left_Buffer'Last; + end loop; + end Compare_Streams; + + ------------------ + -- Copy_Streams -- + ------------------ + + procedure Copy_Streams + (Source, Target : in out Ada.Streams.Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Read (Source, Buffer, Last); + Write (Target, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Copy_Streams; + + ------------- + -- Data_In -- + ------------- + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Read (File_In, Item, Last); + end Data_In; + + -------------- + -- Data_Out -- + -------------- + + procedure Data_Out (Item : in Stream_Element_Array) is + begin + Write (File_Out, Item); + end Data_Out; + + ------------------- + -- Generate_File -- + ------------------- + + procedure Generate_File is + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10; + + Buffer_Count : constant Count := File_Size / Buffer'Length; + -- Number of same buffers in the packet. + + Density : constant Count := 30; -- from 0 to Buffer'Length - 2; + + procedure Fill_Buffer (J, D : in Count); + -- Change the part of the buffer. + + ----------------- + -- Fill_Buffer -- + ----------------- + + procedure Fill_Buffer (J, D : in Count) is + begin + for K in 0 .. D loop + Buffer + (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1)) + := Random_Elements.Random (Gen); + + end loop; + end Fill_Buffer; + + begin + Random_Elements.Reset (Gen, Init_Random); + + Create (File_In, Out_File, In_File_Name); + + Fill_Buffer (1, Buffer'Length - 2); + + for J in 1 .. Buffer_Count loop + Write (File_In, Buffer); + + Fill_Buffer (J, Density); + end loop; + + -- fill remain size. + + Write + (File_In, + Buffer + (1 .. Stream_Element_Offset + (File_Size - Buffer'Length * Buffer_Count))); + + Flush (File_In); + Close (File_In); + end Generate_File; + + --------------------- + -- Print_Statistic -- + --------------------- + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is + use Ada.Calendar; + use Ada.Text_IO; + + package Count_IO is new Integer_IO (ZLib.Count); + + Curr_Dur : Duration := Clock - Time_Stamp; + begin + Put (Msg); + + Set_Col (20); + Ada.Text_IO.Put ("size ="); + + Count_IO.Put + (Data_Size, + Width => Stream_IO.Count'Image (File_Size)'Length); + + Put_Line (" duration =" & Duration'Image (Curr_Dur)); + end Print_Statistic; + + ----------- + -- Stamp -- + ----------- + + procedure Stamp is + begin + Time_Stamp := Ada.Calendar.Clock; + end Stamp; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + Generate_File; + + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put_Line ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Test generic interface. + Open (File_In, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + Stamp; + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter => Filter, + Level => Level, + Strategy => Strategy, + Header => Header); + + Translate (Filter); + Print_Statistic ("Generic compress", ZLib.Total_Out (Filter)); + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Open (File_In, In_File, Z_File_Name); + Create (File_Out, Out_File, Out_File_Name); + + Stamp; + + -- Inflate using generic instantiation. + + ZLib.Inflate_Init (Filter, Header => Header); + + Translate (Filter); + Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter)); + + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Compare_Files (In_File_Name, Out_File_Name); + + -- Test stream interface. + + -- Compress to the back stream. + + Open (File_In, In_File, In_File_Name); + Create (File_Back, Out_File, Z_File_Name); + + Stamp; + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Level => Level, + Strategy => Strategy, + Header => Header); + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + -- Flushing internal buffers to the back stream. + + ZLib.Streams.Flush (File_Z, ZLib.Finish); + + Print_Statistic ("Write compress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_In); + Close (File_Back); + + -- Compare reading from original file and from + -- decompression stream. + + Open (File_In, In_File, In_File_Name); + Open (File_Back, In_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Header => Header); + + Stamp; + Compare_Streams (Stream (File_In).all, File_Z); + + Print_Statistic ("Read decompress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + -- Compress by reading from compression stream. + + Open (File_Back, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Level => Level, + Strategy => Strategy, + Header => Header); + + Stamp; + Copy_Streams + (Source => File_Z, + Target => Stream (File_Out).all); + + Print_Statistic ("Read compress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_Out); + Close (File_Back); + + -- Decompress to decompression stream. + + Open (File_In, In_File, Z_File_Name); + Create (File_Back, Out_File, Out_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Header => Header); + + Stamp; + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + Print_Statistic ("Write decompress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + Compare_Files (In_File_Name, Out_File_Name); + end loop; + + Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok."); + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Test; diff --git a/zlib/contrib/ada/zlib-streams.adb b/zlib/contrib/ada/zlib-streams.adb new file mode 100644 index 0000000..7980f42 --- /dev/null +++ b/zlib/contrib/ada/zlib-streams.adb @@ -0,0 +1,215 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.adb,v 1.9 2003/08/12 13:15:31 vagul Exp $ + +with Ada.Unchecked_Deallocation; + +package body ZLib.Streams is + + ----------- + -- Close -- + ----------- + + procedure Close (Stream : in out Stream_Type) is + procedure Free is new Ada.Unchecked_Deallocation + (Stream_Element_Array, Buffer_Access); + begin + if Stream.Mode = Out_Stream or Stream.Mode = Duplex then + -- We should flush the data written by the writer. + + Flush (Stream, Finish); + + Close (Stream.Writer); + end if; + + if Stream.Mode = In_Stream or Stream.Mode = Duplex then + Close (Stream.Reader); + Free (Stream.Buffer); + end if; + end Close; + + ------------ + -- Create -- + ------------ + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size) + is + + subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size); + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean); + + ----------------- + -- Init_Filter -- + ----------------- + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean) is + begin + if Compress then + Deflate_Init + (Filter, Level, Strategy, Header => Header); + else + Inflate_Init (Filter, Header => Header); + end if; + end Init_Filter; + + begin + Stream.Back := Back; + Stream.Mode := Mode; + + if Mode = Out_Stream or Mode = Duplex then + Init_Filter (Stream.Writer, Back_Compressed); + Stream.Buffer_Size := Write_Buffer_Size; + else + Stream.Buffer_Size := 0; + end if; + + if Mode = In_Stream or Mode = Duplex then + Init_Filter (Stream.Reader, not Back_Compressed); + + Stream.Buffer := new Buffer_Subtype; + Stream.Rest_First := Stream.Buffer'Last + 1; + end if; + end Create; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush) + is + Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Flush (Stream.Writer, Buffer, Last, Mode); + + Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Flush; + + ---------- + -- Read -- + ---------- + + procedure Read + (Stream : in out Stream_Type; + Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) + is + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Ada.Streams.Read (Stream.Back.all, Item, Last); + end Read; + + procedure Read is new ZLib.Read + (Read => Read, + Buffer => Stream.Buffer.all, + Rest_First => Stream.Rest_First, + Rest_Last => Stream.Rest_Last); + + begin + Read (Stream.Reader, Item, Last); + end Read; + + ------------------- + -- Read_Total_In -- + ------------------- + + function Read_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Reader); + end Read_Total_In; + + -------------------- + -- Read_Total_Out -- + -------------------- + + function Read_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Reader); + end Read_Total_Out; + + ----------- + -- Write -- + ----------- + + procedure Write + (Stream : in out Stream_Type; + Item : in Stream_Element_Array) + is + + procedure Write (Item : in Stream_Element_Array); + + ----------- + -- Write -- + ----------- + + procedure Write (Item : in Stream_Element_Array) is + begin + Ada.Streams.Write (Stream.Back.all, Item); + end Write; + + procedure Write is new ZLib.Write + (Write => Write, + Buffer_Size => Stream.Buffer_Size); + + begin + Write (Stream.Writer, Item, No_Flush); + end Write; + + -------------------- + -- Write_Total_In -- + -------------------- + + function Write_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Writer); + end Write_Total_In; + + --------------------- + -- Write_Total_Out -- + --------------------- + + function Write_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Writer); + end Write_Total_Out; + +end ZLib.Streams; diff --git a/zlib/contrib/ada/zlib-streams.ads b/zlib/contrib/ada/zlib-streams.ads new file mode 100644 index 0000000..c9eaff7 --- /dev/null +++ b/zlib/contrib/ada/zlib-streams.ads @@ -0,0 +1,112 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.ads,v 1.11 2003/08/12 13:15:31 vagul Exp $ + +package ZLib.Streams is + + type Stream_Mode is (In_Stream, Out_Stream, Duplex); + + type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class; + + type Stream_Type is + new Ada.Streams.Root_Stream_Type with private; + + procedure Read + (Stream : in out Stream_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + procedure Write + (Stream : in out Stream_Type; + Item : in Ada.Streams.Stream_Element_Array); + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush); + -- Flush the written data to the back stream, + -- all data placed to the compressor is flushing to the Back stream. + -- Should not be used untill necessary, becouse it is decreasing + -- compression. + + function Read_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_In); + -- Return total number of bytes read from back stream so far. + + function Read_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_Out); + -- Return total number of bytes read so far. + + function Write_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_In); + -- Return total number of bytes written so far. + + function Write_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_Out); + -- Return total number of bytes written to the back stream. + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size); + -- Create the Comression/Decompression stream. + -- If mode is In_Stream then Write operation is disabled. + -- If mode is Out_Stream then Read operation is disabled. + + -- If Back_Compressed is true then + -- Data written to the Stream is compressing to the Back stream + -- and data read from the Stream is decompressed data from the Back stream. + + -- If Back_Compressed is false then + -- Data written to the Stream is decompressing to the Back stream + -- and data read from the Stream is compressed data from the Back stream. + + -- !!! When the Need_Header is False ZLib-Ada is using undocumented + -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers. + + procedure Close (Stream : in out Stream_Type); + +private + + use Ada.Streams; + + type Buffer_Access is access all Stream_Element_Array; + + type Stream_Type + is new Root_Stream_Type with + record + Mode : Stream_Mode; + + Buffer : Buffer_Access; + Rest_First : Stream_Element_Offset; + Rest_Last : Stream_Element_Offset; + -- Buffer for Read operation. + -- We need to have this buffer in the record + -- becouse not all read data from back stream + -- could be processed during the read operation. + + Buffer_Size : Stream_Element_Offset; + -- Buffer size for write operation. + -- We do not need to have this buffer + -- in the record becouse all data could be + -- processed in the write operation. + + Back : Stream_Access; + Reader : Filter_Type; + Writer : Filter_Type; + end record; + +end ZLib.Streams; diff --git a/zlib/contrib/ada/zlib-thin.adb b/zlib/contrib/ada/zlib-thin.adb new file mode 100644 index 0000000..7e39283 --- /dev/null +++ b/zlib/contrib/ada/zlib-thin.adb @@ -0,0 +1,185 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.adb,v 1.6 2003/01/21 15:26:37 vagul Exp $ + +package body ZLib.Thin is + + ZLIB_VERSION : constant Chars_Ptr := + Interfaces.C.Strings.New_String ("1.1.4"); + + Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit; + + -------------- + -- Avail_In -- + -------------- + + function Avail_In (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_In; + end Avail_In; + + --------------- + -- Avail_Out -- + --------------- + + function Avail_Out (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_Out; + end Avail_Out; + + ------------------ + -- Deflate_Init -- + ------------------ + + function Deflate_Init + (strm : in Z_Streamp; + level : in Int := Z_DEFAULT_COMPRESSION) + return Int is + begin + return deflateInit (strm, level, ZLIB_VERSION, Z_Stream_Size); + end Deflate_Init; + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int is + begin + return deflateInit2 + (strm, + level, + method, + windowBits, + memLevel, + strategy, + ZLIB_VERSION, + Z_Stream_Size); + end Deflate_Init; + + ------------------ + -- Inflate_Init -- + ------------------ + + function Inflate_Init (strm : Z_Streamp) return Int is + begin + return inflateInit (strm, ZLIB_VERSION, Z_Stream_Size); + end Inflate_Init; + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is + begin + return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size); + end Inflate_Init; + + function Last_Error_Message (Strm : in Z_Stream) return String is + use Interfaces.C.Strings; + begin + if Strm.msg = Null_Ptr then + return ""; + else + return Value (Strm.msg); + end if; + end Last_Error_Message; + + ------------- + -- Need_In -- + ------------- + + function Need_In (strm : Z_Stream) return Boolean is + begin + return strm.Avail_In = 0; + end Need_In; + + -------------- + -- Need_Out -- + -------------- + + function Need_Out (strm : Z_Stream) return Boolean is + begin + return strm.Avail_Out = 0; + end Need_Out; + + ------------ + -- Set_In -- + ------------ + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Byte_Access; + Size : in UInt) is + begin + Strm.Next_In := Buffer; + Strm.Avail_In := Size; + end Set_In; + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Set_In (Strm, Bytes.To_Pointer (Buffer), Size); + end Set_In; + + ------------------ + -- Set_Mem_Func -- + ------------------ + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func) is + begin + Strm.opaque := Opaque; + Strm.zalloc := Alloc; + Strm.zfree := Free; + end Set_Mem_Func; + + ------------- + -- Set_Out -- + ------------- + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Byte_Access; + Size : in UInt) is + begin + Strm.Next_Out := Buffer; + Strm.Avail_Out := Size; + end Set_Out; + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Set_Out (Strm, Bytes.To_Pointer (Buffer), Size); + end Set_Out; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_In; + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_Out; + end Total_Out; + +end ZLib.Thin; diff --git a/zlib/contrib/ada/zlib-thin.ads b/zlib/contrib/ada/zlib-thin.ads new file mode 100644 index 0000000..aec00f9 --- /dev/null +++ b/zlib/contrib/ada/zlib-thin.ads @@ -0,0 +1,485 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.ads,v 1.8 2003/08/12 13:16:51 vagul Exp $ + +with Interfaces.C.Strings; +with System.Address_To_Access_Conversions; + +private package ZLib.Thin is + + -- From zconf.h + + MAX_MEM_LEVEL : constant := 9; -- zconf.h:105 + -- zconf.h:105 + MAX_WBITS : constant := 15; -- zconf.h:115 + -- 32K LZ77 window + -- zconf.h:115 + SEEK_SET : constant := 8#0000#; -- zconf.h:244 + -- Seek from beginning of file. + -- zconf.h:244 + SEEK_CUR : constant := 1; -- zconf.h:245 + -- Seek from current position. + -- zconf.h:245 + SEEK_END : constant := 2; -- zconf.h:246 + -- Set file pointer to EOF plus "offset" + -- zconf.h:246 + + type Byte is new Interfaces.C.unsigned_char; -- 8 bits + -- zconf.h:214 + type UInt is new Interfaces.C.unsigned; -- 16 bits or more + -- zconf.h:216 + type Int is new Interfaces.C.int; + + type ULong is new Interfaces.C.unsigned; -- 32 bits or more + -- zconf.h:217 + subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr; + + type ULong_Access is access ULong; + type Int_Access is access Int; + subtype Voidp is System.Address; -- zconf.h:232 + + package Bytes is new System.Address_To_Access_Conversions (Byte); + + subtype Byte_Access is Bytes.Object_Pointer; + + -- end from zconf + + Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125 + -- zlib.h:125 + Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126 + -- will be removed, use + -- Z_SYNC_FLUSH instead + -- zlib.h:126 + Z_SYNC_FLUSH : constant := 2; -- zlib.h:127 + -- zlib.h:127 + Z_FULL_FLUSH : constant := 3; -- zlib.h:128 + -- zlib.h:128 + Z_FINISH : constant := 4; -- zlib.h:129 + -- zlib.h:129 + Z_OK : constant := 8#0000#; -- zlib.h:132 + -- zlib.h:132 + Z_STREAM_END : constant := 1; -- zlib.h:133 + -- zlib.h:133 + Z_NEED_DICT : constant := 2; -- zlib.h:134 + -- zlib.h:134 + Z_ERRNO : constant := -1; -- zlib.h:135 + -- zlib.h:135 + Z_STREAM_ERROR : constant := -2; -- zlib.h:136 + -- zlib.h:136 + Z_DATA_ERROR : constant := -3; -- zlib.h:137 + -- zlib.h:137 + Z_MEM_ERROR : constant := -4; -- zlib.h:138 + -- zlib.h:138 + Z_BUF_ERROR : constant := -5; -- zlib.h:139 + -- zlib.h:139 + Z_VERSION_ERROR : constant := -6; -- zlib.h:140 + -- zlib.h:140 + Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145 + -- zlib.h:145 + Z_BEST_SPEED : constant := 1; -- zlib.h:146 + -- zlib.h:146 + Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147 + -- zlib.h:147 + Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148 + -- zlib.h:148 + Z_FILTERED : constant := 1; -- zlib.h:151 + -- zlib.h:151 + Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152 + -- zlib.h:152 + Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153 + -- zlib.h:153 + Z_BINARY : constant := 8#0000#; -- zlib.h:156 + -- zlib.h:156 + Z_ASCII : constant := 1; -- zlib.h:157 + -- zlib.h:157 + Z_UNKNOWN : constant := 2; -- zlib.h:158 + -- zlib.h:158 + Z_DEFLATED : constant := 8; -- zlib.h:161 + -- zlib.h:161 + Z_NULL : constant := 8#0000#; -- zlib.h:164 + -- for initializing zalloc, zfree, opaque + -- zlib.h:164 + type gzFile is new Voidp; -- zlib.h:646 + + type Z_Stream is private; + + type Z_Streamp is access all Z_Stream; -- zlib.h:89 + + type alloc_func is access function + (Opaque : Voidp; + Items : UInt; + Size : UInt) + return Voidp; -- zlib.h:63 + + type free_func is access procedure (opaque : Voidp; address : Voidp); + + function zlibVersion return Chars_Ptr; + + function Deflate (strm : Z_Streamp; flush : Int) return Int; + + function DeflateEnd (strm : Z_Streamp) return Int; + + function Inflate (strm : Z_Streamp; flush : Int) return Int; + + function InflateEnd (strm : Z_Streamp) return Int; + + function deflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; + + function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int; + -- zlib.h:478 + + function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495 + + function deflateParams + (strm : Z_Streamp; + level : Int; + strategy : Int) + return Int; -- zlib.h:506 + + function inflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; -- zlib.h:548 + + function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565 + + function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580 + + function compress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; -- zlib.h:601 + + function compress2 + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong; + level : Int) + return Int; -- zlib.h:615 + + function uncompress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; + + function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile; + + function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile; + + function gzsetparams + (file : gzFile; + level : Int; + strategy : Int) + return Int; + + function gzread + (file : gzFile; + buf : Voidp; + len : UInt) + return Int; + + function gzwrite + (file : in gzFile; + buf : in Voidp; + len : in UInt) + return Int; + + function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int; + + function gzputs (file : in gzFile; s : in Chars_Ptr) return Int; + + function gzgets + (file : gzFile; + buf : Chars_Ptr; + len : Int) + return Chars_Ptr; + + function gzputc (file : gzFile; char : Int) return Int; + + function gzgetc (file : gzFile) return Int; + + function gzflush (file : gzFile; flush : Int) return Int; + + function gzseek + (file : gzFile; + offset : Int; + whence : Int) + return Int; + + function gzrewind (file : gzFile) return Int; + + function gztell (file : gzFile) return Int; + + function gzeof (file : gzFile) return Int; + + function gzclose (file : gzFile) return Int; + + function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr; + + function adler32 + (adler : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function crc32 + (crc : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function deflateInit + (strm : Z_Streamp; + level : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function Deflate_Init + (strm : in Z_Streamp; + level : in Int := Z_DEFAULT_COMPRESSION) + return Int; + pragma Inline (Deflate_Init); + + function deflateInit2 + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int; + pragma Inline (Deflate_Init); + + function inflateInit + (strm : Z_Streamp; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function Inflate_Init (strm : Z_Streamp) return Int; + pragma Inline (Inflate_Init); + + function inflateInit2 + (strm : in Z_Streamp; + windowBits : in Int; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + + function inflateBackInit + (strm : in Z_Streamp; + windowBits : in Int; + window : in Byte_Access; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + -- Size of window have to be 2**windowBits. + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int; + pragma Inline (Inflate_Init); + + function zError (err : Int) return Chars_Ptr; + + function inflateSyncPoint (z : Z_Streamp) return Int; + + function get_crc_table return ULong_Access; + + -- Interface to the available fields of the z_stream structure. + -- The application must update next_in and avail_in when avail_in has + -- dropped to zero. It must update next_out and avail_out when avail_out + -- has dropped to zero. The application must initialize zalloc, zfree and + -- opaque before calling the init function. + + function Need_In (strm : in Z_Stream) return Boolean; + -- return true when we do not need to setup Next_In and Avail_In fields. + pragma Inline (Need_In); + + function Need_Out (strm : in Z_Stream) return Boolean; + -- return true when we do not need to setup Next_Out and Avail_Out field. + pragma Inline (Need_Out); + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Byte_Access; + Size : in UInt); + pragma Inline (Set_In); + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_In); + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Byte_Access; + Size : in UInt); + pragma Inline (Set_Out); + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_Out); + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func); + pragma Inline (Set_Mem_Func); + + function Last_Error_Message (Strm : in Z_Stream) return String; + pragma Inline (Last_Error_Message); + + function Avail_Out (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_Out); + + function Avail_In (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_In); + + function Total_In (Strm : in Z_Stream) return ULong; + pragma Inline (Total_In); + + function Total_Out (Strm : in Z_Stream) return ULong; + pragma Inline (Total_Out); + + function inflateCopy + (dest : in Z_Streamp; + Source : in Z_Streamp) + return Int; + + function compressBound (Source_Len : in ULong) return ULong; + + function deflateBound + (Strm : in Z_Streamp; + Source_Len : in ULong) + return ULong; + + function gzungetc (C : in Int; File : in gzFile) return Int; + + function zlibCompileFlags return ULong; + + function deflatePrime + (strm : Z_Streamp; + bits : Int; + value : Int) + return Int; + +private + + type Z_Stream is record -- zlib.h:68 + Next_In : Byte_Access; -- next input byte + Avail_In : UInt := 0; -- number of bytes available at next_in + Total_In : ULong := 0; -- total nb of input bytes read so far + Next_Out : Byte_Access; -- next output byte should be put there + Avail_Out : UInt := 0; -- remaining free space at next_out + Total_Out : ULong := 0; -- total nb of bytes output so far + msg : Chars_Ptr; -- last error message, NULL if no error + state : Voidp; -- not visible by applications + zalloc : alloc_func := null; -- used to allocate the internal state + zfree : free_func := null; -- used to free the internal state + opaque : Voidp; -- private data object passed to + -- zalloc and zfree + data_type : Int; -- best guess about the data type: + -- ascii or binary + adler : ULong; -- adler32 value of the uncompressed + -- data + reserved : ULong; -- reserved for future use + end record; + + pragma Convention (C, Z_Stream); + + pragma Import (C, zlibVersion, "zlibVersion"); + pragma Import (C, Deflate, "deflate"); + pragma Import (C, DeflateEnd, "deflateEnd"); + pragma Import (C, Inflate, "inflate"); + pragma Import (C, InflateEnd, "inflateEnd"); + pragma Import (C, deflateSetDictionary, "deflateSetDictionary"); + pragma Import (C, deflateCopy, "deflateCopy"); + pragma Import (C, deflateReset, "deflateReset"); + pragma Import (C, deflateParams, "deflateParams"); + pragma Import (C, inflateSetDictionary, "inflateSetDictionary"); + pragma Import (C, inflateSync, "inflateSync"); + pragma Import (C, inflateReset, "inflateReset"); + pragma Import (C, compress, "compress"); + pragma Import (C, compress2, "compress2"); + pragma Import (C, uncompress, "uncompress"); + pragma Import (C, gzopen, "gzopen"); + pragma Import (C, gzdopen, "gzdopen"); + pragma Import (C, gzsetparams, "gzsetparams"); + pragma Import (C, gzread, "gzread"); + pragma Import (C, gzwrite, "gzwrite"); + pragma Import (C, gzprintf, "gzprintf"); + pragma Import (C, gzputs, "gzputs"); + pragma Import (C, gzgets, "gzgets"); + pragma Import (C, gzputc, "gzputc"); + pragma Import (C, gzgetc, "gzgetc"); + pragma Import (C, gzflush, "gzflush"); + pragma Import (C, gzseek, "gzseek"); + pragma Import (C, gzrewind, "gzrewind"); + pragma Import (C, gztell, "gztell"); + pragma Import (C, gzeof, "gzeof"); + pragma Import (C, gzclose, "gzclose"); + pragma Import (C, gzerror, "gzerror"); + pragma Import (C, adler32, "adler32"); + pragma Import (C, crc32, "crc32"); + pragma Import (C, deflateInit, "deflateInit_"); + pragma Import (C, inflateInit, "inflateInit_"); + pragma Import (C, deflateInit2, "deflateInit2_"); + pragma Import (C, inflateInit2, "inflateInit2_"); + pragma Import (C, zError, "zError"); + pragma Import (C, inflateSyncPoint, "inflateSyncPoint"); + pragma Import (C, get_crc_table, "get_crc_table"); + + -- added in zlib 1.2.1: + + pragma Import (C, inflateCopy, "inflateCopy"); + pragma Import (C, compressBound, "compressBound"); + pragma Import (C, deflateBound, "deflateBound"); + pragma Import (C, gzungetc, "gzungetc"); + pragma Import (C, zlibCompileFlags, "zlibCompileFlags"); + pragma Import (C, deflatePrime, "deflatePrime"); + + pragma Import (C, inflateBackInit, "inflateBackInit_"); + + -- I stopped binding the inflateBack routines, becouse realize that + -- it does not support zlib and gzip headers for now, and have no + -- symmetric deflateBack routines. + -- ZLib-Ada is symmetric regarding deflate/inflate data transformation + -- and has a similar generic callback interface for the + -- deflate/inflate transformation based on the regular Deflate/Inflate + -- routines. + + -- pragma Import (C, inflateBack, "inflateBack"); + -- pragma Import (C, inflateBackEnd, "inflateBackEnd"); + +end ZLib.Thin; diff --git a/zlib/contrib/ada/zlib.adb b/zlib/contrib/ada/zlib.adb new file mode 100644 index 0000000..f071fac --- /dev/null +++ b/zlib/contrib/ada/zlib.adb @@ -0,0 +1,674 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib.adb,v 1.19 2003/07/13 16:02:19 vagul Exp $ + +with Ada.Exceptions; +with Ada.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; + +with Interfaces.C.Strings; + +with ZLib.Thin; + +package body ZLib is + + use type Thin.Int; + + type Z_Stream is new Thin.Z_Stream; + + type Return_Code_Enum is + (OK, + STREAM_END, + NEED_DICT, + ERRNO, + STREAM_ERROR, + DATA_ERROR, + MEM_ERROR, + BUF_ERROR, + VERSION_ERROR); + + type Flate_Step_Function is access + function (Strm : Thin.Z_Streamp; flush : Thin.Int) return Thin.Int; + pragma Convention (C, Flate_Step_Function); + + type Flate_End_Function is access + function (Ctrm : in Thin.Z_Streamp) return Thin.Int; + pragma Convention (C, Flate_End_Function); + + type Flate_Type is record + Step : Flate_Step_Function; + Done : Flate_End_Function; + end record; + + subtype Footer_Array is Stream_Element_Array (1 .. 8); + + Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) + := (16#1f#, 16#8b#, -- Magic header + 16#08#, -- Z_DEFLATED + 16#00#, -- Flags + 16#00#, 16#00#, 16#00#, 16#00#, -- Time + 16#00#, -- XFlags + 16#03# -- OS code + ); + -- The simplest gzip header is not for informational, but just for + -- gzip format compatibility. + -- Note that some code below is using assumption + -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make + -- Simple_GZip_Header'Last <= Footer_Array'Last. + + Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum + := (0 => OK, + 1 => STREAM_END, + 2 => NEED_DICT, + -1 => ERRNO, + -2 => STREAM_ERROR, + -3 => DATA_ERROR, + -4 => MEM_ERROR, + -5 => BUF_ERROR, + -6 => VERSION_ERROR); + + Flate : constant array (Boolean) of Flate_Type + := (True => (Step => Thin.Deflate'Access, + Done => Thin.DeflateEnd'Access), + False => (Step => Thin.Inflate'Access, + Done => Thin.InflateEnd'Access)); + + Flush_Finish : constant array (Boolean) of Flush_Mode + := (True => Finish, False => No_Flush); + + procedure Raise_Error (Stream : Z_Stream); + pragma Inline (Raise_Error); + + procedure Raise_Error (Message : String); + pragma Inline (Raise_Error); + + procedure Check_Error (Stream : Z_Stream; Code : Thin.Int); + + procedure Free is new Ada.Unchecked_Deallocation + (Z_Stream, Z_Stream_Access); + + function To_Thin_Access is new Ada.Unchecked_Conversion + (Z_Stream_Access, Thin.Z_Streamp); + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Separate translate routine for make gzip header. + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- translate routine without additional headers. + + ----------------- + -- Check_Error -- + ----------------- + + procedure Check_Error (Stream : Z_Stream; Code : Thin.Int) is + use type Thin.Int; + begin + if Code /= Thin.Z_OK then + Raise_Error + (Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Last_Error_Message (Stream)); + end if; + end Check_Error; + + ----------- + -- Close -- + ----------- + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False) + is + Code : Thin.Int; + begin + Code := Flate (Filter.Compression).Done + (To_Thin_Access (Filter.Strm)); + + Filter.Opened := False; + + if Ignore_Error or else Code = Thin.Z_OK then + Free (Filter.Strm); + else + declare + Error_Message : constant String + := Last_Error_Message (Filter.Strm.all); + begin + Free (Filter.Strm); + Ada.Exceptions.Raise_Exception + (ZLib_Error'Identity, + Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Error_Message); + end; + end if; + end Close; + + ----------- + -- CRC32 -- + ----------- + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32 + is + use Thin; + begin + return Unsigned_32 (crc32 + (ULong (CRC), + Bytes.To_Pointer (Data'Address), + Data'Length)); + end CRC32; + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) is + begin + CRC := CRC32 (CRC, Data); + end CRC32; + + ------------------ + -- Deflate_Init -- + ------------------ + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := 15; + Memory_Level : in Memory_Level_Type := 8; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + begin + -- We allow ZLib to make header only in case of default header type. + -- Otherwise we would either do header by ourselfs, or do not do + -- header at all. + + if Header = None or else Header = GZip then + Win_Bits := -Win_Bits; + end if; + + -- For the GZip CRC calculation and make headers. + + if Header = GZip then + Filter.CRC := 0; + Filter.Offset := Simple_GZip_Header'First; + else + Filter.Offset := Simple_GZip_Header'Last + 1; + end if; + + Filter.Strm := new Z_Stream; + Filter.Compression := True; + Filter.Stream_End := False; + Filter.Opened := True; + Filter.Header := Header; + + if Thin.Deflate_Init + (To_Thin_Access (Filter.Strm), + Level => Thin.Int (Level), + method => Thin.Int (Method), + windowBits => Win_Bits, + memLevel => Thin.Int (Memory_Level), + strategy => Thin.Int (Strategy)) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Deflate_Init; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + No_Data : Stream_Element_Array := (1 .. 0 => 0); + Last : Stream_Element_Offset; + begin + Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); + end Flush; + + ----------------------- + -- Generic_Translate -- + ----------------------- + + procedure Generic_Translate + (Filter : in out ZLib.Filter_Type; + In_Buffer_Size : Integer := Default_Buffer_Size; + Out_Buffer_Size : Integer := Default_Buffer_Size) + is + In_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (In_Buffer_Size)); + Out_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (Out_Buffer_Size)); + Last : Stream_Element_Offset; + In_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + begin + Main : loop + Data_In (In_Buffer, Last); + + In_First := In_Buffer'First; + + loop + Translate + (Filter, + In_Buffer (In_First .. Last), + In_Last, + Out_Buffer, + Out_Last, + Flush_Finish (Last < In_Buffer'First)); + + Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); + + exit Main when Stream_End (Filter); + + -- The end of in buffer. + exit when In_Last = Last; + + In_First := In_Last + 1; + end loop; + end loop Main; + + end Generic_Translate; + + ------------------ + -- Inflate_Init -- + ------------------ + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := 15; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + + procedure Check_Version; + -- Check the latest header types compatibility. + + procedure Check_Version is + begin + if Version <= "1.1.4" then + Raise_Error + ("Inflate header type " & Header_Type'Image (Header) + & " incompatible with ZLib version " & Version); + end if; + end Check_Version; + + begin + case Header is + when None => + Check_Version; + + -- Inflate data without headers determined + -- by negative Win_Bits. + + Win_Bits := -Win_Bits; + when GZip => + Check_Version; + + -- Inflate gzip data defined by flag 16. + + Win_Bits := Win_Bits + 16; + when Auto => + Check_Version; + + -- Inflate with automatic detection + -- of gzip or native header defined by flag 32. + + Win_Bits := Win_Bits + 32; + when Default => null; + end case; + + Filter.Strm := new Z_Stream; + Filter.Compression := False; + Filter.Stream_End := False; + Filter.Opened := True; + Filter.Header := Header; + + if Thin.Inflate_Init + (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Inflate_Init; + + ----------------- + -- Raise_Error -- + ----------------- + + procedure Raise_Error (Message : String) is + begin + Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); + end Raise_Error; + + procedure Raise_Error (Stream : Z_Stream) is + begin + Raise_Error (Last_Error_Message (Stream)); + end Raise_Error; + + ---------- + -- Read -- + ---------- + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset) + is + In_Last : Stream_Element_Offset; + Item_First : Ada.Streams.Stream_Element_Offset := Item'First; + + begin + pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); + + loop + if Rest_First > Buffer'Last then + Read (Buffer, Rest_Last); + Rest_First := Buffer'First; + end if; + + pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); + + Translate + (Filter => Filter, + In_Data => Buffer (Rest_First .. Rest_Last), + In_Last => In_Last, + Out_Data => Item (Item_First .. Item'Last), + Out_Last => Last, + Flush => Flush_Finish (Rest_Last < Rest_First)); + + Rest_First := In_Last + 1; + + exit when Last = Item'Last or else Stream_End (Filter); + + Item_First := Last + 1; + end loop; + end Read; + + ---------------- + -- Stream_End -- + ---------------- + + function Stream_End (Filter : in Filter_Type) return Boolean is + begin + if Filter.Header = GZip and Filter.Compression then + return Filter.Stream_End + and then Filter.Offset = Footer_Array'Last + 1; + else + return Filter.Stream_End; + end if; + end Stream_End; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); + end Total_Out; + + --------------- + -- Translate -- + --------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) is + begin + if Filter.Header = GZip and then Filter.Compression then + Translate_GZip + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + else + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + end if; + end Translate; + + -------------------- + -- Translate_Auto -- + -------------------- + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + use type Thin.Int; + Code : Thin.Int; + + begin + if Filter.Opened = False then + raise ZLib_Error; + end if; + + if Out_Data'Length = 0 then + raise Constraint_Error; + end if; + + Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); + Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length); + + Code := Flate (Filter.Compression).Step + (To_Thin_Access (Filter.Strm), + Thin.Int (Flush)); + + if Code = Thin.Z_STREAM_END then + Filter.Stream_End := True; + else + Check_Error (Filter.Strm.all, Code); + end if; + + In_Last := In_Data'Last + - Stream_Element_Offset (Avail_In (Filter.Strm.all)); + Out_Last := Out_Data'Last + - Stream_Element_Offset (Avail_Out (Filter.Strm.all)); + + end Translate_Auto; + + -------------------- + -- Translate_GZip -- + -------------------- + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + Out_First : Stream_Element_Offset; + + procedure Add_Data (Data : in Stream_Element_Array); + -- Add data to stream from the Filter.Offset till necessary, + -- used for add gzip headr/footer. + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32); + pragma Inline (Put_32); + + -------------- + -- Add_Data -- + -------------- + + procedure Add_Data (Data : in Stream_Element_Array) is + Data_First : Stream_Element_Offset renames Filter.Offset; + Data_Last : Stream_Element_Offset; + Data_Len : Stream_Element_Offset; -- -1 + Out_Len : Stream_Element_Offset; -- -1 + begin + Out_First := Out_Last + 1; + + if Data_First > Data'Last then + return; + end if; + + Data_Len := Data'Last - Data_First; + Out_Len := Out_Data'Last - Out_First; + + if Data_Len <= Out_Len then + Out_Last := Out_First + Data_Len; + Data_Last := Data'Last; + else + Out_Last := Out_Data'Last; + Data_Last := Data_First + Out_Len; + end if; + + Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); + + Data_First := Data_Last + 1; + Out_First := Out_Last + 1; + end Add_Data; + + ------------ + -- Put_32 -- + ------------ + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32) + is + D : Unsigned_32 := Data; + begin + for J in Item'First .. Item'First + 3 loop + Item (J) := Stream_Element (D and 16#FF#); + D := Shift_Right (D, 8); + end loop; + end Put_32; + + begin + Out_Last := Out_Data'First - 1; + + if not Filter.Stream_End then + Add_Data (Simple_GZip_Header); + + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data (Out_First .. Out_Data'Last), + Out_Last => Out_Last, + Flush => Flush); + + CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); + + end if; + + if Filter.Stream_End and then Out_Last <= Out_Data'Last then + -- This detection method would work only when + -- Simple_GZip_Header'Last > Footer_Array'Last + + if Filter.Offset = Simple_GZip_Header'Last + 1 then + Filter.Offset := Footer_Array'First; + end if; + + declare + Footer : Footer_Array; + begin + Put_32 (Footer, Filter.CRC); + Put_32 (Footer (Footer'First + 4 .. Footer'Last), + Unsigned_32 (Total_In (Filter))); + Add_Data (Footer); + end; + end if; + end Translate_GZip; + + ------------- + -- Version -- + ------------- + + function Version return String is + begin + return Interfaces.C.Strings.Value (Thin.zlibVersion); + end Version; + + ----------- + -- Write -- + ----------- + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + In_Last, Out_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset := Item'First; + begin + if Item'Length = 0 and Flush = No_Flush then + return; + end if; + + loop + Translate + (Filter => Filter, + In_Data => Item (In_First .. Item'Last), + In_Last => In_Last, + Out_Data => Buffer, + Out_Last => Out_Last, + Flush => Flush); + + if Out_Last >= Buffer'First then + Write (Buffer (1 .. Out_Last)); + end if; + + exit when In_Last = Item'Last or Stream_End (Filter); + + In_First := In_Last + 1; + end loop; + end Write; + +end ZLib; diff --git a/zlib/contrib/ada/zlib.ads b/zlib/contrib/ada/zlib.ads new file mode 100644 index 0000000..56d0a4f --- /dev/null +++ b/zlib/contrib/ada/zlib.ads @@ -0,0 +1,311 @@ +------------------------------------------------------------------------------ +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- This library is free software; you can redistribute it and/or modify -- +-- it under the terms of the GNU General Public License as published by -- +-- the Free Software Foundation; either version 2 of the License, or (at -- +-- your option) any later version. -- +-- -- +-- This library is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of -- +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- +-- General Public License for more details. -- +-- -- +-- You should have received a copy of the GNU General Public License -- +-- along with this library; if not, write to the Free Software Foundation, -- +-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +------------------------------------------------------------------------------ + +-- $Id: zlib.ads,v 1.17 2003/08/12 13:19:07 vagul Exp $ + +with Ada.Streams; + +with Interfaces; + +package ZLib is + + ZLib_Error : exception; + + type Compression_Level is new Integer range -1 .. 9; + + type Flush_Mode is private; + + type Compression_Method is private; + + type Window_Bits_Type is new Integer range 8 .. 15; + + type Memory_Level_Type is new Integer range 1 .. 9; + + type Unsigned_32 is new Interfaces.Unsigned_32; + + type Strategy_Type is private; + + type Header_Type is (None, Auto, Default, GZip); + -- Header type usage have a some limitation for inflate. + -- See comment for Inflate_Init. + + subtype Count is Ada.Streams.Stream_Element_Count; + + ---------------------------------- + -- Compression method constants -- + ---------------------------------- + + Deflated : constant Compression_Method; + -- Only one method allowed in this ZLib version. + + --------------------------------- + -- Compression level constants -- + --------------------------------- + + No_Compression : constant Compression_Level := 0; + Best_Speed : constant Compression_Level := 1; + Best_Compression : constant Compression_Level := 9; + Default_Compression : constant Compression_Level := -1; + + -------------------------- + -- Flush mode constants -- + -------------------------- + + No_Flush : constant Flush_Mode; + -- Regular way for compression, no flush + + Partial_Flush : constant Flush_Mode; + -- will be removed, use Z_SYNC_FLUSH instead + + Sync_Flush : constant Flush_Mode; + -- all pending output is flushed to the output buffer and the output + -- is aligned on a byte boundary, so that the decompressor can get all + -- input data available so far. (In particular avail_in is zero after the + -- call if enough output space has been provided before the call.) + -- Flushing may degrade compression for some compression algorithms and so + -- it should be used only when necessary. + + Full_Flush : constant Flush_Mode; + -- all output is flushed as with SYNC_FLUSH, and the compression state + -- is reset so that decompression can restart from this point if previous + -- compressed data has been damaged or if random access is desired. Using + -- FULL_FLUSH too often can seriously degrade the compression. + + Finish : constant Flush_Mode; + -- Just for tell the compressor that input data is complete. + + ------------------------------------ + -- Compression strategy constants -- + ------------------------------------ + + -- RLE stategy could be used only in version 1.2.0 and later. + + Filtered : constant Strategy_Type; + Huffman_Only : constant Strategy_Type; + RLE : constant Strategy_Type; + Default_Strategy : constant Strategy_Type; + + Default_Buffer_Size : constant := 4096; + + type Filter_Type is limited private; + -- The filter is for compression and for decompression. + -- The usage of the type is depend of its initialization. + + function Version return String; + pragma Inline (Version); + -- Return string representation of the ZLib version. + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := 15; + Memory_Level : in Memory_Level_Type := 8; + Header : in Header_Type := Default); + -- Compressor initialization. + -- When Header parameter is Auto or Default, then default zlib header + -- would be provided for compressed data. + -- When Header is GZip, then gzip header would be set instead of + -- default header. + -- When Header is None, no header would be set for compressed data. + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := 15; + Header : in Header_Type := Default); + -- Decompressor initialization. + -- Default header type mean that ZLib default header is expecting in the + -- input compressed stream. + -- Header type None mean that no header is expecting in the input stream. + -- GZip header type mean that GZip header is expecting in the + -- input compressed stream. + -- Auto header type mean that header type (GZip or Native) would be + -- detected automatically in the input stream. + -- Note that header types parameter values None, GZip and Auto is + -- supporting for inflate routine only in ZLib versions 1.2.0.2 and later. + -- Deflate_Init is supporting all header types. + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False); + -- Closing the compression or decompressor. + -- If stream is closing before the complete and Ignore_Error is False, + -- The exception would be raised. + + generic + with procedure Data_In + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + with procedure Data_Out + (Item : in Ada.Streams.Stream_Element_Array); + procedure Generic_Translate + (Filter : in out Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size); + -- Compressing/decompressing data arrived from Data_In routine + -- to the Data_Out routine. User should provide Data_In and Data_Out + -- for compression/decompression data flow. + -- Compression or decompression depend on initialization of Filter. + + function Total_In (Filter : in Filter_Type) return Count; + pragma Inline (Total_In); + -- Return total number of input bytes read so far. + + function Total_Out (Filter : in Filter_Type) return Count; + pragma Inline (Total_Out); + -- Return total number of bytes output so far. + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32; + pragma Inline (CRC32); + -- Calculate CRC32, it could be necessary for make gzip format. + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array); + pragma Inline (CRC32); + -- Calculate CRC32, it could be necessary for make gzip format. + + ------------------------------------------------- + -- Below is more complex low level routines. -- + ------------------------------------------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Compressing/decompressing the datas from In_Data buffer to the + -- Out_Data buffer. + -- In_Data is incoming data portion, + -- In_Last is the index of last element from In_Data accepted by the + -- Filter. + -- Out_Data is the buffer for output data from the filter. + -- Out_Last is the last element of the received data from Filter. + -- To tell the filter that incoming data is complete put the + -- Flush parameter to FINISH. + + function Stream_End (Filter : in Filter_Type) return Boolean; + pragma Inline (Stream_End); + -- Return the true when the stream is complete. + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + pragma Inline (Flush); + -- Flushing the data from the compressor. + + generic + with procedure Write + (Item : in Ada.Streams.Stream_Element_Array); + -- User should provide this routine for accept + -- compressed/decompressed data. + + Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + -- Buffer size for Write user routine. + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode); + -- Compressing/Decompressing data from Item to the + -- generic parameter procedure Write. + -- Output buffer size could be set in Buffer_Size generic parameter. + + generic + with procedure Read + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + -- User should provide data for compression/decompression + -- thru this routine. + + Buffer : in out Ada.Streams.Stream_Element_Array; + -- Buffer for keep remaining data from the previous + -- back read. + + Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset; + -- Rest_First have to be initialized to Buffer'Last + 1 + -- before usage. + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + -- Compressing/Decompressing data from generic parameter + -- procedure Read to the Item. + -- User should provide Buffer for the operation + -- and Rest_First variable first time initialized to the Buffer'Last + 1. + +private + + use Ada.Streams; + + type Flush_Mode is new Integer range 0 .. 4; + + type Compression_Method is new Integer range 8 .. 8; + + type Strategy_Type is new Integer range 0 .. 3; + + No_Flush : constant Flush_Mode := 0; + Sync_Flush : constant Flush_Mode := 2; + Full_Flush : constant Flush_Mode := 3; + Finish : constant Flush_Mode := 4; + Partial_Flush : constant Flush_Mode := 1; + -- will be removed, use Z_SYNC_FLUSH instead + + Filtered : constant Strategy_Type := 1; + Huffman_Only : constant Strategy_Type := 2; + RLE : constant Strategy_Type := 3; + Default_Strategy : constant Strategy_Type := 0; + + Deflated : constant Compression_Method := 8; + + type Z_Stream; + + type Z_Stream_Access is access all Z_Stream; + + type Filter_Type is record + Strm : Z_Stream_Access; + Compression : Boolean; + Stream_End : Boolean; + Header : Header_Type; + CRC : Unsigned_32; + Offset : Stream_Element_Offset; + -- Offset for gzip header/footer output. + + Opened : Boolean := False; + end record; + +end ZLib; diff --git a/zlib/contrib/ada/zlib.gpr b/zlib/contrib/ada/zlib.gpr new file mode 100644 index 0000000..e6d5526 --- /dev/null +++ b/zlib/contrib/ada/zlib.gpr @@ -0,0 +1,21 @@ +project Zlib is + + for Languages use ("Ada"); + for Source_Dirs use ("."); + for Object_Dir use "."; + for Main use ("test.adb", "mtest.adb", "read.adb"); + + package Compiler is + for Default_Switches ("ada") use ("-gnatwbcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst"); + end Compiler; + + package Linker is + for Default_Switches ("ada") use ("-lz"); + end Linker; + + package Builder is + for Default_Switches ("ada") use ("-s", "-gnatQ"); + end Builder; + +end Zlib; + diff --git a/zlib/contrib/asm586/README.586 b/zlib/contrib/asm586/README.586 new file mode 100644 index 0000000..a9293ed --- /dev/null +++ b/zlib/contrib/asm586/README.586 @@ -0,0 +1,43 @@ +This is a patched version of zlib modified to use +Pentium-optimized assembly code in the deflation algorithm. The files +changed/added by this patch are: + +README.586 +match.S + +The effectiveness of these modifications is a bit marginal, as the the +program's bottleneck seems to be mostly L1-cache contention, for which +there is no real way to work around without rewriting the basic +algorithm. The speedup on average is around 5-10% (which is generally +less than the amount of variance between subsequent executions). +However, when used at level 9 compression, the cache contention can +drop enough for the assembly version to achieve 10-20% speedup (and +sometimes more, depending on the amount of overall redundancy in the +files). Even here, though, cache contention can still be the limiting +factor, depending on the nature of the program using the zlib library. +This may also mean that better improvements will be seen on a Pentium +with MMX, which suffers much less from L1-cache contention, but I have +not yet verified this. + +Note that this code has been tailored for the Pentium in particular, +and will not perform well on the Pentium Pro (due to the use of a +partial register in the inner loop). + +If you are using an assembler other than GNU as, you will have to +translate match.S to use your assembler's syntax. (Have fun.) + +Brian Raiter +breadbox@muppetlabs.com +April, 1998 + + +Added for zlib 1.1.3: + +The patches come from +http://www.muppetlabs.com/~breadbox/software/assembly.html + +To compile zlib with this asm file, copy match.S to the zlib directory +then do: + +CFLAGS="-O3 -DASMV" ./configure +make OBJA=match.o diff --git a/zlib/contrib/asm586/match.S b/zlib/contrib/asm586/match.S new file mode 100644 index 0000000..17d0a26 --- /dev/null +++ b/zlib/contrib/asm586/match.S @@ -0,0 +1,354 @@ +/* match.s -- Pentium-optimized version of longest_match() + * Written for zlib 1.1.2 + * Copyright (C) 1998 Brian Raiter + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License. + */ + +#ifndef NO_UNDERLINE +#define match_init _match_init +#define longest_match _longest_match +#endif + +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ + +#define wmask 0 /* local copy of s->wmask */ +#define window 4 /* local copy of s->window */ +#define windowbestlen 8 /* s->window + bestlen */ +#define chainlenscanend 12 /* high word: current chain len */ + /* low word: last bytes sought */ +#define scanstart 16 /* first two bytes of string */ +#define scanalign 20 /* dword-misalignment of string */ +#define nicematch 24 /* a good enough match size */ +#define bestlen 28 /* size of best match so far */ +#define scan 32 /* ptr to string wanting match */ + +#define LocalVarsSize (36) +/* saved ebx 36 */ +/* saved edi 40 */ +/* saved esi 44 */ +/* saved ebp 48 */ +/* return address 52 */ +#define deflatestate 56 /* the function arguments */ +#define curmatch 60 + +/* Offsets for fields in the deflate_state structure. These numbers + * are calculated from the definition of deflate_state, with the + * assumption that the compiler will dword-align the fields. (Thus, + * changing the definition of deflate_state could easily cause this + * program to crash horribly, without so much as a warning at + * compile time. Sigh.) + */ +#define dsWSize 36 +#define dsWMask 44 +#define dsWindow 48 +#define dsPrev 56 +#define dsMatchLen 88 +#define dsPrevMatch 92 +#define dsStrStart 100 +#define dsMatchStart 104 +#define dsLookahead 108 +#define dsPrevLen 112 +#define dsMaxChainLen 116 +#define dsGoodMatch 132 +#define dsNiceMatch 136 + + +.file "match.S" + +.globl match_init, longest_match + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ + +longest_match: + +/* Save registers that the compiler may be using, and adjust %esp to */ +/* make room for our stack frame. */ + + pushl %ebp + pushl %edi + pushl %esi + pushl %ebx + subl $LocalVarsSize, %esp + +/* Retrieve the function arguments. %ecx will hold cur_match */ +/* throughout the entire function. %edx will hold the pointer to the */ +/* deflate_state structure during the function's setup (before */ +/* entering the main loop). */ + + movl deflatestate(%esp), %edx + movl curmatch(%esp), %ecx + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch(%edx), %eax + movl dsLookahead(%edx), %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, nicematch(%esp) + +/* register Bytef *scan = s->window + s->strstart; */ + + movl dsWindow(%edx), %esi + movl %esi, window(%esp) + movl dsStrStart(%edx), %ebp + lea (%esi,%ebp), %edi + movl %edi, scan(%esp) + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + movl %edi, %eax + negl %eax + andl $3, %eax + movl %eax, scanalign(%esp) + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize(%edx), %eax + subl $MIN_LOOKAHEAD, %eax + subl %eax, %ebp + jg LimitPositive + xorl %ebp, %ebp +LimitPositive: + +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen(%edx), %eax + movl dsGoodMatch(%edx), %ebx + cmpl %ebx, %eax + movl dsMaxChainLen(%edx), %ebx + jl LastMatchGood + shrl $2, %ebx +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the scanend */ +/* scanend value, which it will always accompany. */ + + decl %ebx + shll $16, %ebx + +/* int best_len = s->prev_length; */ + + movl dsPrevLen(%edx), %eax + movl %eax, bestlen(%esp) + +/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ + + addl %eax, %esi + movl %esi, windowbestlen(%esp) + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ + + movw (%edi), %bx + movw %bx, scanstart(%esp) + movw -1(%edi,%eax), %bx + movl %ebx, chainlenscanend(%esp) + +/* Posf *prev = s->prev; */ +/* uInt wmask = s->w_mask; */ + + movl dsPrev(%edx), %edi + movl dsWMask(%edx), %edx + mov %edx, wmask(%esp) + +/* Jump into the main loop. */ + + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + * + * Within this loop: + * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend) + * %ecx = curmatch + * %edx = curmatch & wmask + * %esi = windowbestlen - i.e., (window + bestlen) + * %edi = prev + * %ebp = limit + * + * Two optimization notes on the choice of instructions: + * + * The first instruction uses a 16-bit address, which costs an extra, + * unpairable cycle. This is cheaper than doing a 32-bit access and + * zeroing the high word, due to the 3-cycle misalignment penalty which + * would occur half the time. This also turns out to be cheaper than + * doing two separate 8-bit accesses, as the memory is so rarely in the + * L1 cache. + * + * The window buffer, however, apparently spends a lot of time in the + * cache, and so it is faster to retrieve the word at the end of the + * match string with two 8-bit loads. The instructions that test the + * word at the beginning of the match string, however, are executed + * much less frequently, and there it was cheaper to use 16-bit + * instructions, which avoided the necessity of saving off and + * subsequently reloading one of the other registers. + */ +LookupLoop: + /* 1 U & V */ + movw (%edi,%edx,2), %cx /* 2 U pipe */ + movl wmask(%esp), %edx /* 2 V pipe */ + cmpl %ebp, %ecx /* 3 U pipe */ + jbe LeaveNow /* 3 V pipe */ + subl $0x00010000, %ebx /* 4 U pipe */ + js LeaveNow /* 4 V pipe */ +LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */ + andl %ecx, %edx /* 5 V pipe */ + cmpb %bl, %al /* 6 U pipe */ + jnz LookupLoop /* 6 V pipe */ + movb (%esi,%ecx), %ah + cmpb %bh, %ah + jnz LookupLoop + movl window(%esp), %eax + movw (%eax,%ecx), %ax + cmpw scanstart(%esp), %ax + jnz LookupLoop + +/* Store the current value of chainlen. */ + + movl %ebx, chainlenscanend(%esp) + +/* Point %edi to the string under scrutiny, and %esi to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + movl window(%esp), %esi + movl scan(%esp), %edi + addl %ecx, %esi + movl scanalign(%esp), %eax + movl $(-MAX_MATCH_8), %edx + lea MAX_MATCH_8(%edi,%eax), %edi + lea MAX_MATCH_8(%esi,%eax), %esi + +/* Test the strings for equality, 8 bytes at a time. At the end, + * adjust %edx so that it is offset to the exact byte that mismatched. + * + * We already know at this point that the first three bytes of the + * strings match each other, and they can be safely passed over before + * starting the compare loop. So what this code does is skip over 0-3 + * bytes, as much as necessary in order to dword-align the %edi + * pointer. (%esi will still be misaligned three times out of four.) + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance. + */ +LoopCmps: + movl (%esi,%edx), %eax + movl (%edi,%edx), %ebx + xorl %ebx, %eax + jnz LeaveLoopCmps + movl 4(%esi,%edx), %eax + movl 4(%edi,%edx), %ebx + xorl %ebx, %eax + jnz LeaveLoopCmps4 + addl $8, %edx + jnz LoopCmps + jmp LenMaximum +LeaveLoopCmps4: addl $4, %edx +LeaveLoopCmps: testl $0x0000FFFF, %eax + jnz LenLower + addl $2, %edx + shrl $16, %eax +LenLower: subb $1, %al + adcl $0, %edx + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%edi,%edx), %eax + movl scan(%esp), %edi + subl %edi, %eax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + cmpl %ebx, %eax + jg LongerMatch + movl chainlenscanend(%esp), %ebx + movl windowbestlen(%esp), %esi + movl dsPrev(%edx), %edi + movl wmask(%esp), %edx + andl %ecx, %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: movl nicematch(%esp), %ebx + movl %eax, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + cmpl %ebx, %eax + jge LeaveNow + movl window(%esp), %esi + addl %eax, %esi + movl %esi, windowbestlen(%esp) + movl chainlenscanend(%esp), %ebx + movw -1(%edi,%eax), %bx + movl dsPrev(%edx), %edi + movl %ebx, chainlenscanend(%esp) + movl wmask(%esp), %edx + andl %ecx, %edx + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: movl deflatestate(%esp), %edx + movl $MAX_MATCH, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + movl dsLookahead(%edx), %eax + cmpl %eax, %ebx + jg LookaheadRet + movl %ebx, %eax +LookaheadRet: + +/* Restore the stack and return from whence we came. */ + + addl $LocalVarsSize, %esp + popl %ebx + popl %esi + popl %edi + popl %ebp +match_init: ret diff --git a/zlib/contrib/asm686/README.686 b/zlib/contrib/asm686/README.686 new file mode 100644 index 0000000..929932b --- /dev/null +++ b/zlib/contrib/asm686/README.686 @@ -0,0 +1,34 @@ +This is a patched version of zlib, modified to use +Pentium-Pro-optimized assembly code in the deflation algorithm. The +files changed/added by this patch are: + +README.686 +match.S + +The speedup that this patch provides varies, depending on whether the +compiler used to build the original version of zlib falls afoul of the +PPro's speed traps. My own tests show a speedup of around 10-20% at +the default compression level, and 20-30% using -9, against a version +compiled using gcc 2.7.2.3. Your mileage may vary. + +Note that this code has been tailored for the PPro/PII in particular, +and will not perform particuarly well on a Pentium. + +If you are using an assembler other than GNU as, you will have to +translate match.S to use your assembler's syntax. (Have fun.) + +Brian Raiter +breadbox@muppetlabs.com +April, 1998 + + +Added for zlib 1.1.3: + +The patches come from +http://www.muppetlabs.com/~breadbox/software/assembly.html + +To compile zlib with this asm file, copy match.S to the zlib directory +then do: + +CFLAGS="-O3 -DASMV" ./configure +make OBJA=match.o diff --git a/zlib/contrib/asm686/match.S b/zlib/contrib/asm686/match.S new file mode 100644 index 0000000..f77208e --- /dev/null +++ b/zlib/contrib/asm686/match.S @@ -0,0 +1,327 @@ +/* match.s -- Pentium-Pro-optimized version of longest_match() + * Written for zlib 1.1.2 + * Copyright (C) 1998 Brian Raiter + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License. + */ + +#ifndef NO_UNDERLINE +#define match_init _match_init +#define longest_match _longest_match +#endif + +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ + +#define chainlenwmask 0 /* high word: current chain len */ + /* low word: s->wmask */ +#define window 4 /* local copy of s->window */ +#define windowbestlen 8 /* s->window + bestlen */ +#define scanstart 16 /* first two bytes of string */ +#define scanend 12 /* last two bytes of string */ +#define scanalign 20 /* dword-misalignment of string */ +#define nicematch 24 /* a good enough match size */ +#define bestlen 28 /* size of best match so far */ +#define scan 32 /* ptr to string wanting match */ + +#define LocalVarsSize (36) +/* saved ebx 36 */ +/* saved edi 40 */ +/* saved esi 44 */ +/* saved ebp 48 */ +/* return address 52 */ +#define deflatestate 56 /* the function arguments */ +#define curmatch 60 + +/* Offsets for fields in the deflate_state structure. These numbers + * are calculated from the definition of deflate_state, with the + * assumption that the compiler will dword-align the fields. (Thus, + * changing the definition of deflate_state could easily cause this + * program to crash horribly, without so much as a warning at + * compile time. Sigh.) + */ +#define dsWSize 36 +#define dsWMask 44 +#define dsWindow 48 +#define dsPrev 56 +#define dsMatchLen 88 +#define dsPrevMatch 92 +#define dsStrStart 100 +#define dsMatchStart 104 +#define dsLookahead 108 +#define dsPrevLen 112 +#define dsMaxChainLen 116 +#define dsGoodMatch 132 +#define dsNiceMatch 136 + + +.file "match.S" + +.globl match_init, longest_match + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ + +longest_match: + +/* Save registers that the compiler may be using, and adjust %esp to */ +/* make room for our stack frame. */ + + pushl %ebp + pushl %edi + pushl %esi + pushl %ebx + subl $LocalVarsSize, %esp + +/* Retrieve the function arguments. %ecx will hold cur_match */ +/* throughout the entire function. %edx will hold the pointer to the */ +/* deflate_state structure during the function's setup (before */ +/* entering the main loop). */ + + movl deflatestate(%esp), %edx + movl curmatch(%esp), %ecx + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen(%edx), %eax + movl dsGoodMatch(%edx), %ebx + cmpl %ebx, %eax + movl dsWMask(%edx), %eax + movl dsMaxChainLen(%edx), %ebx + jl LastMatchGood + shrl $2, %ebx +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %ebx + shll $16, %ebx + orl %eax, %ebx + movl %ebx, chainlenwmask(%esp) + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch(%edx), %eax + movl dsLookahead(%edx), %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, nicematch(%esp) + +/* register Bytef *scan = s->window + s->strstart; */ + + movl dsWindow(%edx), %esi + movl %esi, window(%esp) + movl dsStrStart(%edx), %ebp + lea (%esi,%ebp), %edi + movl %edi, scan(%esp) + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + movl %edi, %eax + negl %eax + andl $3, %eax + movl %eax, scanalign(%esp) + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize(%edx), %eax + subl $MIN_LOOKAHEAD, %eax + subl %eax, %ebp + jg LimitPositive + xorl %ebp, %ebp +LimitPositive: + +/* int best_len = s->prev_length; */ + + movl dsPrevLen(%edx), %eax + movl %eax, bestlen(%esp) + +/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ + + addl %eax, %esi + movl %esi, windowbestlen(%esp) + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%edi), %ebx + movl %ebx, scanstart(%esp) + movzwl -1(%edi,%eax), %ebx + movl %ebx, scanend(%esp) + movl dsPrev(%edx), %edi + +/* Jump into the main loop. */ + + movl chainlenwmask(%esp), %edx + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + * + * Within this loop: + * %ebx = scanend + * %ecx = curmatch + * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) + * %esi = windowbestlen - i.e., (window + bestlen) + * %edi = prev + * %ebp = limit + */ +LookupLoop: + andl %edx, %ecx + movzwl (%edi,%ecx,2), %ecx + cmpl %ebp, %ecx + jbe LeaveNow + subl $0x00010000, %edx + js LeaveNow +LoopEntry: movzwl -1(%esi,%ecx), %eax + cmpl %ebx, %eax + jnz LookupLoop + movl window(%esp), %eax + movzwl (%eax,%ecx), %eax + cmpl scanstart(%esp), %eax + jnz LookupLoop + +/* Store the current value of chainlen. */ + + movl %edx, chainlenwmask(%esp) + +/* Point %edi to the string under scrutiny, and %esi to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + movl window(%esp), %esi + movl scan(%esp), %edi + addl %ecx, %esi + movl scanalign(%esp), %eax + movl $(-MAX_MATCH_8), %edx + lea MAX_MATCH_8(%edi,%eax), %edi + lea MAX_MATCH_8(%esi,%eax), %esi + +/* Test the strings for equality, 8 bytes at a time. At the end, + * adjust %edx so that it is offset to the exact byte that mismatched. + * + * We already know at this point that the first three bytes of the + * strings match each other, and they can be safely passed over before + * starting the compare loop. So what this code does is skip over 0-3 + * bytes, as much as necessary in order to dword-align the %edi + * pointer. (%esi will still be misaligned three times out of four.) + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance. + */ +LoopCmps: + movl (%esi,%edx), %eax + xorl (%edi,%edx), %eax + jnz LeaveLoopCmps + movl 4(%esi,%edx), %eax + xorl 4(%edi,%edx), %eax + jnz LeaveLoopCmps4 + addl $8, %edx + jnz LoopCmps + jmp LenMaximum +LeaveLoopCmps4: addl $4, %edx +LeaveLoopCmps: testl $0x0000FFFF, %eax + jnz LenLower + addl $2, %edx + shrl $16, %eax +LenLower: subb $1, %al + adcl $0, %edx + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%edi,%edx), %eax + movl scan(%esp), %edi + subl %edi, %eax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + cmpl %ebx, %eax + jg LongerMatch + movl windowbestlen(%esp), %esi + movl dsPrev(%edx), %edi + movl scanend(%esp), %ebx + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: movl nicematch(%esp), %ebx + movl %eax, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + cmpl %ebx, %eax + jge LeaveNow + movl window(%esp), %esi + addl %eax, %esi + movl %esi, windowbestlen(%esp) + movzwl -1(%edi,%eax), %ebx + movl dsPrev(%edx), %edi + movl %ebx, scanend(%esp) + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: movl deflatestate(%esp), %edx + movl $MAX_MATCH, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + movl dsLookahead(%edx), %eax + cmpl %eax, %ebx + jg LookaheadRet + movl %ebx, %eax +LookaheadRet: + +/* Restore the stack and return from whence we came. */ + + addl $LocalVarsSize, %esp + popl %ebx + popl %esi + popl %edi + popl %ebp +match_init: ret diff --git a/zlib/contrib/blast/Makefile b/zlib/contrib/blast/Makefile new file mode 100644 index 0000000..861cf16 --- /dev/null +++ b/zlib/contrib/blast/Makefile @@ -0,0 +1,8 @@ +blast: blast.c blast.h + cc -DTEST -o blast blast.c + +test: blast + blast < test.pk | cmp - test.txt + +clean: + rm -f blast blast.o diff --git a/zlib/contrib/blast/README b/zlib/contrib/blast/README new file mode 100644 index 0000000..f6a27eb --- /dev/null +++ b/zlib/contrib/blast/README @@ -0,0 +1,4 @@ +Read blast.h for purpose and usage. + +Mark Adler +madler@alumni.caltech.edu diff --git a/zlib/contrib/blast/blast.c b/zlib/contrib/blast/blast.c new file mode 100644 index 0000000..add26f7 --- /dev/null +++ b/zlib/contrib/blast/blast.c @@ -0,0 +1,444 @@ +/* blast.c + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in blast.h + * version 1.1, 16 Feb 2003 + * + * blast.c decompresses data compressed by the PKWare Compression Library. + * This function provides functionality similar to the explode() function of + * the PKWare library, hence the name "blast". + * + * This decompressor is based on the excellent format description provided by + * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the + * example Ben provided in the post is incorrect. The distance 110001 should + * instead be 111000. When corrected, the example byte stream becomes: + * + * 00 04 82 24 25 8f 80 7f + * + * which decompresses to "AIAIAIAIAIAIA" (without the quotes). + */ + +/* + * Change history: + * + * 1.0 12 Feb 2003 - First version + * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "blast.h" /* prototype for blast() */ + +#define local static /* for local function definitions */ +#define MAXBITS 13 /* maximum code length */ +#define MAXWIN 4096 /* maximum window size */ + +/* input and output state */ +struct state { + /* input state */ + blast_in infun; /* input function provided by user */ + void *inhow; /* opaque information passed to infun() */ + unsigned char *in; /* next input location */ + unsigned left; /* available input at in */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; + + /* output state */ + blast_out outfun; /* output function provided by user */ + void *outhow; /* opaque information passed to outfun() */ + unsigned next; /* index of next write location in out[] */ + int first; /* true to check distances (for first 4K) */ + unsigned char out[MAXWIN]; /* output buffer and sliding window */ +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + int val; /* bit accumulator */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ + s->left--; + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = val >> need; + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return val & ((1 << need) - 1); +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. + * + * - The first code for the shortest length is all ones. Subsequent codes of + * the same length are simply integer decrements of the previous code. When + * moving up a length, a one bit is appended to the code. For a complete + * code, the last code of the longest length will be all zeros. To support + * this ordering, the bits pulled during decoding are inverted to apply the + * more "natural" ordering starting with all zeros and incrementing. + */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= (bitbuf & 1) ^ 1; /* invert code */ + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + bitbuf = *(s->in)++; + s->left--; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} + +/* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + */ +local int construct(struct huffman *h, const unsigned char *rep, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short length[256]; /* code lengths */ + + /* convert compact repeat counts into symbol bit length list */ + symbol = 0; + do { + len = *rep++; + left = (len >> 4) + 1; + len &= 15; + do { + length[symbol++] = len; + } while (--left); + } while (--n); + n = symbol; + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode PKWare Compression Library stream. + * + * Format notes: + * + * - First byte is 0 if literals are uncoded or 1 if they are coded. Second + * byte is 4, 5, or 6 for the number of extra bits in the distance code. + * This is the base-2 logarithm of the dictionary size minus six. + * + * - Compressed data is a combination of literals and length/distance pairs + * terminated by an end code. Literals are either Huffman coded or + * uncoded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - A bit preceding a literal or length/distance pair indicates which comes + * next, 0 for literals, 1 for length/distance. + * + * - If literals are uncoded, then the next eight bits are the literal, in the + * normal bit order in th stream, i.e. no bit-reversal is needed. Similarly, + * no bit reversal is needed for either the length extra bits or the distance + * extra bits. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 518 + * simply copies the last byte 518 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. + */ +local int decomp(struct state *s) +{ + int lit; /* true if literals are coded */ + int dict; /* log2(dictionary size) - 6 */ + int symbol; /* decoded symbol, extra bits for distance */ + int len; /* length for copy */ + int dist; /* distance for copy */ + int copy; /* copy counter */ + unsigned char *from, *to; /* copy pointers */ + static int virgin = 1; /* build tables once */ + static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ + static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ + static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ + static struct huffman litcode = {litcnt, litsym}; /* length code */ + static struct huffman lencode = {lencnt, lensym}; /* length code */ + static struct huffman distcode = {distcnt, distsym};/* distance code */ + /* bit lengths of literal codes */ + static const unsigned char litlen[] = { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, + 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, + 44, 173}; + /* bit lengths of length codes 0..15 */ + static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; + /* bit lengths of distance codes 0..63 */ + static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; + static const short base[16] = { /* base for length codes */ + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; + static const char extra[16] = { /* extra bits for length codes */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; + + /* set up decoding tables (once--might not be thread-safe) */ + if (virgin) { + construct(&litcode, litlen, sizeof(litlen)); + construct(&lencode, lenlen, sizeof(lenlen)); + construct(&distcode, distlen, sizeof(distlen)); + virgin = 0; + } + + /* read header */ + lit = bits(s, 8); + if (lit > 1) return -1; + dict = bits(s, 8); + if (dict < 4 || dict > 6) return -2; + + /* decode literals and length/distance pairs */ + do { + if (bits(s, 1)) { + /* get length */ + symbol = decode(s, &lencode); + len = base[symbol] + bits(s, extra[symbol]); + if (len == 519) break; /* end code */ + + /* get distance */ + symbol = len == 2 ? 2 : dict; + dist = decode(s, &distcode) << symbol; + dist += bits(s, symbol); + dist++; + if (s->first && dist > s->next) + return -3; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + do { + to = s->out + s->next; + from = to - dist; + copy = MAXWIN; + if (s->next < dist) { + from += copy; + copy = dist; + } + copy -= s->next; + if (copy > len) copy = len; + len -= copy; + s->next += copy; + do { + *to++ = *from++; + } while (--copy); + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } while (len != 0); + } + else { + /* get literal and write it */ + symbol = lit ? decode(s, &litcode) : bits(s, 8); + s->out[s->next++] = symbol; + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } + } while (1); + return 0; +} + +/* See comments in blast.h */ +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow) +{ + struct state s; /* input/output state */ + int err; /* return value */ + + /* initialize input state */ + s.infun = infun; + s.inhow = inhow; + s.left = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* initialize output state */ + s.outfun = outfun; + s.outhow = outhow; + s.next = 0; + s.first = 1; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ + err = 2; /* then skip decomp(), return error */ + else + err = decomp(&s); /* decompress */ + + /* write any leftover output and update the error code if needed */ + if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) + err = 1; + return err; +} + +#ifdef TEST +/* Example of how to use blast() */ +#include +#include + +#define CHUNK 16384 + +local unsigned inf(void *how, unsigned char **buf) +{ + static unsigned char hold[CHUNK]; + + *buf = hold; + return fread(hold, 1, CHUNK, (FILE *)how); +} + +local int outf(void *how, unsigned char *buf, unsigned len) +{ + return fwrite(buf, 1, len, (FILE *)how) != len; +} + +/* Decompress a PKWare Compression Library stream from stdin to stdout */ +int main(void) +{ + int ret, n; + + /* decompress to stdout */ + ret = blast(inf, stdin, outf, stdout); + if (ret != 0) fprintf(stderr, "blast error: %d\n", ret); + + /* see if there are any leftover bytes */ + n = 0; + while (getchar() != EOF) n++; + if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n); + + /* return blast() error code */ + return ret; +} +#endif diff --git a/zlib/contrib/blast/blast.h b/zlib/contrib/blast/blast.h new file mode 100644 index 0000000..ae42528 --- /dev/null +++ b/zlib/contrib/blast/blast.h @@ -0,0 +1,71 @@ +/* blast.h -- interface for blast.c + Copyright (C) 2003 Mark Adler + version 1.1, 16 Feb 2003 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * blast() decompresses the PKWare Data Compression Library (DCL) compressed + * format. It provides the same functionality as the explode() function in + * that library. (Note: PKWare overused the "implode" verb, and the format + * used by their library implode() function is completely different and + * incompatible with the implode compression method supported by PKZIP.) + */ + + +typedef unsigned (*blast_in)(void *how, unsigned char **buf); +typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); +/* Definitions for input/output functions passed to blast(). See below for + * what the provided functions need to do. + */ + + +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow); +/* Decompress input to output using the provided infun() and outfun() calls. + * On success, the return value of blast() is zero. If there is an error in + * the source data, i.e. it is not in the proper format, then a negative value + * is returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. + * + * The input function is invoked: len = infun(how, &buf), where buf is set by + * infun() to point to the input buffer, and infun() returns the number of + * available bytes there. If infun() returns zero, then blast() returns with + * an input error. (blast() only asks for input if it needs it.) inhow is for + * use by the application to pass an input descriptor to infun(), if desired. + * + * The output function is invoked: err = outfun(how, buf, len), where the bytes + * to be written are buf[0..len-1]. If err is not zero, then blast() returns + * with an output error. outfun() is always called with len <= 4096. outhow + * is for use by the application to pass an output descriptor to outfun(), if + * desired. + * + * The return codes are: + * + * 2: ran out of input before completing decompression + * 1: output error before completing decompression + * 0: successful decompression + * -1: literal flag not zero or one + * -2: dictionary size not in 4..6 + * -3: distance is too far back + * + * At the bottom of blast.c is an example program that uses blast() that can be + * compiled to produce a command-line decompression filter by defining TEST. + */ diff --git a/zlib/contrib/blast/test.pk b/zlib/contrib/blast/test.pk new file mode 100644 index 0000000..be10b2b Binary files /dev/null and b/zlib/contrib/blast/test.pk differ diff --git a/zlib/contrib/blast/test.txt b/zlib/contrib/blast/test.txt new file mode 100644 index 0000000..bfdf1c5 --- /dev/null +++ b/zlib/contrib/blast/test.txt @@ -0,0 +1 @@ +AIAIAIAIAIAIA \ No newline at end of file diff --git a/zlib/contrib/delphi/ZLib.pas b/zlib/contrib/delphi/ZLib.pas new file mode 100644 index 0000000..ec661bc --- /dev/null +++ b/zlib/contrib/delphi/ZLib.pas @@ -0,0 +1,557 @@ +{*******************************************************} +{ } +{ Borland Delphi Supplemental Components } +{ ZLIB Data Compression Interface Unit } +{ } +{ Copyright (c) 1997,99 Borland Corporation } +{ } +{*******************************************************} + +{ Updated for zlib 1.2.x by Cosmin Truta } + +unit ZLib; + +interface + +uses SysUtils, Classes; + +type + TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl; + TFree = procedure (AppData, Block: Pointer); cdecl; + + // Internal structure. Ignore. + TZStreamRec = packed record + next_in: PChar; // next input byte + avail_in: Integer; // number of bytes available at next_in + total_in: Longint; // total nb of input bytes read so far + + next_out: PChar; // next output byte should be put here + avail_out: Integer; // remaining free space at next_out + total_out: Longint; // total nb of bytes output so far + + msg: PChar; // last error message, NULL if no error + internal: Pointer; // not visible by applications + + zalloc: TAlloc; // used to allocate the internal state + zfree: TFree; // used to free the internal state + AppData: Pointer; // private data object passed to zalloc and zfree + + data_type: Integer; // best guess about the data type: ascii or binary + adler: Longint; // adler32 value of the uncompressed data + reserved: Longint; // reserved for future use + end; + + // Abstract ancestor class + TCustomZlibStream = class(TStream) + private + FStrm: TStream; + FStrmPos: Integer; + FOnProgress: TNotifyEvent; + FZRec: TZStreamRec; + FBuffer: array [Word] of Char; + protected + procedure Progress(Sender: TObject); dynamic; + property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; + constructor Create(Strm: TStream); + end; + +{ TCompressionStream compresses data on the fly as data is written to it, and + stores the compressed data to another stream. + + TCompressionStream is write-only and strictly sequential. Reading from the + stream will raise an exception. Using Seek to move the stream pointer + will raise an exception. + + Output data is cached internally, written to the output stream only when + the internal output buffer is full. All pending output data is flushed + when the stream is destroyed. + + The Position property returns the number of uncompressed bytes of + data that have been written to the stream so far. + + CompressionRate returns the on-the-fly percentage by which the original + data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 + If raw data size = 100 and compressed data size = 25, the CompressionRate + is 75% + + The OnProgress event is called each time the output buffer is filled and + written to the output stream. This is useful for updating a progress + indicator when you are writing a large chunk of data to the compression + stream in a single call.} + + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + TCompressionStream = class(TCustomZlibStream) + private + function GetCompressionRate: Single; + public + constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property CompressionRate: Single read GetCompressionRate; + property OnProgress; + end; + +{ TDecompressionStream decompresses data on the fly as data is read from it. + + Compressed data comes from a separate source stream. TDecompressionStream + is read-only and unidirectional; you can seek forward in the stream, but not + backwards. The special case of setting the stream position to zero is + allowed. Seeking forward decompresses data until the requested position in + the uncompressed data has been reached. Seeking backwards, seeking relative + to the end of the stream, requesting the size of the stream, and writing to + the stream will raise an exception. + + The Position property returns the number of bytes of uncompressed data that + have been read from the stream so far. + + The OnProgress event is called each time the internal input buffer of + compressed data is exhausted and the next block is read from the input stream. + This is useful for updating a progress indicator when you are reading a + large chunk of data from the decompression stream in a single call.} + + TDecompressionStream = class(TCustomZlibStream) + public + constructor Create(Source: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress; + end; + + + +{ CompressBuf compresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); + + +{ DecompressBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + OutEstimate = zero, or est. size of the decompressed data + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); + +{ DecompressToUserBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to user-allocated buffer to contain decompressed data + BufSize = number of bytes in OutBuf } +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); + +const + zlib_version = '1.2.1'; + +type + EZlibError = class(Exception); + ECompressionError = class(EZlibError); + EDecompressionError = class(EZlibError); + +implementation + +uses ZLibConst; + +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = (-1); + Z_STREAM_ERROR = (-2); + Z_DATA_ERROR = (-3); + Z_MEM_ERROR = (-4); + Z_BUF_ERROR = (-5); + Z_VERSION_ERROR = (-6); + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = (-1); + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +procedure adler32; external; +procedure compressBound; external; +procedure crc32; external; +procedure deflateInit2_; external; +procedure deflateParams; external; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + Result := AllocMem(Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + + + +// deflate compresses data +function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar; + recsize: Integer): Integer; external; +function deflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function deflateEnd(var strm: TZStreamRec): Integer; external; + +// inflate decompresses data +function inflateInit_(var strm: TZStreamRec; version: PChar; + recsize: Integer): Integer; external; +function inflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function inflateEnd(var strm: TZStreamRec): Integer; external; +function inflateReset(var strm: TZStreamRec): Integer; external; + + +function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; +begin +// GetMem(Result, Items*Size); + Result := AllocMem(Items * Size); +end; + +procedure zlibFreeMem(AppData, Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +{function zlibCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EZlibError.Create('error'); //!! +end;} + +function CCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise ECompressionError.Create('error'); //!! +end; + +function DCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EDecompressionError.Create('error'); //!! +end; + +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm))); + try + while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, 256); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := 256; + end; + finally + CCheck(deflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + + +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; + BufInc: Integer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + BufInc := (InBytes + 255) and not 255; + if OutEstimate = 0 then + OutBytes := BufInc + else + OutBytes := OutEstimate; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + while DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, BufInc); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := BufInc; + end; + finally + DCheck(inflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); +var + strm: TZStreamRec; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := BufSize; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then + raise EZlibError.CreateRes(@sTargetBufferTooSmall); + finally + DCheck(inflateEnd(strm)); + end; +end; + +// TCustomZlibStream + +constructor TCustomZLibStream.Create(Strm: TStream); +begin + inherited Create; + FStrm := Strm; + FStrmPos := Strm.Position; + FZRec.zalloc := zlibAllocMem; + FZRec.zfree := zlibFreeMem; +end; + +procedure TCustomZLibStream.Progress(Sender: TObject); +begin + if Assigned(FOnProgress) then FOnProgress(Sender); +end; + + +// TCompressionStream + +constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel; + Dest: TStream); +const + Levels: array [TCompressionLevel] of ShortInt = + (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); +begin + inherited Create(Dest); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec))); +end; + +destructor TCompressionStream.Destroy; +begin + FZRec.next_in := nil; + FZRec.avail_in := 0; + try + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END) + and (FZRec.avail_out = 0) do + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + end; + if FZRec.avail_out < sizeof(FBuffer) then + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out); + finally + deflateEnd(FZRec); + end; + inherited Destroy; +end; + +function TCompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + FZRec.next_in := @Buffer; + FZRec.avail_in := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_in > 0) do + begin + CCheck(deflate(FZRec, 0)); + if FZRec.avail_out = 0 then + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + FStrmPos := FStrm.Position; + Progress(Self); + end; + end; + Result := Count; +end; + +function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := FZRec.total_in + else + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.GetCompressionRate: Single; +begin + if FZRec.total_in = 0 then + Result := 0 + else + Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0; +end; + + +// TDecompressionStream + +constructor TDecompressionStream.Create(Source: TStream); +begin + inherited Create(Source); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec))); +end; + +destructor TDecompressionStream.Destroy; +begin + FStrm.Seek(-FZRec.avail_in, 1); + inflateEnd(FZRec); + inherited Destroy; +end; + +function TDecompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + FZRec.next_out := @Buffer; + FZRec.avail_out := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_out > 0) do + begin + if FZRec.avail_in = 0 then + begin + FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); + if FZRec.avail_in = 0 then + begin + Result := Count - FZRec.avail_out; + Exit; + end; + FZRec.next_in := FBuffer; + FStrmPos := FStrm.Position; + Progress(Self); + end; + CCheck(inflate(FZRec, 0)); + end; + Result := Count; +end; + +function TDecompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + raise EDecompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +var + I: Integer; + Buf: array [0..4095] of Char; +begin + if (Offset = 0) and (Origin = soFromBeginning) then + begin + DCheck(inflateReset(FZRec)); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + FStrm.Position := 0; + FStrmPos := 0; + end + else if ( (Offset >= 0) and (Origin = soFromCurrent)) or + ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then + begin + if Origin = soFromBeginning then Dec(Offset, FZRec.total_out); + if Offset > 0 then + begin + for I := 1 to Offset div sizeof(Buf) do + ReadBuffer(Buf, sizeof(Buf)); + ReadBuffer(Buf, Offset mod sizeof(Buf)); + end; + end + else + raise EDecompressionError.CreateRes(@sInvalidStreamOp); + Result := FZRec.total_out; +end; + + +end. diff --git a/zlib/contrib/delphi/ZLibConst.pas b/zlib/contrib/delphi/ZLibConst.pas new file mode 100644 index 0000000..9e9fa18 --- /dev/null +++ b/zlib/contrib/delphi/ZLibConst.pas @@ -0,0 +1,11 @@ +unit ZLibConst; + +interface + +resourcestring + sTargetBufferTooSmall = 'ZLib error: target buffer may be too small'; + sInvalidStreamOp = 'Invalid stream operation'; + +implementation + +end. diff --git a/zlib/contrib/delphi/readme.txt b/zlib/contrib/delphi/readme.txt new file mode 100644 index 0000000..5aed74e --- /dev/null +++ b/zlib/contrib/delphi/readme.txt @@ -0,0 +1,76 @@ + +Overview +======== + +This directory contains an update to the ZLib interface unit, +distributed by Borland as a Delphi supplemental component. + +The original ZLib unit is Copyright (c) 1997,99 Borland Corp., +and is based on zlib version 1.0.4. There are a series of bugs +and security problems associated with that old zlib version, and +we recommend the users to update their ZLib unit. + + +Summary of modifications +======================== + +- Improved makefile, adapted to zlib version 1.2.1. + +- Some field types from TZStreamRec are changed from Integer to + Longint, for consistency with the zlib.h header, and for 64-bit + readiness. + +- The zlib_version constant is updated. + +- The new Z_RLE strategy has its corresponding symbolic constant. + +- The allocation and deallocation functions and function types + (TAlloc, TFree, zlibAllocMem and zlibFreeMem) are now cdecl, + and _malloc and _free are added as C RTL stubs. As a result, + the original C sources of zlib can be compiled out of the box, + and linked to the ZLib unit. + + +Suggestions for improvements +============================ + +Currently, the ZLib unit provides only a limited wrapper around +the zlib library, and much of the original zlib functionality is +missing. Handling compressed file formats like ZIP/GZIP or PNG +cannot be implemented without having this functionality. +Applications that handle these formats are either using their own, +duplicated code, or not using the ZLib unit at all. + +Here are a few suggestions: + +- Checksum class wrappers around adler32() and crc32(), similar + to the Java classes that implement the java.util.zip.Checksum + interface. + +- The ability to read and write raw deflate streams, without the + zlib stream header and trailer. Raw deflate streams are used + in the ZIP file format. + +- The ability to read and write gzip streams, used in the GZIP + file format, and normally produced by the gzip program. + +- The ability to select a different compression strategy, useful + to PNG and MNG image compression, and to multimedia compression + in general. Besides the compression level + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + which, in fact, could have used the 'z' prefix and avoided + TColor-like symbols + + TCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax); + + there could be a compression strategy + + TCompressionStrategy = (zsDefault, zsFiltered, zsHuffmanOnly, zsRle); + +- ZIP and GZIP stream handling via TStreams. + + +-- +Cosmin Truta diff --git a/zlib/contrib/delphi/zlibd32.mak b/zlib/contrib/delphi/zlibd32.mak new file mode 100644 index 0000000..6fb10e4 --- /dev/null +++ b/zlib/contrib/delphi/zlibd32.mak @@ -0,0 +1,93 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj +OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj +OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/zlib/contrib/gzappend/gzappend.c b/zlib/contrib/gzappend/gzappend.c new file mode 100644 index 0000000..052ab43 --- /dev/null +++ b/zlib/contrib/gzappend/gzappend.c @@ -0,0 +1,500 @@ +/* gzappend -- command to append to a gzip file + + Copyright (C) 2003 Mark Adler, all rights reserved + version 1.1, 4 Nov 2003 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 19 Oct 2003 - First version + * 1.1 4 Nov 2003 - Expand and clarify some comments and notes + * - Add version and copyright to help + * - Send help to stdout instead of stderr + * - Add some preemptive typecasts + * - Add L to constants in lseek() calls + * - Remove some debugging information in error messages + * - Use new data_type definition for zlib 1.2.1 + * - Simplfy and unify file operations + * - Finish off gzip file in gztack() + * - Use deflatePrime() instead of adding empty blocks + * - Keep gzip file clean on appended file read errors + * - Use in-place rotate instead of auxiliary buffer + * (Why you ask? Because it was fun to write!) + */ + +/* + gzappend takes a gzip file and appends to it, compressing files from the + command line or data from stdin. The gzip file is written to directly, to + avoid copying that file, in case it's large. Note that this results in the + unfriendly behavior that if gzappend fails, the gzip file is corrupted. + + This program was written to illustrate the use of the new Z_BLOCK option of + zlib 1.2.1's inflate() function. This option returns from inflate() at each + block boundary to facilitate locating and modifying the last block bit at + the start of the final deflate block. Also whether using Z_BLOCK or not, + another required feature of zlib 1.2.1 is that inflate() now provides the + number of unusued bits in the last input byte used. gzappend will not work + with versions of zlib earlier than 1.2.1. + + gzappend first decompresses the gzip file internally, discarding all but + the last 32K of uncompressed data, and noting the location of the last block + bit and the number of unused bits in the last byte of the compressed data. + The gzip trailer containing the CRC-32 and length of the uncompressed data + is verified. This trailer will be later overwritten. + + Then the last block bit is cleared by seeking back in the file and rewriting + the byte that contains it. Seeking forward, the last byte of the compressed + data is saved along with the number of unused bits to initialize deflate. + + A deflate process is initialized, using the last 32K of the uncompressed + data from the gzip file to initialize the dictionary. If the total + uncompressed data was less than 32K, then all of it is used to initialize + the dictionary. The deflate output bit buffer is also initialized with the + last bits from the original deflate stream. From here on, the data to + append is simply compressed using deflate, and written to the gzip file. + When that is complete, the new CRC-32 and uncompressed length are written + as the trailer of the gzip file. + */ + +#include +#include +#include +#include +#include +#include "zlib.h" + +#define local static +#define LGCHUNK 14 +#define CHUNK (1U << LGCHUNK) +#define DSIZE 32768U + +/* print an error message and terminate with extreme prejudice */ +local void bye(char *msg1, char *msg2) +{ + fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2); + exit(1); +} + +/* return the greatest common divisor of a and b using Euclid's algorithm, + modified to be fast when one argument much greater than the other, and + coded to avoid unnecessary swapping */ +local unsigned gcd(unsigned a, unsigned b) +{ + unsigned c; + + while (a && b) + if (a > b) { + c = b; + while (a - c >= c) + c <<= 1; + a -= c; + } + else { + c = a; + while (b - c >= c) + c <<= 1; + b -= c; + } + return a + b; +} + +/* rotate list[0..len-1] left by rot positions, in place */ +local void rotate(unsigned char *list, unsigned len, unsigned rot) +{ + unsigned char tmp; + unsigned cycles; + unsigned char *start, *last, *to, *from; + + /* normalize rot and handle degenerate cases */ + if (len < 2) return; + if (rot >= len) rot %= len; + if (rot == 0) return; + + /* pointer to last entry in list */ + last = list + (len - 1); + + /* do simple left shift by one */ + if (rot == 1) { + tmp = *list; + memcpy(list, list + 1, len - 1); + *last = tmp; + return; + } + + /* do simple right shift by one */ + if (rot == len - 1) { + tmp = *last; + memmove(list + 1, list, len - 1); + *list = tmp; + return; + } + + /* otherwise do rotate as a set of cycles in place */ + cycles = gcd(len, rot); /* number of cycles */ + do { + start = from = list + cycles; /* start index is arbitrary */ + tmp = *from; /* save entry to be overwritten */ + for (;;) { + to = from; /* next step in cycle */ + from += rot; /* go right rot positions */ + if (from > last) from -= len; /* (pointer better not wrap) */ + if (from == start) break; /* all but one shifted */ + *to = *from; /* shift left */ + } + *to = tmp; /* complete the circle */ + } while (--cycles); +} + +/* structure for gzip file read operations */ +typedef struct { + int fd; /* file descriptor */ + int size; /* 1 << size is bytes in buf */ + unsigned left; /* bytes available at next */ + unsigned char *buf; /* buffer */ + unsigned char *next; /* next byte in buffer */ + char *name; /* file name for error messages */ +} file; + +/* reload buffer */ +local int readin(file *in) +{ + int len; + + len = read(in->fd, in->buf, 1 << in->size); + if (len == -1) bye("error reading ", in->name); + in->left = (unsigned)len; + in->next = in->buf; + return len; +} + +/* read from file in, exit if end-of-file */ +local int readmore(file *in) +{ + if (readin(in) == 0) bye("unexpected end of ", in->name); + return 0; +} + +#define read1(in) (in->left == 0 ? readmore(in) : 0, \ + in->left--, *(in->next)++) + +/* skip over n bytes of in */ +local void skip(file *in, unsigned n) +{ + unsigned bypass; + + if (n > in->left) { + n -= in->left; + bypass = n & ~((1U << in->size) - 1); + if (bypass) { + if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1) + bye("seeking ", in->name); + n -= bypass; + } + readmore(in); + if (n > in->left) + bye("unexpected end of ", in->name); + } + in->left -= n; + in->next += n; +} + +/* read a four-byte unsigned integer, little-endian, from in */ +unsigned long read4(file *in) +{ + unsigned long val; + + val = read1(in); + val += (unsigned)read1(in) << 8; + val += (unsigned long)read1(in) << 16; + val += (unsigned long)read1(in) << 24; + return val; +} + +/* skip over gzip header */ +local void gzheader(file *in) +{ + int flags; + unsigned n; + + if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file"); + if (read1(in) != 8) bye("unknown compression method in", in->name); + flags = read1(in); + if (flags & 0xe0) bye("unknown header flags set in", in->name); + skip(in, 6); + if (flags & 4) { + n = read1(in); + n += (unsigned)(read1(in)) << 8; + skip(in, n); + } + if (flags & 8) while (read1(in) != 0) ; + if (flags & 16) while (read1(in) != 0) ; + if (flags & 2) skip(in, 2); +} + +/* decompress gzip file "name", return strm with a deflate stream ready to + continue compression of the data in the gzip file, and return a file + descriptor pointing to where to write the compressed data -- the deflate + stream is initialized to compress using level "level" */ +local int gzscan(char *name, z_stream *strm, int level) +{ + int ret, lastbit, left, full; + unsigned have; + unsigned long crc, tot; + unsigned char *window; + off_t lastoff, end; + file gz; + + /* open gzip file */ + gz.name = name; + gz.fd = open(name, O_RDWR, 0); + if (gz.fd == -1) bye("cannot open ", name); + gz.buf = malloc(CHUNK); + if (gz.buf == NULL) bye("out of memory", ""); + gz.size = LGCHUNK; + gz.left = 0; + + /* skip gzip header */ + gzheader(&gz); + + /* prepare to decompress */ + window = malloc(DSIZE); + if (window == NULL) bye("out of memory", ""); + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = inflateInit2(strm, -15); + if (ret != Z_OK) bye("out of memory", " or library mismatch"); + + /* decompress the deflate stream, saving append information */ + lastbit = 0; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + left = 0; + strm->avail_in = gz.left; + strm->next_in = gz.next; + crc = crc32(0L, Z_NULL, 0); + have = full = 0; + do { + /* if needed, get more input */ + if (strm->avail_in == 0) { + readmore(&gz); + strm->avail_in = gz.left; + strm->next_in = gz.next; + } + + /* set up output to next available section of sliding window */ + strm->avail_out = DSIZE - have; + strm->next_out = window + have; + + /* inflate and check for errors */ + ret = inflate(strm, Z_BLOCK); + if (ret == Z_STREAM_ERROR) bye("internal stream error!", ""); + if (ret == Z_MEM_ERROR) bye("out of memory", ""); + if (ret == Z_DATA_ERROR) + bye("invalid compressed data--format violated in", name); + + /* update crc and sliding window pointer */ + crc = crc32(crc, window + have, DSIZE - have - strm->avail_out); + if (strm->avail_out) + have = DSIZE - strm->avail_out; + else { + have = 0; + full = 1; + } + + /* process end of block */ + if (strm->data_type & 128) { + if (strm->data_type & 64) + left = strm->data_type & 0x1f; + else { + lastbit = strm->data_type & 0x1f; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in; + } + } + } while (ret != Z_STREAM_END); + inflateEnd(strm); + gz.left = strm->avail_in; + gz.next = strm->next_in; + + /* save the location of the end of the compressed data */ + end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + + /* check gzip trailer and save total for deflate */ + if (crc != read4(&gz)) + bye("invalid compressed data--crc mismatch in ", name); + tot = strm->total_out; + if ((tot & 0xffffffffUL) != read4(&gz)) + bye("invalid compressed data--length mismatch in", name); + + /* if not at end of file, warn */ + if (gz.left || readin(&gz)) + fprintf(stderr, + "gzappend warning: junk at end of gzip file overwritten\n"); + + /* clear last block bit */ + lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7))); + lseek(gz.fd, -1L, SEEK_CUR); + if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name); + + /* if window wrapped, build dictionary from window by rotating */ + if (full) { + rotate(window, DSIZE, have); + have = DSIZE; + } + + /* set up deflate stream with window, crc, total_in, and leftover bits */ + ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) bye("out of memory", ""); + deflateSetDictionary(strm, window, have); + strm->adler = crc; + strm->total_in = tot; + if (left) { + lseek(gz.fd, --end, SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + deflatePrime(strm, 8 - left, *gz.buf); + } + lseek(gz.fd, end, SEEK_SET); + + /* clean up and return */ + free(window); + free(gz.buf); + return gz.fd; +} + +/* append file "name" to gzip file gd using deflate stream strm -- if last + is true, then finish off the deflate stream at the end */ +local void gztack(char *name, int gd, z_stream *strm, int last) +{ + int fd, len, ret; + unsigned left; + unsigned char *in, *out; + + /* open file to compress and append */ + fd = 0; + if (name != NULL) { + fd = open(name, O_RDONLY, 0); + if (fd == -1) + fprintf(stderr, "gzappend warning: %s not found, skipping ...\n", + name); + } + + /* allocate buffers */ + in = fd == -1 ? NULL : malloc(CHUNK); + out = malloc(CHUNK); + if (out == NULL) bye("out of memory", ""); + + /* compress input file and append to gzip file */ + do { + /* get more input */ + len = fd == -1 ? 0 : read(fd, in, CHUNK); + if (len == -1) { + fprintf(stderr, + "gzappend warning: error reading %s, skipping rest ...\n", + name); + len = 0; + } + strm->avail_in = (unsigned)len; + strm->next_in = in; + if (len) strm->adler = crc32(strm->adler, in, (unsigned)len); + + /* compress and write all available output */ + do { + strm->avail_out = CHUNK; + strm->next_out = out; + ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH); + left = CHUNK - strm->avail_out; + while (left) { + len = write(gd, out + CHUNK - strm->avail_out - left, left); + if (len == -1) bye("writing gzip file", ""); + left -= (unsigned)len; + } + } while (strm->avail_out == 0 && ret != Z_STREAM_END); + } while (len != 0); + + /* write trailer after last entry */ + if (last) { + deflateEnd(strm); + out[0] = (unsigned char)(strm->adler); + out[1] = (unsigned char)(strm->adler >> 8); + out[2] = (unsigned char)(strm->adler >> 16); + out[3] = (unsigned char)(strm->adler >> 24); + out[4] = (unsigned char)(strm->total_in); + out[5] = (unsigned char)(strm->total_in >> 8); + out[6] = (unsigned char)(strm->total_in >> 16); + out[7] = (unsigned char)(strm->total_in >> 24); + len = 8; + do { + ret = write(gd, out + 8 - len, len); + if (ret == -1) bye("writing gzip file", ""); + len -= ret; + } while (len); + close(gd); + } + + /* clean up and return */ + free(out); + if (in != NULL) free(in); + if (fd > 0) close(fd); +} + +/* process the compression level option if present, scan the gzip file, and + append the specified files, or append the data from stdin if no other file + names are provided on the command line -- the gzip file must be writable + and seekable */ +int main(int argc, char **argv) +{ + int gd, level; + z_stream strm; + + /* ignore command name */ + argv++; + + /* provide usage if no arguments */ + if (*argv == NULL) { + printf("gzappend 1.1 (4 Nov 2003) Copyright (C) 2003 Mark Adler\n"); + printf( + "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n"); + return 0; + } + + /* set compression level */ + level = Z_DEFAULT_COMPRESSION; + if (argv[0][0] == '-') { + if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0) + bye("invalid compression level", ""); + level = argv[0][1] - '0'; + if (*++argv == NULL) bye("no gzip file name after options", ""); + } + + /* prepare to append to gzip file */ + gd = gzscan(*argv++, &strm, level); + + /* append files on command line, or from stdin if none */ + if (*argv == NULL) + gztack(NULL, gd, &strm, 1); + else + do { + gztack(*argv, gd, &strm, argv[1] == NULL); + } while (*++argv != NULL); + return 0; +} diff --git a/zlib/contrib/infback9/README b/zlib/contrib/infback9/README new file mode 100644 index 0000000..b084612 --- /dev/null +++ b/zlib/contrib/infback9/README @@ -0,0 +1 @@ +See infback9.h for what this is and how to use it. diff --git a/zlib/contrib/infback9/infback9.c b/zlib/contrib/infback9/infback9.c new file mode 100644 index 0000000..045ab75 --- /dev/null +++ b/zlib/contrib/infback9/infback9.c @@ -0,0 +1,605 @@ +/* infback9.c -- inflate deflate64 data using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infback9.h" +#include "inftree9.h" +#include "inflate9.h" + +#define WSIZE 65536UL + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + window is a user-supplied window and output buffer that is 64K bytes. + */ +int ZEXPORT inflateBack9Init_(strm, window, version, stream_size) +z_stream FAR *strm; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->window = window; + return Z_OK; +} + +/* + Build and output length and distance decoding tables for fixed code + decoding. + */ +#ifdef MAKEFIXED +#include + +void makefixed9(void) +{ + unsigned sym, bits, low, size; + code *next, *lenfix, *distfix; + struct inflate_state state; + code fixed[544]; + + /* literal/length table */ + sym = 0; + while (sym < 144) state.lens[sym++] = 8; + while (sym < 256) state.lens[sym++] = 9; + while (sym < 280) state.lens[sym++] = 7; + while (sym < 288) state.lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table9(LENS, state.lens, 288, &(next), &(bits), state.work); + + /* distance table */ + sym = 0; + while (sym < 32) state.lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table9(DISTS, state.lens, 32, &(next), &(bits), state.work); + + /* write tables */ + puts(" /* inffix9.h -- table for decoding deflate64 fixed codes"); + puts(" * Generated automatically by makefixed9()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", lenfix[low].op, lenfix[low].bits, + lenfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 5) == 0) printf("\n "); + printf("{%u,%u,%d}", distfix[low].op, distfix[low].bits, + distfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* Macros for inflateBack(): */ + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n <= 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = window; \ + left = WSIZE; \ + wrap = 1; \ + if (out(out_desc, put, (unsigned)left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have; /* available input */ + unsigned long left; /* available output */ + inflate_mode mode; /* current inflate mode */ + int lastblock; /* true if processing last block */ + int wrap; /* true if the window has wrapped */ + unsigned long write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned extra; /* extra bits needed */ + unsigned long length; /* literal or length of data to copy */ + unsigned long offset; /* distance back to copy string from */ + unsigned long copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + 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}; +#include "inffix9.h" + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + mode = TYPE; + lastblock = 0; + write = 0; + wrap = 0; + window = state->window; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = window; + left = WSIZE; + lencode = Z_NULL; + distcode = Z_NULL; + + /* Inflate until end of block marked as last */ + for (;;) + switch (mode) { + case TYPE: + /* determine and dispatch block type */ + if (lastblock) { + BYTEBITS(); + mode = DONE; + break; + } + NEEDBITS(3); + lastblock = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + lastblock ? " (last)" : "")); + mode = STORED; + break; + case 1: /* fixed block */ + lencode = lenfix; + lenbits = 9; + distcode = distfix; + distbits = 5; + Tracev((stderr, "inflate: fixed codes block%s\n", + lastblock ? " (last)" : "")); + mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + lastblock ? " (last)" : "")); + mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + mode = BAD; + break; + } + length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %lu\n", + length)); + INITBITS(); + + /* copy stored block from input to output */ + while (length != 0) { + copy = length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); + if (state->nlen > 286) { + strm->msg = (char *)"too many length symbols"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 7; + ret = inflate_table9(CODES, state->lens, 19, &(state->next), + &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = lencode[BITS(lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 9; + ret = inflate_table9(LENS, state->lens, state->nlen, + &(state->next), &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + mode = BAD; + break; + } + distcode = (code const FAR *)(state->next); + distbits = 6; + ret = inflate_table9(DISTS, state->lens + state->nlen, + state->ndist, &(state->next), &(distbits), + state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + mode = LEN; + + case LEN: + /* get a literal, length, or end-of-block code */ + for (;;) { + this = lencode[BITS(lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(length); + left--; + mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + extra = (unsigned)(this.op) & 31; + if (extra != 0) { + NEEDBITS(extra); + length += BITS(extra); + DROPBITS(extra); + } + Tracevv((stderr, "inflate: length %lu\n", length)); + + /* get distance code */ + for (;;) { + this = distcode[BITS(distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + mode = BAD; + break; + } + offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + extra = (unsigned)(this.op) & 15; + if (extra != 0) { + NEEDBITS(extra); + offset += BITS(extra); + DROPBITS(extra); + } + if (offset > WSIZE - (wrap ? 0: left)) { + strm->msg = (char *)"invalid distance too far back"; + mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %lu\n", offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = WSIZE - offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - offset; + copy = left; + } + if (copy > length) copy = length; + length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < WSIZE) { + if (out(out_desc, window, (unsigned)(WSIZE - left))) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBack9End(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/zlib/contrib/infback9/infback9.h b/zlib/contrib/infback9/infback9.h new file mode 100644 index 0000000..6dbd0bc --- /dev/null +++ b/zlib/contrib/infback9/infback9.h @@ -0,0 +1,29 @@ +/* infback9.h -- header for using inflateBack9 functions + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * This header file and associated patches provide a decoder for PKWare's + * undocumented deflate64 compression method (method 9). Use with infback9.c, + * inftree9.h, inftree9.c, and inffix9.h. These patches are not supported. + * This should be compiled with zlib, since it uses zutil.h and zutil.o. + * This code has not yet been tested on 16-bit architectures. See the + * comments in zlib.h for inflateBack() usage. These functions are used + * identically, except that there is no windowBits parameter, and a 64K + * window must be provided. Also if int's are 16 bits, then a zero for + * the third parameter of the "out" function actually means 65536UL. + * zlib.h must be included before this header file. + */ + +ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm)); +ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define inflateBack9Init(strm, window) \ + inflateBack9Init_((strm), (window), \ + ZLIB_VERSION, sizeof(z_stream)) diff --git a/zlib/contrib/infback9/inffix9.h b/zlib/contrib/infback9/inffix9.h new file mode 100644 index 0000000..6f128f6 --- /dev/null +++ b/zlib/contrib/infback9/inffix9.h @@ -0,0 +1,107 @@ + /* inffix9.h -- table for decoding deflate64 fixed codes + * Generated automatically by makefixed9(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{132,8,115},{130,7,31},{0,8,112}, + {0,8,48},{0,9,192},{128,7,10},{0,8,96},{0,8,32},{0,9,160}, + {0,8,0},{0,8,128},{0,8,64},{0,9,224},{128,7,6},{0,8,88}, + {0,8,24},{0,9,144},{131,7,59},{0,8,120},{0,8,56},{0,9,208}, + {129,7,17},{0,8,104},{0,8,40},{0,9,176},{0,8,8},{0,8,136}, + {0,8,72},{0,9,240},{128,7,4},{0,8,84},{0,8,20},{133,8,227}, + {131,7,43},{0,8,116},{0,8,52},{0,9,200},{129,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232}, + {128,7,8},{0,8,92},{0,8,28},{0,9,152},{132,7,83},{0,8,124}, + {0,8,60},{0,9,216},{130,7,23},{0,8,108},{0,8,44},{0,9,184}, + {0,8,12},{0,8,140},{0,8,76},{0,9,248},{128,7,3},{0,8,82}, + {0,8,18},{133,8,163},{131,7,35},{0,8,114},{0,8,50},{0,9,196}, + {129,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},{0,8,130}, + {0,8,66},{0,9,228},{128,7,7},{0,8,90},{0,8,26},{0,9,148}, + {132,7,67},{0,8,122},{0,8,58},{0,9,212},{130,7,19},{0,8,106}, + {0,8,42},{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244}, + {128,7,5},{0,8,86},{0,8,22},{65,8,0},{131,7,51},{0,8,118}, + {0,8,54},{0,9,204},{129,7,15},{0,8,102},{0,8,38},{0,9,172}, + {0,8,6},{0,8,134},{0,8,70},{0,9,236},{128,7,9},{0,8,94}, + {0,8,30},{0,9,156},{132,7,99},{0,8,126},{0,8,62},{0,9,220}, + {130,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{133,8,131}, + {130,7,31},{0,8,113},{0,8,49},{0,9,194},{128,7,10},{0,8,97}, + {0,8,33},{0,9,162},{0,8,1},{0,8,129},{0,8,65},{0,9,226}, + {128,7,6},{0,8,89},{0,8,25},{0,9,146},{131,7,59},{0,8,121}, + {0,8,57},{0,9,210},{129,7,17},{0,8,105},{0,8,41},{0,9,178}, + {0,8,9},{0,8,137},{0,8,73},{0,9,242},{128,7,4},{0,8,85}, + {0,8,21},{144,8,3},{131,7,43},{0,8,117},{0,8,53},{0,9,202}, + {129,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133}, + {0,8,69},{0,9,234},{128,7,8},{0,8,93},{0,8,29},{0,9,154}, + {132,7,83},{0,8,125},{0,8,61},{0,9,218},{130,7,23},{0,8,109}, + {0,8,45},{0,9,186},{0,8,13},{0,8,141},{0,8,77},{0,9,250}, + {128,7,3},{0,8,83},{0,8,19},{133,8,195},{131,7,35},{0,8,115}, + {0,8,51},{0,9,198},{129,7,11},{0,8,99},{0,8,35},{0,9,166}, + {0,8,3},{0,8,131},{0,8,67},{0,9,230},{128,7,7},{0,8,91}, + {0,8,27},{0,9,150},{132,7,67},{0,8,123},{0,8,59},{0,9,214}, + {130,7,19},{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139}, + {0,8,75},{0,9,246},{128,7,5},{0,8,87},{0,8,23},{77,8,0}, + {131,7,51},{0,8,119},{0,8,55},{0,9,206},{129,7,15},{0,8,103}, + {0,8,39},{0,9,174},{0,8,7},{0,8,135},{0,8,71},{0,9,238}, + {128,7,9},{0,8,95},{0,8,31},{0,9,158},{132,7,99},{0,8,127}, + {0,8,63},{0,9,222},{130,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80}, + {0,8,16},{132,8,115},{130,7,31},{0,8,112},{0,8,48},{0,9,193}, + {128,7,10},{0,8,96},{0,8,32},{0,9,161},{0,8,0},{0,8,128}, + {0,8,64},{0,9,225},{128,7,6},{0,8,88},{0,8,24},{0,9,145}, + {131,7,59},{0,8,120},{0,8,56},{0,9,209},{129,7,17},{0,8,104}, + {0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},{0,9,241}, + {128,7,4},{0,8,84},{0,8,20},{133,8,227},{131,7,43},{0,8,116}, + {0,8,52},{0,9,201},{129,7,13},{0,8,100},{0,8,36},{0,9,169}, + {0,8,4},{0,8,132},{0,8,68},{0,9,233},{128,7,8},{0,8,92}, + {0,8,28},{0,9,153},{132,7,83},{0,8,124},{0,8,60},{0,9,217}, + {130,7,23},{0,8,108},{0,8,44},{0,9,185},{0,8,12},{0,8,140}, + {0,8,76},{0,9,249},{128,7,3},{0,8,82},{0,8,18},{133,8,163}, + {131,7,35},{0,8,114},{0,8,50},{0,9,197},{129,7,11},{0,8,98}, + {0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {128,7,7},{0,8,90},{0,8,26},{0,9,149},{132,7,67},{0,8,122}, + {0,8,58},{0,9,213},{130,7,19},{0,8,106},{0,8,42},{0,9,181}, + {0,8,10},{0,8,138},{0,8,74},{0,9,245},{128,7,5},{0,8,86}, + {0,8,22},{65,8,0},{131,7,51},{0,8,118},{0,8,54},{0,9,205}, + {129,7,15},{0,8,102},{0,8,38},{0,9,173},{0,8,6},{0,8,134}, + {0,8,70},{0,9,237},{128,7,9},{0,8,94},{0,8,30},{0,9,157}, + {132,7,99},{0,8,126},{0,8,62},{0,9,221},{130,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253}, + {96,7,0},{0,8,81},{0,8,17},{133,8,131},{130,7,31},{0,8,113}, + {0,8,49},{0,9,195},{128,7,10},{0,8,97},{0,8,33},{0,9,163}, + {0,8,1},{0,8,129},{0,8,65},{0,9,227},{128,7,6},{0,8,89}, + {0,8,25},{0,9,147},{131,7,59},{0,8,121},{0,8,57},{0,9,211}, + {129,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},{0,8,137}, + {0,8,73},{0,9,243},{128,7,4},{0,8,85},{0,8,21},{144,8,3}, + {131,7,43},{0,8,117},{0,8,53},{0,9,203},{129,7,13},{0,8,101}, + {0,8,37},{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235}, + {128,7,8},{0,8,93},{0,8,29},{0,9,155},{132,7,83},{0,8,125}, + {0,8,61},{0,9,219},{130,7,23},{0,8,109},{0,8,45},{0,9,187}, + {0,8,13},{0,8,141},{0,8,77},{0,9,251},{128,7,3},{0,8,83}, + {0,8,19},{133,8,195},{131,7,35},{0,8,115},{0,8,51},{0,9,199}, + {129,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{128,7,7},{0,8,91},{0,8,27},{0,9,151}, + {132,7,67},{0,8,123},{0,8,59},{0,9,215},{130,7,19},{0,8,107}, + {0,8,43},{0,9,183},{0,8,11},{0,8,139},{0,8,75},{0,9,247}, + {128,7,5},{0,8,87},{0,8,23},{77,8,0},{131,7,51},{0,8,119}, + {0,8,55},{0,9,207},{129,7,15},{0,8,103},{0,8,39},{0,9,175}, + {0,8,7},{0,8,135},{0,8,71},{0,9,239},{128,7,9},{0,8,95}, + {0,8,31},{0,9,159},{132,7,99},{0,8,127},{0,8,63},{0,9,223}, + {130,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143}, + {0,8,79},{0,9,255} + }; + + static const code distfix[32] = { + {128,5,1},{135,5,257},{131,5,17},{139,5,4097},{129,5,5}, + {137,5,1025},{133,5,65},{141,5,16385},{128,5,3},{136,5,513}, + {132,5,33},{140,5,8193},{130,5,9},{138,5,2049},{134,5,129}, + {142,5,32769},{128,5,2},{135,5,385},{131,5,25},{139,5,6145}, + {129,5,7},{137,5,1537},{133,5,97},{141,5,24577},{128,5,4}, + {136,5,769},{132,5,49},{140,5,12289},{130,5,13},{138,5,3073}, + {134,5,193},{142,5,49153} + }; diff --git a/zlib/contrib/infback9/inflate9.h b/zlib/contrib/infback9/inflate9.h new file mode 100644 index 0000000..893a46f --- /dev/null +++ b/zlib/contrib/infback9/inflate9.h @@ -0,0 +1,47 @@ +/* inflate9.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Possible inflate modes between inflate() calls */ +typedef enum { + TYPE, /* i: waiting for type bits, including last-flag bit */ + STORED, /* i: waiting for stored size (length and complement) */ + TABLE, /* i: waiting for dynamic block table lengths */ + LEN, /* i: waiting for length/lit code */ + DONE, /* finished check, done -- remain here until reset */ + BAD /* got a data error -- remain here until reset */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD mode -- not shown for clarity) + + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or DONE + STORED -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LEN or TYPE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + /* sliding window */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/zlib/contrib/infback9/inftree9.c b/zlib/contrib/infback9/inftree9.c new file mode 100644 index 0000000..8fd417d --- /dev/null +++ b/zlib/contrib/infback9/inftree9.c @@ -0,0 +1,323 @@ +/* inftree9.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftree9.h" + +#define MAXBITS 15 + +const char inflate9_copyright[] = + " inflate9 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table9(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, + 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 3, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, + 133, 133, 133, 133, 144, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..31 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, + 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153}; + static const unsigned short dext[32] = { /* Distance codes 0..31 extra */ + 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, + 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, + 139, 139, 140, 140, 141, 141, 142, 142}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/zlib/contrib/infback9/inftree9.h b/zlib/contrib/infback9/inftree9.h new file mode 100644 index 0000000..0789c94 --- /dev/null +++ b/zlib/contrib/infback9/inftree9.h @@ -0,0 +1,55 @@ +/* inftree9.h -- header to use inftree9.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 100eeeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table9 OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/zlib/contrib/inflate86/inffas86.c b/zlib/contrib/inflate86/inffas86.c new file mode 100644 index 0000000..903b539 --- /dev/null +++ b/zlib/contrib/inflate86/inffas86.c @@ -0,0 +1,783 @@ +/* inffas86.c is a hand tuned assembler version of + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + struct inffast_ar { + void *esp; /* esp save */ + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned status; /* this is set when state changes */ + } ar; + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - 5); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - 257); + ar.wsize = state->wsize; + ar.write = state->write; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 2 byte boundary */ + if (((unsigned long)(void *)ar.in & 0x1) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + +#if defined( __GNUC__ ) || defined( __ICC ) + __asm__ __volatile__ ( +" leal %0, %%eax\n" +" pushf\n" +" pushl %%ebp\n" +" movl %%esp, (%%eax)\n" +" movl %%eax, %%esp\n" +" movl 4(%%esp), %%esi\n" /* esi = in */ +" movl 12(%%esp), %%edi\n" /* edi = out */ +" movl 36(%%esp), %%edx\n" /* edx = hold */ +" movl 40(%%esp), %%ebx\n" /* ebx = bits */ +" movl 44(%%esp), %%ebp\n" /* ebp = lcode */ + +" cld\n" +" jmp .L_do_loop\n" + +".L_while_test:\n" +" cmpl %%edi, 20(%%esp)\n" +" jbe .L_break_loop\n" +" cmpl %%esi, 8(%%esp)\n" +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" cmpb $15, %%bl\n" +" ja .L_get_length_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_length_code:\n" +" movl 52(%%esp), %%eax\n" /* eax = lmask */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".L_test_for_length_base:\n" +" movl %%eax, %%ecx\n" /* len = this */ +" shrl $16, %%ecx\n" /* len = this.val */ +" movl %%ecx, 60(%%esp)\n" /* len = this */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_len\n" /* if (op <= bits) */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_len:\n" +" movl $1, %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" subb %%cl, %%bl\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, 60(%%esp)\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" cmpb $15, %%bl\n" +" ja .L_get_distance_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_distance_code:\n" +" movl 56(%%esp), %%eax\n" /* eax = dmask */ +" movl 48(%%esp), %%ecx\n" /* ecx = dcode */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%ebp\n" /* dist = this */ +" shrl $16, %%ebp\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_dist:\n" +" movl $1, %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" subb %%cl, %%bl\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movl %%esi, 4(%%esp)\n" /* save in so from can use it's reg */ +" movl %%edi, %%eax\n" +" subl 16(%%esp), %%eax\n" /* nbytes = out - beg */ + +" cmpl %%ebp, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl 60(%%esp), %%ecx\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ + +" subl $3, %%ecx\n" /* copy from to out */ +" movb (%%esi), %%al\n" +" movb %%al, (%%edi)\n" +" movb 1(%%esi), %%al\n" +" movb 2(%%esi), %%ah\n" +" addl $3, %%esi\n" +" movb %%al, 1(%%edi)\n" +" movb %%ah, 2(%%edi)\n" +" addl $3, %%edi\n" +" rep movsb\n" + +" movl 4(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 44(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_check_dist_one:\n" +" cmpl $1, %%ebp\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpl %%edi, 16(%%esp)\n" +" je .L_check_window\n" + +" decl %%edi\n" +" movl 60(%%esp), %%ecx\n" +" movb (%%edi), %%al\n" +" subl $3, %%ecx\n" + +" movb %%al, 1(%%edi)\n" /* memset out with from[-1] */ +" movb %%al, 2(%%edi)\n" +" movb %%al, 3(%%edi)\n" +" addl $4, %%edi\n" +" rep stosb\n" +" movl 44(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" movl $1, %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl 60(%%esp), %%eax\n" /* eax += this.val */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" movl $1, %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%ebp, %%eax\n" /* eax += this.val */ +" movl 48(%%esp), %%ecx\n" /* ecx = dcode */ +" movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".L_clip_window:\n" +" movl %%eax, %%ecx\n" +" movl 24(%%esp), %%eax\n" /* prepare for dist compare */ +" negl %%ecx\n" /* nbytes = -nbytes */ +" movl 32(%%esp), %%esi\n" /* from = window */ + +" cmpl %%ebp, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 28(%%esp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" subl %%ecx, %%eax\n" +" addl %%eax, %%esi\n" /* from += wsize - nbytes */ + +" movl 60(%%esp), %%eax\n" +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy1\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy1\n" + +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy1\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy1\n" + +".L_wrap_around_window:\n" +" movl 28(%%esp), %%eax\n" +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" addl 24(%%esp), %%esi\n" +" addl %%eax, %%esi\n" +" subl %%ecx, %%esi\n" /* from += wsize + write - nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl 60(%%esp), %%eax\n" +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy1\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl 32(%%esp), %%esi\n" /* from = window */ +" movl 28(%%esp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy1\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy1\n" + +".L_contiguous_in_window:\n" +" addl %%eax, %%esi\n" +" subl %%ecx, %%esi\n" /* from += write - nbytes */ + +" movl 60(%%esp), %%eax\n" +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy1\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ + +".L_do_copy1:\n" +" movl %%eax, %%ecx\n" +" rep movsb\n" + +" movl 4(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 44(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 68(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 68(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 68(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl 4(%%esp), %%esi\n" +" movl $4, 68(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 68(%%esp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movl %%esi, 4(%%esp)\n" +" movl %%edi, 12(%%esp)\n" +" movl %%ebx, 40(%%esp)\n" +" movl %%edx, 36(%%esp)\n" +" movl (%%esp), %%esp\n" +" popl %%ebp\n" +" popf\n" + : + : "m" (ar) + : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" + ); +#elif defined( _MSC_VER ) + __asm { + lea eax, ar + pushfd + push ebp + mov [eax], esp + mov esp, eax + mov esi, [esp+4] /* esi = in */ + mov edi, [esp+12] /* edi = out */ + mov edx, [esp+36] /* edx = hold */ + mov ebx, [esp+40] /* ebx = bits */ + mov ebp, [esp+44] /* ebp = lcode */ + + cld + jmp L_do_loop + +L_while_test: + cmp [esp+20], edi + jbe L_break_loop + cmp [esp+8], esi + jbe L_break_loop + +L_do_loop: + cmp bl, 15 + ja L_get_length_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_length_code: + mov eax, [esp+52] /* eax = lmask */ + and eax, edx /* eax &= hold */ + mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah /* cl = this.bits */ + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base /* if (op != 0) 45.7% */ + + shr eax, 16 /* output this.val char */ + stosb + jmp L_while_test + +L_test_for_length_base: + mov ecx, eax /* len = this */ + shr ecx, 16 /* len = this.val */ + mov [esp+60], ecx /* len = this */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + and cl, 15 /* op &= 15 */ + jz L_decode_distance /* if (!op) */ + cmp bl, cl + jae L_add_bits_to_len /* if (op <= bits) */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_len: + mov eax, 1 + shl eax, cl + dec eax + sub bl, cl + and eax, edx /* eax &= hold */ + shr edx, cl + add [esp+60], eax /* len += hold & mask[op] */ + +L_decode_distance: + cmp bl, 15 + ja L_get_distance_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_distance_code: + mov eax, [esp+56] /* eax = dmask */ + mov ecx, [esp+48] /* ecx = dcode */ + and eax, edx /* eax &= hold */ + mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */ + +L_dodist: + mov ebp, eax /* dist = this */ + shr ebp, 16 /* dist = this.val */ + mov cl, ah + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + mov cl, al /* cl = this.op */ + + test al, 16 /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 /* op &= 15 */ + jz L_check_dist_one + cmp bl, cl + jae L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_dist: + mov eax, 1 + shl eax, cl + dec eax /* (1 << op) - 1 */ + sub bl, cl + and eax, edx /* eax &= hold */ + shr edx, cl + add ebp, eax /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov [esp+4], esi /* save in so from can use it's reg */ + mov eax, edi + sub eax, [esp+16] /* nbytes = out - beg */ + + cmp eax, ebp + jb L_clip_window /* if (dist > nbytes) 4.2% */ + + mov ecx, [esp+60] + mov esi, edi + sub esi, ebp /* from = out - dist */ + + sub ecx, 3 /* copy from to out */ + mov al, [esi] + mov [edi], al + mov al, [esi+1] + mov ah, [esi+2] + add esi, 3 + mov [edi+1], al + mov [edi+2], ah + add edi, 3 + rep movsb + + mov esi, [esp+4] /* move in back to %esi, toss from */ + mov ebp, [esp+44] /* ebp = lcode */ + jmp L_while_test + +L_check_dist_one: + cmp ebp, 1 /* if dist 1, is a memset */ + jne L_check_window + cmp [esp+16], edi + je L_check_window + + dec edi + mov ecx, [esp+60] + mov al, [edi] + sub ecx, 3 + + mov [edi+1], al /* memset out with from[-1] */ + mov [edi+2], al + mov [edi+3], al + add edi, 4 + rep stosb + mov ebp, [esp+44] /* ebp = lcode */ + jmp L_while_test + +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block /* if ((op & 64) != 0) */ + + mov eax, 1 + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, [esp+60] /* eax += this.val */ + mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code /* if ((op & 64) != 0) */ + + mov eax, 1 + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, ebp /* eax += this.val */ + mov ecx, [esp+48] /* ecx = dcode */ + mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +L_clip_window: + mov ecx, eax + mov eax, [esp+24] /* prepare for dist compare */ + neg ecx /* nbytes = -nbytes */ + mov esi, [esp+32] /* from = window */ + + cmp eax, ebp + jb L_invalid_distance_too_far /* if (dist > wsize) */ + + add ecx, ebp /* nbytes = dist - nbytes */ + cmp dword ptr [esp+28], 0 + jne L_wrap_around_window /* if (write != 0) */ + + sub eax, ecx + add esi, eax /* from += wsize - nbytes */ + + mov eax, [esp+60] + cmp eax, ecx + jbe L_do_copy1 /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy1 + + cmp eax, ecx + jbe L_do_copy1 /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy1 + +L_wrap_around_window: + mov eax, [esp+28] + cmp ecx, eax + jbe L_contiguous_in_window /* if (write >= nbytes) */ + + add esi, [esp+24] + add esi, eax + sub esi, ecx /* from += wsize + write - nbytes */ + sub ecx, eax /* nbytes -= write */ + + mov eax, [esp+60] + cmp eax, ecx + jbe L_do_copy1 /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, [esp+32] /* from = window */ + mov ecx, [esp+28] /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy1 /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy1 + +L_contiguous_in_window: + add esi, eax + sub esi, ecx /* from += write - nbytes */ + + mov eax, [esp+60] + cmp eax, ecx + jbe L_do_copy1 /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + +L_do_copy1: + mov ecx, eax + rep movsb + + mov esi, [esp+4] /* move in back to %esi, toss from */ + mov ebp, [esp+44] /* ebp = lcode */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [esp+68], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [esp+68], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [esp+68], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov esi, [esp+4] + mov dword ptr [esp+68], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [esp+68], 0 + +L_break_loop_with_status: +/* put in, out, bits, and hold back into ar and pop esp */ + mov [esp+4], esi + mov [esp+12], edi + mov [esp+40], ebx + mov [esp+36], edx + mov esp, [esp] + pop ebp + popfd + } +#endif + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? 5 + (ar.last - ar.in) : + 5 - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? 257 + (ar.end - ar.out) : + 257 - (ar.out - ar.end)); + state->hold = ar.hold; + state->bits = ar.bits; + return; +} + diff --git a/zlib/contrib/inflate86/inffast.S b/zlib/contrib/inflate86/inffast.S new file mode 100644 index 0000000..efcba03 --- /dev/null +++ b/zlib/contrib/inflate86/inffast.S @@ -0,0 +1,1377 @@ +/* + * inffast.S is a hand tuned assembler version of: + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * This version (Jan-23-2003) of inflate_fast was coded and tested under + * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that + * machine, I found that gzip style archives decompressed about 20% faster than + * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will + * depend on how large of a buffer is used for z_stream.next_in & next_out + * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in + * stream processing I/O and crc32/addler32. In my case, this routine used + * 70% of the cpu time and crc32 used 20%. + * + * I am confident that this version will work in the general case, but I have + * not tested a wide variety of datasets or a wide variety of platforms. + * + * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating. + * It should be a runtime flag instead of compile time flag... + * + * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction. + * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code + * is compiled. Without either option, runtime detection is enabled. Runtime + * detection should work on all modern cpus and the recomended algorithm (flip + * ID bit on eflags and then use the cpuid instruction) is used in many + * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12 + * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o + * inffast.obj generates a COFF object which can then be linked with MSVC++ + * compiled code. Tested under FreeBSD 4.7 with gcc-2.95. + * + * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and + * slower than compiler generated code). Adjusted cpuid check to use the MMX + * code only for Pentiums < P4 until I have more data on the P4. Speed + * improvment is only about 15% on the Athlon when compared with code generated + * with MSVC++. Not sure yet, but I think the P4 will also be slower using the + * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and + * have less latency than MMX ops. Added code to buffer the last 11 bytes of + * the input stream since the MMX code grabs bits in chunks of 32, which + * differs from the inffast.c algorithm. I don't think there would have been + * read overruns where a page boundary was crossed (a segfault), but there + * could have been overruns when next_in ends on unaligned memory (unintialized + * memory read). + * + * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C + * version of the non-MMX code so that it doesn't depend on zstrm and zstate + * structure offsets which are hard coded in this file. This was last tested + * with zlib-1.2.0 which is currently in beta testing, newer versions of this + * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and + * http://www.charm.net/~christop/zlib/ + */ + + +/* + * if you have underscore linking problems (_inflate_fast undefined), try + * using -DGAS_COFF + */ +#if ! defined( GAS_COFF ) && ! defined( GAS_ELF ) + +#if defined( WIN32 ) || defined( __CYGWIN__ ) +#define GAS_COFF /* windows object format */ +#else +#define GAS_ELF +#endif + +#endif /* ! GAS_COFF && ! GAS_ELF */ + + +#if defined( GAS_COFF ) + +/* coff externals have underscores */ +#define inflate_fast _inflate_fast +#define inflate_fast_use_mmx _inflate_fast_use_mmx + +#endif /* GAS_COFF */ + + +.file "inffast.S" + +.globl inflate_fast + +.text +.align 4,0 +.L_invalid_literal_length_code_msg: +.string "invalid literal/length code" + +.align 4,0 +.L_invalid_distance_code_msg: +.string "invalid distance code" + +.align 4,0 +.L_invalid_distance_too_far_msg: +.string "invalid distance too far back" + +#if ! defined( NO_MMX ) +.align 4,0 +.L_mask: /* mask[N] = ( 1 << N ) - 1 */ +.long 0 +.long 1 +.long 3 +.long 7 +.long 15 +.long 31 +.long 63 +.long 127 +.long 255 +.long 511 +.long 1023 +.long 2047 +.long 4095 +.long 8191 +.long 16383 +.long 32767 +.long 65535 +.long 131071 +.long 262143 +.long 524287 +.long 1048575 +.long 2097151 +.long 4194303 +.long 8388607 +.long 16777215 +.long 33554431 +.long 67108863 +.long 134217727 +.long 268435455 +.long 536870911 +.long 1073741823 +.long 2147483647 +.long 4294967295 +#endif /* NO_MMX */ + +.text + +/* + * struct z_stream offsets, in zlib.h + */ +#define next_in_strm 0 /* strm->next_in */ +#define avail_in_strm 4 /* strm->avail_in */ +#define next_out_strm 12 /* strm->next_out */ +#define avail_out_strm 16 /* strm->avail_out */ +#define msg_strm 24 /* strm->msg */ +#define state_strm 28 /* strm->state */ + +/* + * struct inflate_state offsets, in inflate.h + */ +#define mode_state 0 /* state->mode */ +#define wsize_state 32 /* state->wsize */ +#define write_state 40 /* state->write */ +#define window_state 44 /* state->window */ +#define hold_state 48 /* state->hold */ +#define bits_state 52 /* state->bits */ +#define lencode_state 68 /* state->lencode */ +#define distcode_state 72 /* state->distcode */ +#define lenbits_state 76 /* state->lenbits */ +#define distbits_state 80 /* state->distbits */ + +/* + * inflate_fast's activation record + */ +#define local_var_size 64 /* how much local space for vars */ +#define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */ +#define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */ + +/* + * offsets for local vars on stack + */ +#define out 60 /* unsigned char* */ +#define window 56 /* unsigned char* */ +#define wsize 52 /* unsigned int */ +#define write 48 /* unsigned int */ +#define in 44 /* unsigned char* */ +#define beg 40 /* unsigned char* */ +#define buf 28 /* char[ 12 ] */ +#define len 24 /* unsigned int */ +#define last 20 /* unsigned char* */ +#define end 16 /* unsigned char* */ +#define dcode 12 /* code* */ +#define lcode 8 /* code* */ +#define dmask 4 /* unsigned int */ +#define lmask 0 /* unsigned int */ + +/* + * typedef enum inflate_mode consts, in inflate.h + */ +#ifndef NO_GUNZIP +#define GUNZIP +#endif + +#ifdef GUNZIP +#define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */ +#define INFLATE_MODE_BAD 26 +#else +#define INFLATE_MODE_TYPE 3 +#define INFLATE_MODE_BAD 17 +#endif + + +#if ! defined( USE_MMX ) && ! defined( NO_MMX ) + +#define RUN_TIME_MMX + +#define CHECK_MMX 1 +#define DO_USE_MMX 2 +#define DONT_USE_MMX 3 + +.globl inflate_fast_use_mmx + +.data + +.align 4,0 +inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */ +.long CHECK_MMX + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast_use_mmx,@object +.size inflate_fast_use_mmx,4 +#endif + +#endif /* RUN_TIME_MMX */ + +#if defined( GAS_COFF ) +/* coff info: scl 2 = extern, type 32 = function */ +.def inflate_fast; .scl 2; .type 32; .endef +#endif + +.text + +.align 32,0x90 +inflate_fast: + pushl %edi + pushl %esi + pushl %ebp + pushl %ebx + pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */ + subl $local_var_size, %esp + cld + +#define strm_r %esi +#define state_r %edi + + movl strm_sp(%esp), strm_r + movl state_strm(strm_r), state_r + + /* in = strm->next_in; + * out = strm->next_out; + * last = in + strm->avail_in - 11; + * beg = out - (start - strm->avail_out); + * end = out + (strm->avail_out - 257); + */ + movl avail_in_strm(strm_r), %edx + movl next_in_strm(strm_r), %eax + + addl %eax, %edx /* avail_in += next_in */ + subl $11, %edx /* avail_in -= 11 */ + + movl %eax, in(%esp) + movl %edx, last(%esp) + + movl start_sp(%esp), %ebp + movl avail_out_strm(strm_r), %ecx + movl next_out_strm(strm_r), %ebx + + subl %ecx, %ebp /* start -= avail_out */ + negl %ebp /* start = -start */ + addl %ebx, %ebp /* start += next_out */ + + subl $257, %ecx /* avail_out -= 257 */ + addl %ebx, %ecx /* avail_out += out */ + + movl %ebx, out(%esp) + movl %ebp, beg(%esp) + movl %ecx, end(%esp) + + /* wsize = state->wsize; + * write = state->write; + * window = state->window; + * hold = state->hold; + * bits = state->bits; + * lcode = state->lencode; + * dcode = state->distcode; + * lmask = ( 1 << state->lenbits ) - 1; + * dmask = ( 1 << state->distbits ) - 1; + */ + + movl lencode_state(state_r), %eax + movl distcode_state(state_r), %ecx + + movl %eax, lcode(%esp) + movl %ecx, dcode(%esp) + + movl $1, %eax + movl lenbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, lmask(%esp) + + movl $1, %eax + movl distbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, dmask(%esp) + + movl wsize_state(state_r), %eax + movl write_state(state_r), %ecx + movl window_state(state_r), %edx + + movl %eax, wsize(%esp) + movl %ecx, write(%esp) + movl %edx, window(%esp) + + movl hold_state(state_r), %ebp + movl bits_state(state_r), %ebx + +#undef strm_r +#undef state_r + +#define in_r %esi +#define from_r %esi +#define out_r %edi + + movl in(%esp), in_r + movl last(%esp), %ecx + cmpl in_r, %ecx + ja .L_align_long /* if in < last */ + + addl $11, %ecx /* ecx = &in[ avail_in ] */ + subl in_r, %ecx /* ecx = avail_in */ + movl $12, %eax + subl %ecx, %eax /* eax = 12 - avail_in */ + leal buf(%esp), %edi + rep movsb /* memcpy( buf, in, avail_in ) */ + movl %eax, %ecx + xorl %eax, %eax + rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */ + leal buf(%esp), in_r /* in = buf */ + movl in_r, last(%esp) /* last = in, do just one iteration */ + jmp .L_is_aligned + + /* align in_r on long boundary */ +.L_align_long: + testl $3, in_r + jz .L_is_aligned + xorl %eax, %eax + movb (in_r), %al + incl in_r + movl %ebx, %ecx + addl $8, %ebx + shll %cl, %eax + orl %eax, %ebp + jmp .L_align_long + +.L_is_aligned: + movl out(%esp), out_r + +#if defined( NO_MMX ) + jmp .L_do_loop +#endif + +#if defined( USE_MMX ) + jmp .L_init_mmx +#endif + +/*** Runtime MMX check ***/ + +#if defined( RUN_TIME_MMX ) +.L_check_mmx: + cmpl $DO_USE_MMX, inflate_fast_use_mmx + je .L_init_mmx + ja .L_do_loop /* > 2 */ + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushf + movl (%esp), %eax /* copy eflags to eax */ + xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21) + * to see if cpu supports cpuid... + * ID bit method not supported by NexGen but + * bios may load a cpuid instruction and + * cpuid may be disabled on Cyrix 5-6x86 */ + popf + pushf + popl %edx /* copy new eflags to edx */ + xorl %eax, %edx /* test if ID bit is flipped */ + jz .L_dont_use_mmx /* not flipped if zero */ + xorl %eax, %eax + cpuid + cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */ + jne .L_dont_use_mmx + cmpl $0x6c65746e, %ecx + jne .L_dont_use_mmx + cmpl $0x49656e69, %edx + jne .L_dont_use_mmx + movl $1, %eax + cpuid /* get cpu features */ + shrl $8, %eax + andl $15, %eax + cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */ + jne .L_dont_use_mmx + testl $0x800000, %edx /* test if MMX feature is set (bit 23) */ + jnz .L_use_mmx + jmp .L_dont_use_mmx +.L_use_mmx: + movl $DO_USE_MMX, inflate_fast_use_mmx + jmp .L_check_mmx_pop +.L_dont_use_mmx: + movl $DONT_USE_MMX, inflate_fast_use_mmx +.L_check_mmx_pop: + popl %edx + popl %ecx + popl %ebx + popl %eax + jmp .L_check_mmx +#endif + + +/*** Non-MMX code ***/ + +#if defined ( NO_MMX ) || defined( RUN_TIME_MMX ) + +#define hold_r %ebp +#define bits_r %bl +#define bitslong_r %ebx + +.align 32,0x90 +.L_while_test: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * do { + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = lcode[hold & lmask] + */ + cmpb $15, bits_r + ja .L_get_length_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_length_code: + movl lmask(%esp), %edx /* edx = lmask */ + movl lcode(%esp), %ecx /* ecx = lcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * dolen: + * bits -= this.bits; + * hold >>= this.bits + */ + movb %ah, %cl /* cl = this.bits */ + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* check if op is a literal + * if (op == 0) { + * PUP(out) = this.val; + * } + */ + testb %al, %al + jnz .L_test_for_length_base /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test + +.L_test_for_length_base: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len + * + * else if (op & 16) { + * len = this.val + * op &= 15 + * if (op) { + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * len += hold & mask[op]; + * bits -= op; + * hold >>= op; + * } + */ +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + movb %al, %cl + + testb $16, %al + jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + andb $15, %cl /* op &= 15 */ + jz .L_save_len /* if (!op) */ + cmpb %cl, bits_r + jae .L_add_bits_to_len /* if (op <= bits) */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_len: + movl $1, %eax + shll %cl, %eax + decl %eax + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, len_r /* len += hold & mask[op] */ + +.L_save_len: + movl len_r, len(%esp) /* save len */ +#undef len_r + +.L_decode_distance: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = dcode[hold & dmask]; + * dodist: + * bits -= this.bits; + * hold >>= this.bits; + * op = this.op; + */ + + cmpb $15, bits_r + ja .L_get_distance_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_distance_code: + movl dmask(%esp), %edx /* edx = dmask */ + movl dcode(%esp), %ecx /* ecx = dcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */ + +#define dist_r %edx +.L_dodist: + movl %eax, dist_r /* dist = this */ + shrl $16, dist_r /* dist = this.val */ + movb %ah, %cl + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* if (op & 16) { + * dist = this.val + * op &= 15 + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * dist += hold & mask[op]; + * bits -= op; + * hold >>= op; + */ + movb %al, %cl /* cl = this.op */ + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist + andb $15, %cl /* op &= 15 */ + jz .L_check_dist_one + cmpb %cl, bits_r + jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_dist: + movl $1, %eax + shll %cl, %eax + decl %eax /* (1 << op) - 1 */ + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */ + jmp .L_check_window + +.L_check_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * nbytes = out - beg; + * if (dist <= nbytes) { + * from = out - dist; + * do { + * PUP(out) = PUP(from); + * } while (--len > 0) { + * } + */ + + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window /* if (dist > nbytes) 4.2% */ + + movl len(%esp), %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +.align 16,0x90 +.L_check_dist_one: + cmpl $1, dist_r + jne .L_check_window + cmpl out_r, beg(%esp) + je .L_check_window + + decl out_r + movl len(%esp), %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + jmp .L_while_test + +.align 16,0x90 +.L_test_for_second_level_length: + /* else if ((op & 64) == 0) { + * this = lcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl lcode(%esp), %edx /* edx = lcode */ + movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */ + jmp .L_dolen + +.align 16,0x90 +.L_test_for_second_level_dist: + /* else if ((op & 64) == 0) { + * this = dcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl dcode(%esp), %edx /* edx = dcode */ + movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */ + jmp .L_dodist + +.align 16,0x90 +.L_clip_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * else { + * if (dist > wsize) { + * invalid distance + * } + * from = window; + * nbytes = dist - nbytes; + * if (write == 0) { + * from += wsize - nbytes; + */ +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = len + * + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define len_r %eax + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_wrap_around_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else if (write < nbytes) { + * from += wsize + write - nbytes; + * nbytes -= write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = window; + * nbytes = write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while(--nbytes); + * from = out - dist; + * } + * } + * } + */ +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_contiguous_in_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else { + * from += write - nbytes; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1: + /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out + * %eax = len + * + * while (len > 0) { + * PUP(out) = PUP(from); + * len--; + * } + * } + * } while (in < last && out < end); + */ +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +#undef len_r +#undef dist_r + +#endif /* NO_MMX || RUN_TIME_MMX */ + + +/*** MMX code ***/ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +.align 32,0x90 +.L_init_mmx: + emms + +#undef bits_r +#undef bitslong_r +#define bitslong_r %ebp +#define hold_mm %mm0 + movd %ebp, hold_mm + movl %ebx, bitslong_r + +#define used_mm %mm1 +#define dmask2_mm %mm2 +#define lmask2_mm %mm3 +#define lmask_mm %mm4 +#define dmask_mm %mm5 +#define tmp_mm %mm6 + + movd lmask(%esp), lmask_mm + movq lmask_mm, lmask2_mm + movd dmask(%esp), dmask_mm + movq dmask_mm, dmask2_mm + pxor used_mm, used_mm + movl lcode(%esp), %ebx /* ebx = lcode */ + jmp .L_do_loop_mmx + +.align 32,0x90 +.L_while_test_mmx: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_length_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_length_code_mmx: + pand hold_mm, lmask_mm + movd lmask_mm, %eax + movq lmask2_mm, lmask_mm + movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen_mmx: + movzbl %ah, %ecx /* ecx = this.bits */ + movd %ecx, used_mm + subl %ecx, bitslong_r /* bits -= this.bits */ + + testb %al, %al + jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test_mmx + +.L_test_for_length_base_mmx: +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + + testb $16, %al + jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */ + andl $15, %eax /* op &= 15 */ + jz .L_decode_distance_mmx /* if (!op) */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm + movd hold_mm, %ecx + subl %eax, bitslong_r + andl .L_mask(,%eax,4), %ecx + addl %ecx, len_r /* len += hold & mask[op] */ + +.L_decode_distance_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_dist_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_dist_code_mmx: + movl dcode(%esp), %ebx /* ebx = dcode */ + pand hold_mm, dmask_mm + movd dmask_mm, %eax + movq dmask2_mm, dmask_mm + movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */ + +.L_dodist_mmx: +#define dist_r %ebx + movzbl %ah, %ecx /* ecx = this.bits */ + movl %eax, dist_r + shrl $16, dist_r /* dist = this.val */ + subl %ecx, bitslong_r /* bits -= this.bits */ + movd %ecx, used_mm + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist_mmx + andl $15, %eax /* op &= 15 */ + jz .L_check_dist_one_mmx + +.L_add_bits_to_dist_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm /* save bit length of current op */ + movd hold_mm, %ecx /* get the next bits on input stream */ + subl %eax, bitslong_r /* bits -= op bits */ + andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */ + addl %ecx, dist_r /* dist += hold & mask[op] */ + +.L_check_window_mmx: + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */ + + movl len_r, %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_check_dist_one_mmx: + cmpl $1, dist_r + jne .L_check_window_mmx + cmpl out_r, beg(%esp) + je .L_check_window_mmx + + decl out_r + movl len_r, %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_test_for_second_level_length_mmx: + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + addl len_r, %ecx + movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dolen_mmx + +.align 16,0x90 +.L_test_for_second_level_dist_mmx: + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + movl dcode(%esp), %eax /* ecx = dcode */ + addl dist_r, %ecx + movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dodist_mmx + +.align 16,0x90 +.L_clip_window_mmx: +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window_mmx /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_wrap_around_window_mmx: +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_contiguous_in_window_mmx: +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1_mmx: +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +#undef hold_r +#undef bitslong_r + +#endif /* USE_MMX || RUN_TIME_MMX */ + + +/*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/ + +.L_invalid_distance_code: + /* else { + * strm->msg = "invalid distance code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_distance_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_test_for_end_of_block: + /* else if (op & 32) { + * state->mode = TYPE; + * break; + * } + */ + testb $32, %al + jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */ + + movl $0, %ecx + movl $INFLATE_MODE_TYPE, %edx + jmp .L_update_stream_state + +.L_invalid_literal_length_code: + /* else { + * strm->msg = "invalid literal/length code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_literal_length_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_invalid_distance_too_far: + /* strm->msg = "invalid distance too far back"; + * state->mode = BAD; + */ + movl in(%esp), in_r /* from_r has in's reg, put in back */ + movl $.L_invalid_distance_too_far_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_update_stream_state: + /* set strm->msg = %ecx, strm->state->mode = %edx */ + movl strm_sp(%esp), %eax + testl %ecx, %ecx /* if (msg != NULL) */ + jz .L_skip_msg + movl %ecx, msg_strm(%eax) /* strm->msg = msg */ +.L_skip_msg: + movl state_strm(%eax), %eax /* state = strm->state */ + movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */ + jmp .L_break_loop + +.align 32,0x90 +.L_break_loop: + +/* + * Regs: + * + * bits = %ebp when mmx, and in %ebx when non-mmx + * hold = %hold_mm when mmx, and in %ebp when non-mmx + * in = %esi + * out = %edi + */ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_next_in + +#endif /* RUN_TIME_MMX */ + + movl %ebp, %ebx + +.L_update_next_in: + +#endif + +#define strm_r %eax +#define state_r %edx + + /* len = bits >> 3; + * in -= len; + * bits -= len << 3; + * hold &= (1U << bits) - 1; + * state->hold = hold; + * state->bits = bits; + * strm->next_in = in; + * strm->next_out = out; + */ + movl strm_sp(%esp), strm_r + movl %ebx, %ecx + movl state_strm(strm_r), state_r + shrl $3, %ecx + subl %ecx, in_r + shll $3, %ecx + subl %ecx, %ebx + movl out_r, next_out_strm(strm_r) + movl %ebx, bits_state(state_r) + movl %ebx, %ecx + + leal buf(%esp), %ebx + cmpl %ebx, last(%esp) + jne .L_buf_not_used /* if buf != last */ + + subl %ebx, in_r /* in -= buf */ + movl next_in_strm(strm_r), %ebx + movl %ebx, last(%esp) /* last = strm->next_in */ + addl %ebx, in_r /* in += strm->next_in */ + movl avail_in_strm(strm_r), %ebx + subl $11, %ebx + addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */ + +.L_buf_not_used: + movl in_r, next_in_strm(strm_r) + + movl $1, %ebx + shll %cl, %ebx + decl %ebx + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_hold + +#endif /* RUN_TIME_MMX */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ebp + + emms + +.L_update_hold: + +#endif /* USE_MMX || RUN_TIME_MMX */ + + andl %ebx, %ebp + movl %ebp, hold_state(state_r) + +#define last_r %ebx + + /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */ + movl last(%esp), last_r + cmpl in_r, last_r + jbe .L_last_is_smaller /* if (in >= last) */ + + subl in_r, last_r /* last -= in */ + addl $11, last_r /* last += 11 */ + movl last_r, avail_in_strm(strm_r) + jmp .L_fixup_out +.L_last_is_smaller: + subl last_r, in_r /* in -= last */ + negl in_r /* in = -in */ + addl $11, in_r /* in += 11 */ + movl in_r, avail_in_strm(strm_r) + +#undef last_r +#define end_r %ebx + +.L_fixup_out: + /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/ + movl end(%esp), end_r + cmpl out_r, end_r + jbe .L_end_is_smaller /* if (out >= end) */ + + subl out_r, end_r /* end -= out */ + addl $257, end_r /* end += 257 */ + movl end_r, avail_out_strm(strm_r) + jmp .L_done +.L_end_is_smaller: + subl end_r, out_r /* out -= end */ + negl out_r /* out = -out */ + addl $257, out_r /* out += 257 */ + movl out_r, avail_out_strm(strm_r) + +#undef end_r +#undef strm_r +#undef state_r + +.L_done: + addl $local_var_size, %esp + popf + popl %ebx + popl %ebp + popl %esi + popl %edi + ret + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast,@function +.size inflate_fast,.-inflate_fast +#endif diff --git a/zlib/contrib/iostream/test.cpp b/zlib/contrib/iostream/test.cpp new file mode 100644 index 0000000..063e3bf --- /dev/null +++ b/zlib/contrib/iostream/test.cpp @@ -0,0 +1,24 @@ + +#include "zfstream.h" + +int main() { + + // Construct a stream object with this filebuffer. Anything sent + // to this stream will go to standard out. + gzofstream os( 1, ios::out ); + + // This text is getting compressed and sent to stdout. + // To prove this, run 'test | zcat'. + os << "Hello, Mommy" << endl; + + os << setcompressionlevel( Z_NO_COMPRESSION ); + os << "hello, hello, hi, ho!" << endl; + + setcompressionlevel( os, Z_DEFAULT_COMPRESSION ) + << "I'm compressing again" << endl; + + os.close(); + + return 0; + +} diff --git a/zlib/contrib/iostream/zfstream.cpp b/zlib/contrib/iostream/zfstream.cpp new file mode 100644 index 0000000..100e68f --- /dev/null +++ b/zlib/contrib/iostream/zfstream.cpp @@ -0,0 +1,329 @@ + +#include "zfstream.h" + +gzfilebuf::gzfilebuf() : + file(NULL), + mode(0), + own_file_descriptor(0) +{ } + +gzfilebuf::~gzfilebuf() { + + sync(); + if ( own_file_descriptor ) + close(); + +} + +gzfilebuf *gzfilebuf::open( const char *name, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzopen(name, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 1; + + return this; + +} + +gzfilebuf *gzfilebuf::attach( int file_descriptor, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzdopen(file_descriptor, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 0; + + return this; + +} + +gzfilebuf *gzfilebuf::close() { + + if ( is_open() ) { + + sync(); + gzclose( file ); + file = NULL; + + } + + return this; + +} + +int gzfilebuf::setcompressionlevel( int comp_level ) { + + return gzsetparams(file, comp_level, -2); + +} + +int gzfilebuf::setcompressionstrategy( int comp_strategy ) { + + return gzsetparams(file, -2, comp_strategy); + +} + + +streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) { + + return streampos(EOF); + +} + +int gzfilebuf::underflow() { + + // If the file hasn't been opened for reading, error. + if ( !is_open() || !(mode & ios::in) ) + return EOF; + + // if a buffer doesn't exists, allocate one. + if ( !base() ) { + + if ( (allocate()) == EOF ) + return EOF; + setp(0,0); + + } else { + + if ( in_avail() ) + return (unsigned char) *gptr(); + + if ( out_waiting() ) { + if ( flushbuf() == EOF ) + return EOF; + } + + } + + // Attempt to fill the buffer. + + int result = fillbuf(); + if ( result == EOF ) { + // disable get area + setg(0,0,0); + return EOF; + } + + return (unsigned char) *gptr(); + +} + +int gzfilebuf::overflow( int c ) { + + if ( !is_open() || !(mode & ios::out) ) + return EOF; + + if ( !base() ) { + if ( allocate() == EOF ) + return EOF; + setg(0,0,0); + } else { + if (in_avail()) { + return EOF; + } + if (out_waiting()) { + if (flushbuf() == EOF) + return EOF; + } + } + + int bl = blen(); + setp( base(), base() + bl); + + if ( c != EOF ) { + + *pptr() = c; + pbump(1); + + } + + return 0; + +} + +int gzfilebuf::sync() { + + if ( !is_open() ) + return EOF; + + if ( out_waiting() ) + return flushbuf(); + + return 0; + +} + +int gzfilebuf::flushbuf() { + + int n; + char *q; + + q = pbase(); + n = pptr() - q; + + if ( gzwrite( file, q, n) < n ) + return EOF; + + setp(0,0); + + return 0; + +} + +int gzfilebuf::fillbuf() { + + int required; + char *p; + + p = base(); + + required = blen(); + + int t = gzread( file, p, required ); + + if ( t <= 0) return EOF; + + setg( base(), base(), base()+t); + + return t; + +} + +gzfilestream_common::gzfilestream_common() : + ios( gzfilestream_common::rdbuf() ) +{ } + +gzfilestream_common::~gzfilestream_common() +{ } + +void gzfilestream_common::attach( int fd, int io_mode ) { + + if ( !buffer.attach( fd, io_mode) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::open( const char *name, int io_mode ) { + + if ( !buffer.open( name, io_mode ) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::close() { + + if ( !buffer.close() ) + clear( ios::failbit | ios::badbit ); + +} + +gzfilebuf *gzfilestream_common::rdbuf() +{ + return &buffer; +} + +gzifstream::gzifstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzifstream::gzifstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzifstream::gzifstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzifstream::~gzifstream() { } + +gzofstream::gzofstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzofstream::gzofstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzofstream::gzofstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzofstream::~gzofstream() { } diff --git a/zlib/contrib/iostream/zfstream.h b/zlib/contrib/iostream/zfstream.h new file mode 100644 index 0000000..96d7f6a --- /dev/null +++ b/zlib/contrib/iostream/zfstream.h @@ -0,0 +1,128 @@ + +#ifndef zfstream_h +#define zfstream_h + +#include +#include "zlib.h" + +class gzfilebuf : public streambuf { + +public: + + gzfilebuf( ); + virtual ~gzfilebuf(); + + gzfilebuf *open( const char *name, int io_mode ); + gzfilebuf *attach( int file_descriptor, int io_mode ); + gzfilebuf *close(); + + int setcompressionlevel( int comp_level ); + int setcompressionstrategy( int comp_strategy ); + + inline int is_open() const { return (file !=NULL); } + + virtual streampos seekoff( streamoff, ios::seek_dir, int ); + + virtual int sync(); + +protected: + + virtual int underflow(); + virtual int overflow( int = EOF ); + +private: + + gzFile file; + short mode; + short own_file_descriptor; + + int flushbuf(); + int fillbuf(); + +}; + +class gzfilestream_common : virtual public ios { + + friend class gzifstream; + friend class gzofstream; + friend gzofstream &setcompressionlevel( gzofstream &, int ); + friend gzofstream &setcompressionstrategy( gzofstream &, int ); + +public: + virtual ~gzfilestream_common(); + + void attach( int fd, int io_mode ); + void open( const char *name, int io_mode ); + void close(); + +protected: + gzfilestream_common(); + +private: + gzfilebuf *rdbuf(); + + gzfilebuf buffer; + +}; + +class gzifstream : public gzfilestream_common, public istream { + +public: + + gzifstream(); + gzifstream( const char *name, int io_mode = ios::in ); + gzifstream( int fd, int io_mode = ios::in ); + + virtual ~gzifstream(); + +}; + +class gzofstream : public gzfilestream_common, public ostream { + +public: + + gzofstream(); + gzofstream( const char *name, int io_mode = ios::out ); + gzofstream( int fd, int io_mode = ios::out ); + + virtual ~gzofstream(); + +}; + +template class gzomanip { + friend gzofstream &operator<<(gzofstream &, const gzomanip &); +public: + gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { } +private: + gzofstream &(*func)(gzofstream &, T); + T val; +}; + +template gzofstream &operator<<(gzofstream &s, const gzomanip &m) +{ + return (*m.func)(s, m.val); +} + +inline gzofstream &setcompressionlevel( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionlevel(l); + return s; +} + +inline gzofstream &setcompressionstrategy( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionstrategy(l); + return s; +} + +inline gzomanip setcompressionlevel(int l) +{ + return gzomanip(&setcompressionlevel,l); +} + +inline gzomanip setcompressionstrategy(int l) +{ + return gzomanip(&setcompressionstrategy,l); +} + +#endif diff --git a/zlib/contrib/iostream2/zstream.h b/zlib/contrib/iostream2/zstream.h new file mode 100644 index 0000000..522371c --- /dev/null +++ b/zlib/contrib/iostream2/zstream.h @@ -0,0 +1,307 @@ +/* + * + * Copyright (c) 1997 + * Christian Michelsen Research AS + * Advanced Computing + * Fantoftvegen 38, 5036 BERGEN, Norway + * http://www.cmr.no + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Christian Michelsen Research AS makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef ZSTREAM__H +#define ZSTREAM__H + +/* + * zstream.h - C++ interface to the 'zlib' general purpose compression library + * $Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge $ + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(_WIN32) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +class zstringlen { +public: + zstringlen(class izstream&); + zstringlen(class ozstream&, const char*); + size_t value() const { return val.word; } +private: + struct Val { unsigned char byte; size_t word; } val; +}; + +// ----------------------------- izstream ----------------------------- + +class izstream +{ + public: + izstream() : m_fp(0) {} + izstream(FILE* fp) : m_fp(0) { open(fp); } + izstream(const char* name) : m_fp(0) { open(name); } + ~izstream() { close(); } + + /* Opens a gzip (.gz) file for reading. + * open() can be used to read a file which is not in gzip format; + * in this case read() will directly read from the file without + * decompression. errno can be checked to distinguish two error + * cases (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name) { + if (m_fp) close(); + m_fp = ::gzopen(name, "rb"); + } + + void open(FILE* fp) { + SET_BINARY_MODE(fp); + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), "rb"); + } + + /* Flushes all pending input if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + int r = ::gzclose(m_fp); + m_fp = 0; return r; + } + + /* Binary read the given number of bytes from the compressed file. + */ + int read(void* buf, size_t len) { + return ::gzread(m_fp, buf, len); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + private: + gzFile m_fp; +}; + +/* + * Binary read the given (array of) object(s) from the compressed file. + * If the input file was not in gzip format, read() copies the objects number + * of bytes into the buffer. + * returns the number of uncompressed bytes actually read + * (0 for end of file, -1 for error). + */ +template +inline int read(izstream& zs, T* x, Items items) { + return ::gzread(zs.fp(), x, items*sizeof(T)); +} + +/* + * Binary input with the '>' operator. + */ +template +inline izstream& operator>(izstream& zs, T& x) { + ::gzread(zs.fp(), &x, sizeof(T)); + return zs; +} + + +inline zstringlen::zstringlen(izstream& zs) { + zs > val.byte; + if (val.byte == 255) zs > val.word; + else val.word = val.byte; +} + +/* + * Read length of string + the string with the '>' operator. + */ +inline izstream& operator>(izstream& zs, char* x) { + zstringlen len(zs); + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return zs; +} + +inline char* read_string(izstream& zs) { + zstringlen len(zs); + char* x = new char[len.value()+1]; + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return x; +} + +// ----------------------------- ozstream ----------------------------- + +class ozstream +{ + public: + ozstream() : m_fp(0), m_os(0) { + } + ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(fp, level); + } + ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(name, level); + } + ~ozstream() { + close(); + } + + /* Opens a gzip (.gz) file for writing. + * The compression level parameter should be in 0..9 + * errno can be checked to distinguish two error cases + * (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name, int level = Z_DEFAULT_COMPRESSION) { + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzopen(name, mode); + } + + /* open from a FILE pointer. + */ + void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) { + SET_BINARY_MODE(fp); + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), mode); + } + + /* Flushes all pending output if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + if (m_os) { + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = 0; + } + int r = ::gzclose(m_fp); m_fp = 0; return r; + } + + /* Binary write the given number of bytes into the compressed file. + */ + int write(const void* buf, size_t len) { + return ::gzwrite(m_fp, (voidp) buf, len); + } + + /* Flushes all pending output into the compressed file. The parameter + * _flush is as in the deflate() function. The return value is the zlib + * error number (see function gzerror below). flush() returns Z_OK if + * the flush_ parameter is Z_FINISH and all output could be flushed. + * flush() should be called only when strictly necessary because it can + * degrade compression. + */ + int flush(int _flush) { + os_flush(); + return ::gzflush(m_fp, _flush); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + ostream& os() { + if (m_os == 0) m_os = new ostrstream; + return *m_os; + } + + void os_flush() { + if (m_os && m_os->pcount()>0) { + ostrstream* oss = new ostrstream; + oss->fill(m_os->fill()); + oss->flags(m_os->flags()); + oss->precision(m_os->precision()); + oss->width(m_os->width()); + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = oss; + } + } + + private: + gzFile m_fp; + ostrstream* m_os; +}; + +/* + * Binary write the given (array of) object(s) into the compressed file. + * returns the number of uncompressed bytes actually written + * (0 in case of error). + */ +template +inline int write(ozstream& zs, const T* x, Items items) { + return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T)); +} + +/* + * Binary output with the '<' operator. + */ +template +inline ozstream& operator<(ozstream& zs, const T& x) { + ::gzwrite(zs.fp(), (voidp) &x, sizeof(T)); + return zs; +} + +inline zstringlen::zstringlen(ozstream& zs, const char* x) { + val.byte = 255; val.word = ::strlen(x); + if (val.word < 255) zs < (val.byte = val.word); + else zs < val; +} + +/* + * Write length of string + the string with the '<' operator. + */ +inline ozstream& operator<(ozstream& zs, const char* x) { + zstringlen len(zs, x); + ::gzwrite(zs.fp(), (voidp) x, len.value()); + return zs; +} + +#ifdef _MSC_VER +inline ozstream& operator<(ozstream& zs, char* const& x) { + return zs < (const char*) x; +} +#endif + +/* + * Ascii write with the << operator; + */ +template +inline ostream& operator<<(ozstream& zs, const T& x) { + zs.os_flush(); + return zs.os() << x; +} + +#endif diff --git a/zlib/contrib/iostream2/zstream_test.cpp b/zlib/contrib/iostream2/zstream_test.cpp new file mode 100644 index 0000000..8f4d970 --- /dev/null +++ b/zlib/contrib/iostream2/zstream_test.cpp @@ -0,0 +1,25 @@ +#include "zstream.h" +#include +#include +#include + +void main() { + char h[256] = "Hello"; + char* g = "Goodbye"; + ozstream out("temp.gz"); + out < "This works well" < h < g; + out.close(); + + izstream in("temp.gz"); // read it back + char *x = read_string(in), *y = new char[256], z[256]; + in > y > z; + in.close(); + cout << x << endl << y << endl << z << endl; + + out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results + out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl; + out << z << endl << y << endl << x << endl; + out << 1.1234567890123456789 << endl; + + delete[] x; delete[] y; +} diff --git a/zlib/contrib/iostream3/README b/zlib/contrib/iostream3/README new file mode 100644 index 0000000..1d18c96 --- /dev/null +++ b/zlib/contrib/iostream3/README @@ -0,0 +1,35 @@ +These classes provide a C++ stream interface to the zlib library. It allows you +to do things like: + + gzofstream outf("blah.gz"); + outf << "These go into the gzip file " << 123 << endl; + +It does this by deriving a specialized stream buffer for gzipped files, which is +the way Stroustrup would have done it. :-> + +The gzifstream and gzofstream classes were originally written by Kevin Ruland +and made available in the zlib contrib/iostream directory. The older version still +compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of +this version. + +The new classes are as standard-compliant as possible, closely following the +approach of the standard library's fstream classes. It compiles under gcc versions +3.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard +library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs +from the previous one in the following respects: +- added showmanyc +- added setbuf, with support for unbuffered output via setbuf(0,0) +- a few bug fixes of stream behavior +- gzipped output file opened with default compression level instead of maximum level +- setcompressionlevel()/strategy() members replaced by single setcompression() + +The code is provided "as is", with the permission to use, copy, modify, distribute +and sell it for any purpose without fee. + +Ludwig Schwardt + + +DSP Lab +Electrical & Electronic Engineering Department +University of Stellenbosch +South Africa diff --git a/zlib/contrib/iostream3/TODO b/zlib/contrib/iostream3/TODO new file mode 100644 index 0000000..f2eb1a2 --- /dev/null +++ b/zlib/contrib/iostream3/TODO @@ -0,0 +1,17 @@ +Possible upgrades to gzfilebuf: + +- The ability to do putback (e.g. putbackfail) + +- The ability to seek (zlib supports this, but could be slow/tricky) + +- Simultaneous read/write access (does it make sense?) + +- Support for ios_base::ate open mode + +- Locale support? + +- Check public interface to see which calls give problems + (due to dependence on library internals) + +- Override operator<<(ostream&, gzfilebuf*) to allow direct copying + of stream buffer to stream ( i.e. os << is.rdbuf(); ) diff --git a/zlib/contrib/iostream3/test.cc b/zlib/contrib/iostream3/test.cc new file mode 100644 index 0000000..a9acc21 --- /dev/null +++ b/zlib/contrib/iostream3/test.cc @@ -0,0 +1,50 @@ +/* + * Test program for gzifstream and gzofstream + * + * by Ludwig Schwardt + * original version by Kevin Ruland + */ + +#include "zfstream.h" +#include // for cout + +int main() { + + gzofstream outf; + gzifstream inf; + char buf[80]; + + outf.open("test1.txt.gz"); + outf << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n" + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + + std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n"; + inf.open("test1.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + outf.rdbuf()->pubsetbuf(0,0); + outf.open("test2.txt.gz"); + outf << setcompression(Z_NO_COMPRESSION) + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form"; + + std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n"; + inf.rdbuf()->pubsetbuf(0,0); + inf.open("test2.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + return 0; + +} diff --git a/zlib/contrib/iostream3/zfstream.cc b/zlib/contrib/iostream3/zfstream.cc new file mode 100644 index 0000000..62ed8ec --- /dev/null +++ b/zlib/contrib/iostream3/zfstream.cc @@ -0,0 +1,479 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#include "zfstream.h" +#include // for strcpy, strcat, strlen (mode strings) +#include // for BUFSIZ + +// Internal buffer sizes (default and "unbuffered" versions) +#define BIGBUFSIZE BUFSIZ +#define SMALLBUFSIZE 1 + +/*****************************************************************************/ + +// Default constructor +gzfilebuf::gzfilebuf() +: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false), + buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true) +{ + // No buffers to start with + this->disable_buffer(); +} + +// Destructor +gzfilebuf::~gzfilebuf() +{ + // Sync output buffer and close only if responsible for file + // (i.e. attached streams should be left open at this stage) + this->sync(); + if (own_fd) + this->close(); + // Make sure internal buffer is deallocated + this->disable_buffer(); +} + +// Set compression level and strategy +int +gzfilebuf::setcompression(int comp_level, + int comp_strategy) +{ + return gzsetparams(file, comp_level, comp_strategy); +} + +// Open gzipped file +gzfilebuf* +gzfilebuf::open(const char *name, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to open file + if ((file = gzopen(name, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = true; + return this; +} + +// Attach to gzipped file +gzfilebuf* +gzfilebuf::attach(int fd, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzdopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to attach to file + if ((file = gzdopen(fd, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = false; + return this; +} + +// Close gzipped file +gzfilebuf* +gzfilebuf::close() +{ + // Fail immediately if no file is open + if (!this->is_open()) + return NULL; + // Assume success + gzfilebuf* retval = this; + // Attempt to sync and close gzipped file + if (this->sync() == -1) + retval = NULL; + if (gzclose(file) < 0) + retval = NULL; + // File is now gone anyway (postcondition [27.8.1.3.8]) + file = NULL; + own_fd = false; + // Destroy internal buffer if it exists + this->disable_buffer(); + return retval; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Convert int open mode to mode string +bool +gzfilebuf::open_mode(std::ios_base::openmode mode, + char* c_mode) const +{ + bool testb = mode & std::ios_base::binary; + bool testi = mode & std::ios_base::in; + bool testo = mode & std::ios_base::out; + bool testt = mode & std::ios_base::trunc; + bool testa = mode & std::ios_base::app; + + // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) + // Original zfstream hardcoded the compression level to maximum here... + // Double the time for less than 1% size improvement seems + // excessive though - keeping it at the default level + // To change back, just append "9" to the next three mode strings + if (!testi && testo && !testt && !testa) + strcpy(c_mode, "w"); + if (!testi && testo && !testt && testa) + strcpy(c_mode, "a"); + if (!testi && testo && testt && !testa) + strcpy(c_mode, "w"); + if (testi && !testo && !testt && !testa) + strcpy(c_mode, "r"); + // No read/write mode yet +// if (testi && testo && !testt && !testa) +// strcpy(c_mode, "r+"); +// if (testi && testo && testt && !testa) +// strcpy(c_mode, "w+"); + + // Mode string should be empty for invalid combination of flags + if (strlen(c_mode) == 0) + return false; + if (testb) + strcat(c_mode, "b"); + return true; +} + +// Determine number of characters in internal get buffer +std::streamsize +gzfilebuf::showmanyc() +{ + // Calls to underflow will fail if file not opened for reading + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return -1; + // Make sure get area is in use + if (this->gptr() && (this->gptr() < this->egptr())) + return std::streamsize(this->egptr() - this->gptr()); + else + return 0; +} + +// Fill get area from gzipped file +gzfilebuf::int_type +gzfilebuf::underflow() +{ + // If something is left in the get area by chance, return it + // (this shouldn't normally happen, as underflow is only supposed + // to be called when gptr >= egptr, but it serves as error check) + if (this->gptr() && (this->gptr() < this->egptr())) + return traits_type::to_int_type(*(this->gptr())); + + // If the file hasn't been opened for reading, produce error + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return traits_type::eof(); + + // Attempt to fill internal buffer from gzipped file + // (buffer must be guaranteed to exist...) + int bytes_read = gzread(file, buffer, buffer_size); + // Indicates error or EOF + if (bytes_read <= 0) + { + // Reset get area + this->setg(buffer, buffer, buffer); + return traits_type::eof(); + } + // Make all bytes read from file available as get area + this->setg(buffer, buffer, buffer + bytes_read); + + // Return next character in get area + return traits_type::to_int_type(*(this->gptr())); +} + +// Write put area to gzipped file +gzfilebuf::int_type +gzfilebuf::overflow(int_type c) +{ + // Determine whether put area is in use + if (this->pbase()) + { + // Double-check pointer range + if (this->pptr() > this->epptr() || this->pptr() < this->pbase()) + return traits_type::eof(); + // Add extra character to buffer if not EOF + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + *(this->pptr()) = traits_type::to_char_type(c); + this->pbump(1); + } + // Number of characters to write to file + int bytes_to_write = this->pptr() - this->pbase(); + // Overflow doesn't fail if nothing is to be written + if (bytes_to_write > 0) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // If gzipped file won't accept all bytes written to it, fail + if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write) + return traits_type::eof(); + // Reset next pointer to point to pbase on success + this->pbump(-bytes_to_write); + } + } + // Write extra character to file if not EOF + else if (!traits_type::eq_int_type(c, traits_type::eof())) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // Impromptu char buffer (allows "unbuffered" output) + char_type last_char = traits_type::to_char_type(c); + // If gzipped file won't accept this character, fail + if (gzwrite(file, &last_char, 1) != 1) + return traits_type::eof(); + } + + // If you got here, you have succeeded (even if c was EOF) + // The return value should therefore be non-EOF + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + else + return c; +} + +// Assign new buffer +std::streambuf* +gzfilebuf::setbuf(char_type* p, + std::streamsize n) +{ + // First make sure stuff is sync'ed, for safety + if (this->sync() == -1) + return NULL; + // If buffering is turned off on purpose via setbuf(0,0), still allocate one... + // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at + // least a buffer of size 1 (very inefficient though, therefore make it bigger?) + // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems) + if (!p || !n) + { + // Replace existing buffer (if any) with small internal buffer + this->disable_buffer(); + buffer = NULL; + buffer_size = 0; + own_buffer = true; + this->enable_buffer(); + } + else + { + // Replace existing buffer (if any) with external buffer + this->disable_buffer(); + buffer = p; + buffer_size = n; + own_buffer = false; + this->enable_buffer(); + } + return this; +} + +// Write put area to gzipped file (i.e. ensures that put area is empty) +int +gzfilebuf::sync() +{ + return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Allocate internal buffer +void +gzfilebuf::enable_buffer() +{ + // If internal buffer required, allocate one + if (own_buffer && !buffer) + { + // Check for buffered vs. "unbuffered" + if (buffer_size > 0) + { + // Allocate internal buffer + buffer = new char_type[buffer_size]; + // Get area starts empty and will be expanded by underflow as need arises + this->setg(buffer, buffer, buffer); + // Setup entire internal buffer as put area. + // The one-past-end pointer actually points to the last element of the buffer, + // so that overflow(c) can safely add the extra character c to the sequence. + // These pointers remain in place for the duration of the buffer + this->setp(buffer, buffer + buffer_size - 1); + } + else + { + // Even in "unbuffered" case, (small?) get buffer is still required + buffer_size = SMALLBUFSIZE; + buffer = new char_type[buffer_size]; + this->setg(buffer, buffer, buffer); + // "Unbuffered" means no put buffer + this->setp(0, 0); + } + } + else + { + // If buffer already allocated, reset buffer pointers just to make sure no + // stale chars are lying around + this->setg(buffer, buffer, buffer); + this->setp(buffer, buffer + buffer_size - 1); + } +} + +// Destroy internal buffer +void +gzfilebuf::disable_buffer() +{ + // If internal buffer exists, deallocate it + if (own_buffer && buffer) + { + // Preserve unbuffered status by zeroing size + if (!this->pbase()) + buffer_size = 0; + delete[] buffer; + buffer = NULL; + this->setg(0, 0, 0); + this->setp(0, 0); + } + else + { + // Reset buffer pointers to initial state if external buffer exists + this->setg(buffer, buffer, buffer); + if (buffer) + this->setp(buffer, buffer + buffer_size - 1); + else + this->setp(0, 0); + } +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzifstream::gzifstream() +: std::istream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzifstream::gzifstream(const char* name, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzifstream::gzifstream(int fd, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzifstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzifstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzifstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzofstream::gzofstream() +: std::ostream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzofstream::gzofstream(const char* name, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzofstream::gzofstream(int fd, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzofstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzofstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzofstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} diff --git a/zlib/contrib/iostream3/zfstream.h b/zlib/contrib/iostream3/zfstream.h new file mode 100644 index 0000000..9db884a --- /dev/null +++ b/zlib/contrib/iostream3/zfstream.h @@ -0,0 +1,466 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#ifndef ZFSTREAM_H +#define ZFSTREAM_H + +#include // not iostream, since we don't need cin/cout +#include +#include "zlib.h" + +/*****************************************************************************/ + +/** + * @brief Gzipped file stream buffer class. + * + * This class implements basic_filebuf for gzipped files. It doesn't yet support + * seeking (allowed by zlib but slow/limited), putback and read/write access + * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard + * file streambuf. +*/ +class gzfilebuf : public std::streambuf +{ +public: + // Default constructor. + gzfilebuf(); + + // Destructor. + virtual + ~gzfilebuf(); + + /** + * @brief Set compression level and strategy on the fly. + * @param comp_level Compression level (see zlib.h for allowed values) + * @param comp_strategy Compression strategy (see zlib.h for allowed values) + * @return Z_OK on success, Z_STREAM_ERROR otherwise. + * + * Unfortunately, these parameters cannot be modified separately, as the + * previous zfstream version assumed. Since the strategy is seldom changed, + * it can default and setcompression(level) then becomes like the old + * setcompressionlevel(level). + */ + int + setcompression(int comp_level, + int comp_strategy = Z_DEFAULT_STRATEGY); + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() const { return (file != NULL); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + open(const char* name, + std::ios_base::openmode mode); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + attach(int fd, + std::ios_base::openmode mode); + + /** + * @brief Close gzipped file. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + close(); + +protected: + /** + * @brief Convert ios open mode int to mode string used by zlib. + * @return True if valid mode flag combination. + */ + bool + open_mode(std::ios_base::openmode mode, + char* c_mode) const; + + /** + * @brief Number of characters available in stream buffer. + * @return Number of characters. + * + * This indicates number of characters in get area of stream buffer. + * These characters can be read without accessing the gzipped file. + */ + virtual std::streamsize + showmanyc(); + + /** + * @brief Fill get area from gzipped file. + * @return First character in get area on success, EOF on error. + * + * This actually reads characters from gzipped file to stream + * buffer. Always buffered. + */ + virtual int_type + underflow(); + + /** + * @brief Write put area to gzipped file. + * @param c Extra character to add to buffer contents. + * @return Non-EOF on success, EOF on error. + * + * This actually writes characters in stream buffer to + * gzipped file. With unbuffered output this is done one + * character at a time. + */ + virtual int_type + overflow(int_type c = traits_type::eof()); + + /** + * @brief Installs external stream buffer. + * @param p Pointer to char buffer. + * @param n Size of external buffer. + * @return @c this on success, NULL on failure. + * + * Call setbuf(0,0) to enable unbuffered output. + */ + virtual std::streambuf* + setbuf(char_type* p, + std::streamsize n); + + /** + * @brief Flush stream buffer to file. + * @return 0 on success, -1 on error. + * + * This calls underflow(EOF) to do the job. + */ + virtual int + sync(); + +// +// Some future enhancements +// +// virtual int_type uflow(); +// virtual int_type pbackfail(int_type c = traits_type::eof()); +// virtual pos_type +// seekoff(off_type off, +// std::ios_base::seekdir way, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); +// virtual pos_type +// seekpos(pos_type sp, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); + +private: + /** + * @brief Allocate internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that a proper internal buffer exists if it is required. If the + * buffer already exists or is external, the buffer pointers will be + * reset to their original state. + */ + void + enable_buffer(); + + /** + * @brief Destroy internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that the internal buffer is deallocated if it exists. In any + * case, it will also reset the buffer pointers. + */ + void + disable_buffer(); + + /** + * Underlying file pointer. + */ + gzFile file; + + /** + * Mode in which file was opened. + */ + std::ios_base::openmode io_mode; + + /** + * @brief True if this object owns file descriptor. + * + * This makes the class responsible for closing the file + * upon destruction. + */ + bool own_fd; + + /** + * @brief Stream buffer. + * + * For simplicity this remains allocated on the free store for the + * entire life span of the gzfilebuf object, unless replaced by setbuf. + */ + char_type* buffer; + + /** + * @brief Stream buffer size. + * + * Defaults to system default buffer size (typically 8192 bytes). + * Modified by setbuf. + */ + std::streamsize buffer_size; + + /** + * @brief True if this object owns stream buffer. + * + * This makes the class responsible for deleting the buffer + * upon destruction. + */ + bool own_buffer; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file input stream class. + * + * This class implements ifstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzifstream : public std::istream +{ +public: + // Default constructor + gzifstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ifstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream class. + * + * This class implements ofstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzofstream : public std::ostream +{ +public: + // Default constructor + gzofstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ofstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream manipulator class. + * + * This class defines a two-argument manipulator for gzofstream. It is used + * as base for the setcompression(int,int) manipulator. +*/ +template + class gzomanip2 + { + public: + // Allows insertor to peek at internals + template + friend gzofstream& + operator<<(gzofstream&, + const gzomanip2&); + + // Constructor + gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2), + T1 v1, + T2 v2); + private: + // Underlying manipulator function + gzofstream& + (*func)(gzofstream&, T1, T2); + + // Arguments for manipulator function + T1 val1; + T2 val2; + }; + +/*****************************************************************************/ + +// Manipulator function thunks through to stream buffer +inline gzofstream& +setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) +{ + (gzs.rdbuf())->setcompression(l, s); + return gzs; +} + +// Manipulator constructor stores arguments +template + inline + gzomanip2::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), + T1 v1, + T2 v2) + : func(f), val1(v1), val2(v2) + { } + +// Insertor applies underlying manipulator function to stream +template + inline gzofstream& + operator<<(gzofstream& s, const gzomanip2& m) + { return (*m.func)(s, m.val1, m.val2); } + +// Insert this onto stream to simplify setting of compression level +inline gzomanip2 +setcompression(int l, int s = Z_DEFAULT_STRATEGY) +{ return gzomanip2(&setcompression, l, s); } + +#endif // ZFSTREAM_H diff --git a/zlib/contrib/masm686/match.asm b/zlib/contrib/masm686/match.asm new file mode 100644 index 0000000..e2d2ec0 --- /dev/null +++ b/zlib/contrib/masm686/match.asm @@ -0,0 +1,408 @@ + +; match.asm -- Pentium-Pro optimized version of longest_match() +; +; Updated for zlib 1.1.3 and converted to MASM 6.1x +; Copyright (C) 2000 Dan Higdon +; and Chuck Walbourn +; Corrections by Cosmin Truta +; +; This is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License. + +; Based on match.S +; Written for zlib 1.1.2 +; Copyright (C) 1998 Brian Raiter + + .686P + .MODEL FLAT + +;=========================================================================== +; EQUATES +;=========================================================================== + +MAX_MATCH EQU 258 +MIN_MATCH EQU 3 +MIN_LOOKAHEAD EQU (MAX_MATCH + MIN_MATCH + 1) +MAX_MATCH_8 EQU ((MAX_MATCH + 7) AND (NOT 7)) + +;=========================================================================== +; STRUCTURES +;=========================================================================== + +; This STRUCT assumes a 4-byte alignment + +DEFLATE_STATE STRUCT +ds_strm dd ? +ds_status dd ? +ds_pending_buf dd ? +ds_pending_buf_size dd ? +ds_pending_out dd ? +ds_pending dd ? +ds_wrap dd ? +ds_data_type db ? +ds_method db ? + db ? ; padding + db ? ; padding +ds_last_flush dd ? +ds_w_size dd ? ; used +ds_w_bits dd ? +ds_w_mask dd ? ; used +ds_window dd ? ; used +ds_window_size dd ? +ds_prev dd ? ; used +ds_head dd ? +ds_ins_h dd ? +ds_hash_size dd ? +ds_hash_bits dd ? +ds_hash_mask dd ? +ds_hash_shift dd ? +ds_block_start dd ? +ds_match_length dd ? ; used +ds_prev_match dd ? ; used +ds_match_available dd ? +ds_strstart dd ? ; used +ds_match_start dd ? ; used +ds_lookahead dd ? ; used +ds_prev_length dd ? ; used +ds_max_chain_length dd ? ; used +ds_max_laxy_match dd ? +ds_level dd ? +ds_strategy dd ? +ds_good_match dd ? ; used +ds_nice_match dd ? ; used + +; Don't need anymore of the struct for match +DEFLATE_STATE ENDS + +;=========================================================================== +; CODE +;=========================================================================== +_TEXT SEGMENT + +;--------------------------------------------------------------------------- +; match_init +;--------------------------------------------------------------------------- + ALIGN 4 +PUBLIC _match_init +_match_init PROC + ; no initialization needed + ret +_match_init ENDP + +;--------------------------------------------------------------------------- +; uInt longest_match(deflate_state *deflatestate, IPos curmatch) +;--------------------------------------------------------------------------- + ALIGN 4 + +PUBLIC _longest_match +_longest_match PROC + +; Since this code uses EBP for a scratch register, the stack frame must +; be manually constructed and referenced relative to the ESP register. + +; Stack image +; Variables +chainlenwmask = 0 ; high word: current chain len + ; low word: s->wmask +window = 4 ; local copy of s->window +windowbestlen = 8 ; s->window + bestlen +scanend = 12 ; last two bytes of string +scanstart = 16 ; first two bytes of string +scanalign = 20 ; dword-misalignment of string +nicematch = 24 ; a good enough match size +bestlen = 28 ; size of best match so far +scan = 32 ; ptr to string wanting match +varsize = 36 ; number of bytes (also offset to last saved register) + +; Saved Registers (actually pushed into place) +ebx_save = 36 +edi_save = 40 +esi_save = 44 +ebp_save = 48 + +; Parameters +retaddr = 52 +deflatestate = 56 +curmatch = 60 + +; Save registers that the compiler may be using + push ebp + push edi + push esi + push ebx + +; Allocate local variable space + sub esp,varsize + +; Retrieve the function arguments. ecx will hold cur_match +; throughout the entire function. edx will hold the pointer to the +; deflate_state structure during the function's setup (before +; entering the main loop). + + mov edx, [esp+deflatestate] +ASSUME edx:PTR DEFLATE_STATE + + mov ecx, [esp+curmatch] + +; uInt wmask = s->w_mask; +; unsigned chain_length = s->max_chain_length; +; if (s->prev_length >= s->good_match) { +; chain_length >>= 2; +; } + + mov eax, [edx].ds_prev_length + mov ebx, [edx].ds_good_match + cmp eax, ebx + mov eax, [edx].ds_w_mask + mov ebx, [edx].ds_max_chain_length + jl SHORT LastMatchGood + shr ebx, 2 +LastMatchGood: + +; chainlen is decremented once beforehand so that the function can +; use the sign flag instead of the zero flag for the exit test. +; It is then shifted into the high word, to make room for the wmask +; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + mov [esp+chainlenwmask], ebx + +; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + mov eax, [edx].ds_nice_match + mov ebx, [edx].ds_lookahead + cmp ebx, eax + jl SHORT LookaheadLess + mov ebx, eax +LookaheadLess: + mov [esp+nicematch], ebx + +;/* register Bytef *scan = s->window + s->strstart; */ + + mov esi, [edx].ds_window + mov [esp+window], esi + mov ebp, [edx].ds_strstart + lea edi, [esi+ebp] + mov [esp+scan],edi + +;/* Determine how many bytes the scan ptr is off from being */ +;/* dword-aligned. */ + + mov eax, edi + neg eax + and eax, 3 + mov [esp+scanalign], eax + +;/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +;/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + mov eax, [edx].ds_w_size + sub eax, MIN_LOOKAHEAD + sub ebp, eax + jg SHORT LimitPositive + xor ebp, ebp +LimitPositive: + +;/* int best_len = s->prev_length; */ + + mov eax, [edx].ds_prev_length + mov [esp+bestlen], eax + +;/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ + + add esi, eax + mov [esp+windowbestlen], esi + +;/* register ush scan_start = *(ushf*)scan; */ +;/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +;/* Posf *prev = s->prev; */ + + movzx ebx, WORD PTR[edi] + mov [esp+scanstart], ebx + movzx ebx, WORD PTR[eax+edi-1] + mov [esp+scanend], ebx + mov edi, [edx].ds_prev + +;/* Jump into the main loop. */ + + mov edx, [esp+chainlenwmask] + jmp SHORT LoopEntry + +;/* do { +; * match = s->window + cur_match; +; * if (*(ushf*)(match+best_len-1) != scan_end || +; * *(ushf*)match != scan_start) continue; +; * [...] +; * } while ((cur_match = prev[cur_match & wmask]) > limit +; * && --chain_length != 0); +; * +; * Here is the inner loop of the function. The function will spend the +; * majority of its time in this loop, and majority of that time will +; * be spent in the first ten instructions. +; * +; * Within this loop: +; * %ebx = scanend +; * %ecx = curmatch +; * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +; * %esi = windowbestlen - i.e., (window + bestlen) +; * %edi = prev +; * %ebp = limit +; */ + + ALIGN 4 +LookupLoop: + and ecx, edx + movzx ecx, WORD PTR[edi+ecx*2] + cmp ecx, ebp + jbe LeaveNow + sub edx, 000010000H + js LeaveNow + +LoopEntry: + movzx eax, WORD PTR[esi+ecx-1] + cmp eax, ebx + jnz SHORT LookupLoop + + mov eax, [esp+window] + movzx eax, WORD PTR[eax+ecx] + cmp eax, [esp+scanstart] + jnz SHORT LookupLoop + +;/* Store the current value of chainlen. */ + + mov [esp+chainlenwmask], edx + +;/* Point %edi to the string under scrutiny, and %esi to the string we */ +;/* are hoping to match it up with. In actuality, %esi and %edi are */ +;/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +;/* initialized to -(MAX_MATCH_8 - scanalign). */ + + mov esi, [esp+window] + mov edi, [esp+scan] + add esi, ecx + mov eax, [esp+scanalign] + mov edx, -MAX_MATCH_8 + lea edi, [edi+eax+MAX_MATCH_8] + lea esi, [esi+eax+MAX_MATCH_8] + +;/* Test the strings for equality, 8 bytes at a time. At the end, +; * adjust %edx so that it is offset to the exact byte that mismatched. +; * +; * We already know at this point that the first three bytes of the +; * strings match each other, and they can be safely passed over before +; * starting the compare loop. So what this code does is skip over 0-3 +; * bytes, as much as necessary in order to dword-align the %edi +; * pointer. (%esi will still be misaligned three times out of four.) +; * +; * It should be confessed that this loop usually does not represent +; * much of the total running time. Replacing it with a more +; * straightforward "rep cmpsb" would not drastically degrade +; * performance. +; */ + +LoopCmps: + mov eax, DWORD PTR[esi+edx] + xor eax, DWORD PTR[edi+edx] + jnz SHORT LeaveLoopCmps + + mov eax, DWORD PTR[esi+edx+4] + xor eax, DWORD PTR[edi+edx+4] + jnz SHORT LeaveLoopCmps4 + + add edx, 8 + jnz SHORT LoopCmps + jmp LenMaximum + ALIGN 4 + +LeaveLoopCmps4: + add edx, 4 + +LeaveLoopCmps: + test eax, 00000FFFFH + jnz SHORT LenLower + + add edx, 2 + shr eax, 16 + +LenLower: + sub al, 1 + adc edx, 0 + +;/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +;/* then automatically accept it as the best possible match and leave. */ + + lea eax, [edi+edx] + mov edi, [esp+scan] + sub eax, edi + cmp eax, MAX_MATCH + jge SHORT LenMaximum + +;/* If the length of the match is not longer than the best match we */ +;/* have so far, then forget it and return to the lookup loop. */ + + mov edx, [esp+deflatestate] + mov ebx, [esp+bestlen] + cmp eax, ebx + jg SHORT LongerMatch + mov esi, [esp+windowbestlen] + mov edi, [edx].ds_prev + mov ebx, [esp+scanend] + mov edx, [esp+chainlenwmask] + jmp LookupLoop + ALIGN 4 + +;/* s->match_start = cur_match; */ +;/* best_len = len; */ +;/* if (len >= nice_match) break; */ +;/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: + mov ebx, [esp+nicematch] + mov [esp+bestlen], eax + mov [edx].ds_match_start, ecx + cmp eax, ebx + jge SHORT LeaveNow + mov esi, [esp+window] + add esi, eax + mov [esp+windowbestlen], esi + movzx ebx, WORD PTR[edi+eax-1] + mov edi, [edx].ds_prev + mov [esp+scanend], ebx + mov edx, [esp+chainlenwmask] + jmp LookupLoop + ALIGN 4 + +;/* Accept the current string, with the maximum possible length. */ + +LenMaximum: + mov edx, [esp+deflatestate] + mov DWORD PTR[esp+bestlen], MAX_MATCH + mov [edx].ds_match_start, ecx + +;/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +;/* return s->lookahead; */ + +LeaveNow: + mov edx, [esp+deflatestate] + mov ebx, [esp+bestlen] + mov eax, [edx].ds_lookahead + cmp ebx, eax + jg SHORT LookaheadRet + mov eax, ebx +LookaheadRet: + +; Restore the stack and return from whence we came. + + add esp, varsize + pop ebx + pop esi + pop edi + pop ebp + ret + +_longest_match ENDP + +_TEXT ENDS +END diff --git a/zlib/contrib/masmx86/gvmat32.asm b/zlib/contrib/masmx86/gvmat32.asm new file mode 100644 index 0000000..aedf17d --- /dev/null +++ b/zlib/contrib/masmx86/gvmat32.asm @@ -0,0 +1,905 @@ +; +; gvmat32.asm -- Asm portion of the optimized longest_match for 32 bits x86 +; Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant. +; File written by Gilles Vollant, by modifiying the longest_match +; from Jean-loup Gailly in deflate.c +; It need wmask == 0x7fff +; (assembly code is faster with a fixed wmask) +; +; For Visual C++ 4.2 and ML 6.11c (version in directory \MASM611C of Win95 DDK) +; I compile with : "ml /coff /Zi /c gvmat32.asm" +; + +;uInt longest_match_7fff(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ + + NbStack equ 76 + cur_match equ dword ptr[esp+NbStack-0] + str_s equ dword ptr[esp+NbStack-4] +; 5 dword on top (ret,ebp,esi,edi,ebx) + adrret equ dword ptr[esp+NbStack-8] + pushebp equ dword ptr[esp+NbStack-12] + pushedi equ dword ptr[esp+NbStack-16] + pushesi equ dword ptr[esp+NbStack-20] + pushebx equ dword ptr[esp+NbStack-24] + + chain_length equ dword ptr [esp+NbStack-28] + limit equ dword ptr [esp+NbStack-32] + best_len equ dword ptr [esp+NbStack-36] + window equ dword ptr [esp+NbStack-40] + prev equ dword ptr [esp+NbStack-44] + scan_start equ word ptr [esp+NbStack-48] + wmask equ dword ptr [esp+NbStack-52] + match_start_ptr equ dword ptr [esp+NbStack-56] + nice_match equ dword ptr [esp+NbStack-60] + scan equ dword ptr [esp+NbStack-64] + + windowlen equ dword ptr [esp+NbStack-68] + match_start equ dword ptr [esp+NbStack-72] + strend equ dword ptr [esp+NbStack-76] + NbStackAdd equ (NbStack-24) + + .386p + + name gvmatch + .MODEL FLAT + + + +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure + dep_chain_length equ 70h+4 + dep_window equ 2ch+4 + dep_strstart equ 60h+4 + dep_prev_length equ 6ch+4 + dep_nice_match equ 84h+4 + dep_w_size equ 20h+4 + dep_prev equ 34h+4 + dep_w_mask equ 28h+4 + dep_good_match equ 80h+4 + dep_match_start equ 64h+4 + dep_lookahead equ 68h+4 + + +_TEXT segment + +IFDEF NOUNDERLINE + public longest_match_7fff + public longest_match_686 +; public match_init +ELSE + public _longest_match_7fff + public _longest_match_686 +; public _match_init +ENDIF + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + + +IFDEF NOUNDERLINE +;match_init proc near +; ret +;match_init endp +ELSE +;_match_init proc near +; ret +;_match_init endp +ENDIF + + +IFDEF NOUNDERLINE +longest_match_7fff proc near +ELSE +_longest_match_7fff proc near +ENDIF + + mov edx,[esp+4] + + + + push ebp + push edi + push esi + push ebx + + sub esp,NbStackAdd + +; initialize or check the variables used in match.asm. + mov ebp,edx + +; chain_length = s->max_chain_length +; if (prev_length>=good_match) chain_length >>= 2 + mov edx,[ebp+dep_chain_length] + mov ebx,[ebp+dep_prev_length] + cmp [ebp+dep_good_match],ebx + ja noshr + shr edx,2 +noshr: +; we increment chain_length because in the asm, the --chain_lenght is in the beginning of the loop + inc edx + mov edi,[ebp+dep_nice_match] + mov chain_length,edx + mov eax,[ebp+dep_lookahead] + cmp eax,edi +; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + jae nolookaheadnicematch + mov edi,eax +nolookaheadnicematch: +; best_len = s->prev_length + mov best_len,ebx + +; window = s->window + mov esi,[ebp+dep_window] + mov ecx,[ebp+dep_strstart] + mov window,esi + + mov nice_match,edi +; scan = window + strstart + add esi,ecx + mov scan,esi +; dx = *window + mov dx,word ptr [esi] +; bx = *(window+best_len-1) + mov bx,word ptr [esi+ebx-1] + add esi,MAX_MATCH-1 +; scan_start = *scan + mov scan_start,dx +; strend = scan + MAX_MATCH-1 + mov strend,esi +; bx = scan_end = *(window+best_len-1) + +; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +; s->strstart - (IPos)MAX_DIST(s) : NIL; + + mov esi,[ebp+dep_w_size] + sub esi,MIN_LOOKAHEAD +; here esi = MAX_DIST(s) + sub ecx,esi + ja nodist + xor ecx,ecx +nodist: + mov limit,ecx + +; prev = s->prev + mov edx,[ebp+dep_prev] + mov prev,edx + +; + mov edx,dword ptr [ebp+dep_match_start] + mov bp,scan_start + mov eax,cur_match + mov match_start,edx + + mov edx,window + mov edi,edx + add edi,best_len + mov esi,prev + dec edi +; windowlen = window + best_len -1 + mov windowlen,edi + + jmp beginloop2 + align 4 + +; here, in the loop +; eax = ax = cur_match +; ecx = limit +; bx = scan_end +; bp = scan_start +; edi = windowlen (window + best_len -1) +; esi = prev + + +;// here; chain_length <=16 +normalbeg0add16: + add chain_length,16 + jz exitloop +normalbeg0: + cmp word ptr[edi+eax],bx + je normalbeg2noroll +rcontlabnoroll: +; cur_match = prev[cur_match & wmask] + and eax,7fffh + mov ax,word ptr[esi+eax*2] +; if cur_match > limit, go to exitloop + cmp ecx,eax + jnb exitloop +; if --chain_length != 0, go to exitloop + dec chain_length + jnz normalbeg0 + jmp exitloop + +normalbeg2noroll: +; if (scan_start==*(cur_match+window)) goto normalbeg2 + cmp bp,word ptr[edx+eax] + jne rcontlabnoroll + jmp normalbeg2 + +contloop3: + mov edi,windowlen + +; cur_match = prev[cur_match & wmask] + and eax,7fffh + mov ax,word ptr[esi+eax*2] +; if cur_match > limit, go to exitloop + cmp ecx,eax +jnbexitloopshort1: + jnb exitloop +; if --chain_length != 0, go to exitloop + + +; begin the main loop +beginloop2: + sub chain_length,16+1 +; if chain_length <=16, don't use the unrolled loop + jna normalbeg0add16 + +do16: + cmp word ptr[edi+eax],bx + je normalbeg2dc0 + +maccn MACRO lab + and eax,7fffh + mov ax,word ptr[esi+eax*2] + cmp ecx,eax + jnb exitloop + cmp word ptr[edi+eax],bx + je lab + ENDM + +rcontloop0: + maccn normalbeg2dc1 + +rcontloop1: + maccn normalbeg2dc2 + +rcontloop2: + maccn normalbeg2dc3 + +rcontloop3: + maccn normalbeg2dc4 + +rcontloop4: + maccn normalbeg2dc5 + +rcontloop5: + maccn normalbeg2dc6 + +rcontloop6: + maccn normalbeg2dc7 + +rcontloop7: + maccn normalbeg2dc8 + +rcontloop8: + maccn normalbeg2dc9 + +rcontloop9: + maccn normalbeg2dc10 + +rcontloop10: + maccn short normalbeg2dc11 + +rcontloop11: + maccn short normalbeg2dc12 + +rcontloop12: + maccn short normalbeg2dc13 + +rcontloop13: + maccn short normalbeg2dc14 + +rcontloop14: + maccn short normalbeg2dc15 + +rcontloop15: + and eax,7fffh + mov ax,word ptr[esi+eax*2] + cmp ecx,eax + jnb exitloop + + sub chain_length,16 + ja do16 + jmp normalbeg0add16 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +normbeg MACRO rcontlab,valsub +; if we are here, we know that *(match+best_len-1) == scan_end + cmp bp,word ptr[edx+eax] +; if (match != scan_start) goto rcontlab + jne rcontlab +; calculate the good chain_length, and we'll compare scan and match string + add chain_length,16-valsub + jmp iseq + ENDM + + +normalbeg2dc11: + normbeg rcontloop11,11 + +normalbeg2dc12: + normbeg short rcontloop12,12 + +normalbeg2dc13: + normbeg short rcontloop13,13 + +normalbeg2dc14: + normbeg short rcontloop14,14 + +normalbeg2dc15: + normbeg short rcontloop15,15 + +normalbeg2dc10: + normbeg rcontloop10,10 + +normalbeg2dc9: + normbeg rcontloop9,9 + +normalbeg2dc8: + normbeg rcontloop8,8 + +normalbeg2dc7: + normbeg rcontloop7,7 + +normalbeg2dc6: + normbeg rcontloop6,6 + +normalbeg2dc5: + normbeg rcontloop5,5 + +normalbeg2dc4: + normbeg rcontloop4,4 + +normalbeg2dc3: + normbeg rcontloop3,3 + +normalbeg2dc2: + normbeg rcontloop2,2 + +normalbeg2dc1: + normbeg rcontloop1,1 + +normalbeg2dc0: + normbeg rcontloop0,0 + + +; we go in normalbeg2 because *(ushf*)(match+best_len-1) == scan_end + +normalbeg2: + mov edi,window + + cmp bp,word ptr[edi+eax] + jne contloop3 ; if *(ushf*)match != scan_start, continue + +iseq: +; if we are here, we know that *(match+best_len-1) == scan_end +; and (match == scan_start) + + mov edi,edx + mov esi,scan ; esi = scan + add edi,eax ; edi = window + cur_match = match + + mov edx,[esi+3] ; compare manually dword at match+3 + xor edx,[edi+3] ; and scan +3 + + jz begincompare ; if equal, go to long compare + +; we will determine the unmatch byte and calculate len (in esi) + or dl,dl + je eq1rr + mov esi,3 + jmp trfinval +eq1rr: + or dx,dx + je eq1 + + mov esi,4 + jmp trfinval +eq1: + and edx,0ffffffh + jz eq11 + mov esi,5 + jmp trfinval +eq11: + mov esi,6 + jmp trfinval + +begincompare: + ; here we now scan and match begin same + add edi,6 + add esi,6 + mov ecx,(MAX_MATCH-(2+4))/4 ; scan for at most MAX_MATCH bytes + repe cmpsd ; loop until mismatch + + je trfin ; go to trfin if not unmatch +; we determine the unmatch byte + sub esi,4 + mov edx,[edi-4] + xor edx,[esi] + + or dl,dl + jnz trfin + inc esi + + or dx,dx + jnz trfin + inc esi + + and edx,0ffffffh + jnz trfin + inc esi + +trfin: + sub esi,scan ; esi = len +trfinval: +; here we have finised compare, and esi contain len of equal string + cmp esi,best_len ; if len > best_len, go newbestlen + ja short newbestlen +; now we restore edx, ecx and esi, for the big loop + mov esi,prev + mov ecx,limit + mov edx,window + jmp contloop3 + +newbestlen: + mov best_len,esi ; len become best_len + + mov match_start,eax ; save new position as match_start + cmp esi,nice_match ; if best_len >= nice_match, exit + jae exitloop + mov ecx,scan + mov edx,window ; restore edx=window + add ecx,esi + add esi,edx + + dec esi + mov windowlen,esi ; windowlen = window + best_len-1 + mov bx,[ecx-1] ; bx = *(scan+best_len-1) = scan_end + +; now we restore ecx and esi, for the big loop : + mov esi,prev + mov ecx,limit + jmp contloop3 + +exitloop: +; exit : s->match_start=match_start + mov ebx,match_start + mov ebp,str_s + mov ecx,best_len + mov dword ptr [ebp+dep_match_start],ebx + mov eax,dword ptr [ebp+dep_lookahead] + cmp ecx,eax + ja minexlo + mov eax,ecx +minexlo: +; return min(best_len,s->lookahead) + +; restore stack and register ebx,esi,edi,ebp + add esp,NbStackAdd + + pop ebx + pop esi + pop edi + pop ebp + ret +InfoAuthor: +; please don't remove this string ! +; Your are free use gvmat32 in any fre or commercial apps if you don't remove the string in the binary! + db 0dh,0ah,"GVMat32 optimised assembly code written 1996-98 by Gilles Vollant",0dh,0ah + + + +IFDEF NOUNDERLINE +longest_match_7fff endp +ELSE +_longest_match_7fff endp +ENDIF + + +IFDEF NOUNDERLINE +cpudetect32 proc near +ELSE +_cpudetect32 proc near +ENDIF + + push ebx + + pushfd ; push original EFLAGS + pop eax ; get original EFLAGS + mov ecx, eax ; save original EFLAGS + xor eax, 40000h ; flip AC bit in EFLAGS + push eax ; save new EFLAGS value on stack + popfd ; replace current EFLAGS value + pushfd ; get new EFLAGS + pop eax ; store new EFLAGS in EAX + xor eax, ecx ; can’t toggle AC bit, processor=80386 + jz end_cpu_is_386 ; jump if 80386 processor + push ecx + popfd ; restore AC bit in EFLAGS first + + pushfd + pushfd + pop ecx + + mov eax, ecx ; get original EFLAGS + xor eax, 200000h ; flip ID bit in EFLAGS + push eax ; save new EFLAGS value on stack + popfd ; replace current EFLAGS value + pushfd ; get new EFLAGS + pop eax ; store new EFLAGS in EAX + popfd ; restore original EFLAGS + xor eax, ecx ; can’t toggle ID bit, + je is_old_486 ; processor=old + + mov eax,1 + db 0fh,0a2h ;CPUID + +exitcpudetect: + pop ebx + ret + +end_cpu_is_386: + mov eax,0300h + jmp exitcpudetect + +is_old_486: + mov eax,0400h + jmp exitcpudetect + +IFDEF NOUNDERLINE +cpudetect32 endp +ELSE +_cpudetect32 endp +ENDIF + + + + +MAX_MATCH equ 258 +MIN_MATCH equ 3 +MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1) +MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h) + + +;;; stack frame offsets + +chainlenwmask equ esp + 0 ; high word: current chain len + ; low word: s->wmask +window equ esp + 4 ; local copy of s->window +windowbestlen equ esp + 8 ; s->window + bestlen +scanstart equ esp + 16 ; first two bytes of string +scanend equ esp + 12 ; last two bytes of string +scanalign equ esp + 20 ; dword-misalignment of string +nicematch equ esp + 24 ; a good enough match size +bestlen equ esp + 28 ; size of best match so far +scan equ esp + 32 ; ptr to string wanting match + +LocalVarsSize equ 36 +; saved ebx byte esp + 36 +; saved edi byte esp + 40 +; saved esi byte esp + 44 +; saved ebp byte esp + 48 +; return address byte esp + 52 +deflatestate equ esp + 56 ; the function arguments +curmatch equ esp + 60 + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +dsWSize equ 36 +dsWMask equ 44 +dsWindow equ 48 +dsPrev equ 56 +dsMatchLen equ 88 +dsPrevMatch equ 92 +dsStrStart equ 100 +dsMatchStart equ 104 +dsLookahead equ 108 +dsPrevLen equ 112 +dsMaxChainLen equ 116 +dsGoodMatch equ 132 +dsNiceMatch equ 136 + + +;;; match.asm -- Pentium-Pro-optimized version of longest_match() +;;; Written for zlib 1.1.2 +;;; Copyright (C) 1998 Brian Raiter +;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html +;;; +;;; This is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License. + +;GLOBAL _longest_match, _match_init + + +;SECTION .text + +;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch) + +;_longest_match: +IFDEF NOUNDERLINE +longest_match_686 proc near +ELSE +_longest_match_686 proc near +ENDIF + + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + push ebp + push edi + push esi + push ebx + sub esp, LocalVarsSize + +;;; Retrieve the function arguments. ecx will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + + mov edx, [deflatestate] + mov ecx, [curmatch] + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov eax, [edx + dsPrevLen] + mov ebx, [edx + dsGoodMatch] + cmp eax, ebx + mov eax, [edx + dsWMask] + mov ebx, [edx + dsMaxChainLen] + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + mov [chainlenwmask], ebx + +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + mov eax, [edx + dsNiceMatch] + mov ebx, [edx + dsLookahead] + cmp ebx, eax + jl LookaheadLess + mov ebx, eax +LookaheadLess: mov [nicematch], ebx + +;;; register Bytef *scan = s->window + s->strstart; + + mov esi, [edx + dsWindow] + mov [window], esi + mov ebp, [edx + dsStrStart] + lea edi, [esi + ebp] + mov [scan], edi + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov eax, edi + neg eax + and eax, 3 + mov [scanalign], eax + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + mov eax, [edx + dsWSize] + sub eax, MIN_LOOKAHEAD + sub ebp, eax + jg LimitPositive + xor ebp, ebp +LimitPositive: + +;;; int best_len = s->prev_length; + + mov eax, [edx + dsPrevLen] + mov [bestlen], eax + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + add esi, eax + mov [windowbestlen], esi + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx ebx, word ptr [edi] + mov [scanstart], ebx + movzx ebx, word ptr [edi + eax - 1] + mov [scanend], ebx + mov edi, [edx + dsPrev] + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + jmp short LoopEntry + +align 4 + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; ecx = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and ecx, edx + movzx ecx, word ptr [edi + ecx*2] + cmp ecx, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow +LoopEntry: movzx eax, word ptr [esi + ecx - 1] + cmp eax, ebx + jnz LookupLoop + mov eax, [window] + movzx eax, word ptr [eax + ecx] + cmp eax, [scanstart] + jnz LookupLoop + +;;; Store the current value of chainlen. + + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + mov esi, [window] + mov edi, [scan] + add esi, ecx + mov eax, [scanalign] + mov edx, 0fffffef8h; -(MAX_MATCH_8) + lea edi, [edi + eax + 0108h] ;MAX_MATCH_8] + lea esi, [esi + eax + 0108h] ;MAX_MATCH_8] + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust edx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (esi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + +LoopCmps: + mov eax, [esi + edx] + xor eax, [edi + edx] + jnz LeaveLoopCmps + mov eax, [esi + edx + 4] + xor eax, [edi + edx + 4] + jnz LeaveLoopCmps4 + add edx, 8 + jnz LoopCmps + jmp short LenMaximum +LeaveLoopCmps4: add edx, 4 +LeaveLoopCmps: test eax, 0000FFFFh + jnz LenLower + add edx, 2 + shr eax, 16 +LenLower: sub al, 1 + adc edx, 0 + +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea eax, [edi + edx] + mov edi, [scan] + sub eax, edi + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. + + mov edx, [deflatestate] + mov ebx, [bestlen] + cmp eax, ebx + jg LongerMatch + mov esi, [windowbestlen] + mov edi, [edx + dsPrev] + mov ebx, [scanend] + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: mov ebx, [nicematch] + mov [bestlen], eax + mov [edx + dsMatchStart], ecx + cmp eax, ebx + jge LeaveNow + mov esi, [window] + add esi, eax + mov [windowbestlen], esi + movzx ebx, word ptr [edi + eax - 1] + mov edi, [edx + dsPrev] + mov [scanend], ebx + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: mov edx, [deflatestate] + mov dword ptr [bestlen], MAX_MATCH + mov [edx + dsMatchStart], ecx + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: + mov edx, [deflatestate] + mov ebx, [bestlen] + mov eax, [edx + dsLookahead] + cmp ebx, eax + jg LookaheadRet + mov eax, ebx +LookaheadRet: + +;;; Restore the stack and return from whence we came. + + add esp, LocalVarsSize + pop ebx + pop esi + pop edi + pop ebp + + ret +; please don't remove this string ! +; Your can freely use gvmat32 in any free or commercial app if you don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah + +IFDEF NOUNDERLINE +longest_match_686 endp +ELSE +_longest_match_686 endp +ENDIF + +_TEXT ends +end diff --git a/zlib/contrib/masmx86/gvmat32c.c b/zlib/contrib/masmx86/gvmat32c.c new file mode 100644 index 0000000..d7124fa --- /dev/null +++ b/zlib/contrib/masmx86/gvmat32c.c @@ -0,0 +1,206 @@ +/* gvmat32.c -- C portion of the optimized longest_match for 32 bits x86 + * Copyright (C) 1995-1996 Jean-loup Gailly and Gilles Vollant. + * File written by Gilles Vollant, by modifiying the longest_match + * from Jean-loup Gailly in deflate.c + * it prepare all parameters and call the assembly longest_match_gvasm + * longest_match execute standard C code is wmask != 0x7fff + * (assembly code is faster with a fixed wmask) + * + */ + +#include "deflate.h" + +#ifdef ASMV +#define NIL 0 + +#define UNALIGNED_OK + + +/* if your C compiler don't add underline before function name, + define ADD_UNDERLINE_ASMFUNC */ +#ifdef ADD_UNDERLINE_ASMFUNC +#define longest_match_7fff _longest_match_7fff +#define longest_match_686 _longest_match_686 +#define cpudetect32 _cpudetect32 +#endif + + + +void match_init() +{ +} + +unsigned long cpudetect32(); + +uInt longest_match_c( + deflate_state *s, + IPos cur_match); /* current match */ + + +uInt longest_match_7fff( + deflate_state *s, + IPos cur_match); /* current match */ + +uInt longest_match_686( + deflate_state *s, + IPos cur_match); /* current match */ + +uInt longest_match( + deflate_state *s, + IPos cur_match) /* current match */ +{ + static uInt iIsPPro=2; + + if ((s->w_mask == 0x7fff) && (iIsPPro==0)) + return longest_match_7fff(s,cur_match); + + if (iIsPPro==1) + return longest_match_686(s,cur_match); + + if (iIsPPro==2) + iIsPPro = (((cpudetect32()/0x100)&0xf)>=6) ? 1 : 0; + + return longest_match_c(s,cur_match); +} + + + +uInt longest_match_c(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#endif /* ASMV */ diff --git a/zlib/contrib/masmx86/inffas32.asm b/zlib/contrib/masmx86/inffas32.asm new file mode 100644 index 0000000..a7db4ce --- /dev/null +++ b/zlib/contrib/masmx86/inffas32.asm @@ -0,0 +1,1033 @@ +; 75 "inffast.S" +;FILE "inffast.S" + +;;;GLOBAL _inflate_fast + +;;;SECTION .text + + + + .586p + .mmx + + name inflate_fast_x86 + .MODEL FLAT + +_DATA segment +inflate_fast_use_mmx: + dd 1 + + +_TEXT segment +PUBLIC _inflate_fast + +ALIGN 4 +_inflate_fast: + jmp inflate_fast_entry + + + +ALIGN 4 + db 'Fast decoding Code from Chris Anderson' + db 0 + +ALIGN 4 +invalid_literal_length_code_msg: + db 'invalid literal/length code' + db 0 + +ALIGN 4 +invalid_distance_code_msg: + db 'invalid distance code' + db 0 + +ALIGN 4 +invalid_distance_too_far_msg: + db 'invalid distance too far back' + db 0 + + +ALIGN 4 +inflate_fast_mask: +dd 0 +dd 1 +dd 3 +dd 7 +dd 15 +dd 31 +dd 63 +dd 127 +dd 255 +dd 511 +dd 1023 +dd 2047 +dd 4095 +dd 8191 +dd 16383 +dd 32767 +dd 65535 +dd 131071 +dd 262143 +dd 524287 +dd 1048575 +dd 2097151 +dd 4194303 +dd 8388607 +dd 16777215 +dd 33554431 +dd 67108863 +dd 134217727 +dd 268435455 +dd 536870911 +dd 1073741823 +dd 2147483647 +dd 4294967295 + + + +mode_state equ 0 ;/* state->mode */ +wsize_state equ 32 ;/* state->wsize */ +write_state equ (36+4) ;/* state->write */ +window_state equ (40+4) ;/* state->window */ +hold_state equ (44+4) ;/* state->hold */ +bits_state equ (48+4) ;/* state->bits */ +lencode_state equ (64+4) ;/* state->lencode */ +distcode_state equ (68+4) ;/* state->distcode */ +lenbits_state equ (72+4) ;/* state->lenbits */ +distbits_state equ (76+4) ;/* state->distbits */ + + +;;SECTION .text +; 205 "inffast.S" +;GLOBAL inflate_fast_use_mmx + +;SECTION .data + + +; GLOBAL inflate_fast_use_mmx:object +;.size inflate_fast_use_mmx, 4 +; 226 "inffast.S" +;SECTION .text + +ALIGN 4 +inflate_fast_entry: + push edi + push esi + push ebp + push ebx + pushfd + sub esp,64 + cld + + + + + mov esi, [esp+88] + mov edi, [esi+28] + + + + + + + + mov edx, [esi+4] + mov eax, [esi+0] + + add edx,eax + sub edx,11 + + mov [esp+44],eax + mov [esp+20],edx + + mov ebp, [esp+92] + mov ecx, [esi+16] + mov ebx, [esi+12] + + sub ebp,ecx + neg ebp + add ebp,ebx + + sub ecx,257 + add ecx,ebx + + mov [esp+60],ebx + mov [esp+40],ebp + mov [esp+16],ecx +; 285 "inffast.S" + mov eax, [edi+lencode_state] + mov ecx, [edi+distcode_state] + + mov [esp+8],eax + mov [esp+12],ecx + + mov eax,1 + mov ecx, [edi+lenbits_state] + shl eax,cl + dec eax + mov [esp+0],eax + + mov eax,1 + mov ecx, [edi+distbits_state] + shl eax,cl + dec eax + mov [esp+4],eax + + mov eax, [edi+wsize_state] + mov ecx, [edi+write_state] + mov edx, [edi+window_state] + + mov [esp+52],eax + mov [esp+48],ecx + mov [esp+56],edx + + mov ebp, [edi+hold_state] + mov ebx, [edi+bits_state] +; 321 "inffast.S" + mov esi, [esp+44] + mov ecx, [esp+20] + cmp ecx,esi + ja L_align_long + + add ecx,11 + sub ecx,esi + mov eax,12 + sub eax,ecx + lea edi, [esp+28] + rep movsb + mov ecx,eax + xor eax,eax + rep stosb + lea esi, [esp+28] + mov [esp+20],esi + jmp L_is_aligned + + +L_align_long: + test esi,3 + jz L_is_aligned + xor eax,eax + mov al, [esi] + inc esi + mov ecx,ebx + add ebx,8 + shl eax,cl + or ebp,eax + jmp L_align_long + +L_is_aligned: + mov edi, [esp+60] +; 366 "inffast.S" +L_check_mmx: + cmp dword ptr [inflate_fast_use_mmx],2 + je L_init_mmx + ja L_do_loop + + push eax + push ebx + push ecx + push edx + pushfd + mov eax, [esp] + xor dword ptr [esp],0200000h + + + + + popfd + pushfd + pop edx + xor edx,eax + jz L_dont_use_mmx + xor eax,eax + cpuid + cmp ebx,0756e6547h + jne L_dont_use_mmx + cmp ecx,06c65746eh + jne L_dont_use_mmx + cmp edx,049656e69h + jne L_dont_use_mmx + mov eax,1 + cpuid + shr eax,8 + and eax,15 + cmp eax,6 + jne L_dont_use_mmx + test edx,0800000h + jnz L_use_mmx + jmp L_dont_use_mmx +L_use_mmx: + mov dword ptr [inflate_fast_use_mmx],2 + jmp L_check_mmx_pop +L_dont_use_mmx: + mov dword ptr [inflate_fast_use_mmx],3 +L_check_mmx_pop: + pop edx + pop ecx + pop ebx + pop eax + jmp L_check_mmx +; 426 "inffast.S" +ALIGN 4 +L_do_loop: +; 437 "inffast.S" + cmp bl,15 + ja L_get_length_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_length_code: + mov edx, [esp+0] + mov ecx, [esp+8] + and edx,ebp + mov eax, [ecx+edx*4] + +L_dolen: + + + + + + + mov cl,ah + sub bl,ah + shr ebp,cl + + + + + + + test al,al + jnz L_test_for_length_base + + shr eax,16 + stosb + +L_while_test: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop + jmp L_break_loop + +L_test_for_length_base: +; 502 "inffast.S" + mov edx,eax + shr edx,16 + mov cl,al + + test al,16 + jz L_test_for_second_level_length + and cl,15 + jz L_save_len + cmp bl,cl + jae L_add_bits_to_len + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_len: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + +L_save_len: + mov [esp+24],edx + + +L_decode_distance: +; 549 "inffast.S" + cmp bl,15 + ja L_get_distance_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_distance_code: + mov edx, [esp+4] + mov ecx, [esp+12] + and edx,ebp + mov eax, [ecx+edx*4] + + +L_dodist: + mov edx,eax + shr edx,16 + mov cl,ah + sub bl,ah + shr ebp,cl +; 584 "inffast.S" + mov cl,al + + test al,16 + jz L_test_for_second_level_dist + and cl,15 + jz L_check_dist_one + cmp bl,cl + jae L_add_bits_to_dist + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_dist: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + jmp L_check_window + +L_check_window: +; 625 "inffast.S" + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,edx + jb L_clip_window + + mov ecx, [esp+24] + mov esi,edi + sub esi,edx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp edx,1 + jne L_check_window + cmp [esp+40],edi + je L_check_window + + dec edi + mov ecx, [esp+24] + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + + + + + test al,64 + jnz L_test_for_end_of_block + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+8] + mov eax, [edx+eax*4] + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + + + + + test al,64 + jnz L_invalid_distance_code + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+12] + mov eax, [edx+eax*4] + jmp L_dodist + +ALIGN 4 +L_clip_window: +; 721 "inffast.S" + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,edx + jb L_invalid_distance_too_far + + add ecx,edx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window + + sub eax,ecx + add esi,eax +; 749 "inffast.S" + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_wrap_around_window: +; 793 "inffast.S" + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_contiguous_in_window: +; 836 "inffast.S" + add esi,eax + sub esi,ecx + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + +L_do_copy1: +; 862 "inffast.S" + mov ecx,eax + rep movsb + + mov esi, [esp+44] + jmp L_while_test +; 878 "inffast.S" +ALIGN 4 +L_init_mmx: + emms + + + + + + movd mm0,ebp + mov ebp,ebx +; 896 "inffast.S" + movd mm4,[esp+0] + movq mm3,mm4 + movd mm5,[esp+4] + movq mm2,mm5 + pxor mm1,mm1 + mov ebx, [esp+8] + jmp L_do_loop_mmx + +ALIGN 4 +L_do_loop_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_length_code_mmx + + movd mm6,ebp + movd mm7,[esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_length_code_mmx: + pand mm4,mm0 + movd eax,mm4 + movq mm4,mm3 + mov eax, [ebx+eax*4] + +L_dolen_mmx: + movzx ecx,ah + movd mm1,ecx + sub ebp,ecx + + test al,al + jnz L_test_for_length_base_mmx + + shr eax,16 + stosb + +L_while_test_mmx: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop_mmx + jmp L_break_loop + +L_test_for_length_base_mmx: + + mov edx,eax + shr edx,16 + + test al,16 + jz L_test_for_second_level_length_mmx + and eax,15 + jz L_decode_distance_mmx + + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add edx,ecx + +L_decode_distance_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_dist_code_mmx + + movd mm6,ebp + movd mm7,[esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_dist_code_mmx: + mov ebx, [esp+12] + pand mm5,mm0 + movd eax,mm5 + movq mm5,mm2 + mov eax, [ebx+eax*4] + +L_dodist_mmx: + + movzx ecx,ah + mov ebx,eax + shr ebx,16 + sub ebp,ecx + movd mm1,ecx + + test al,16 + jz L_test_for_second_level_dist_mmx + and eax,15 + jz L_check_dist_one_mmx + +L_add_bits_to_dist_mmx: + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add ebx,ecx + +L_check_window_mmx: + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,ebx + jb L_clip_window_mmx + + mov ecx,edx + mov esi,edi + sub esi,ebx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_check_dist_one_mmx: + cmp ebx,1 + jne L_check_window_mmx + cmp [esp+40],edi + je L_check_window_mmx + + dec edi + mov ecx,edx + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_test_for_second_level_length_mmx: + test al,64 + jnz L_test_for_end_of_block + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + add ecx,edx + mov eax, [ebx+ecx*4] + jmp L_dolen_mmx + +ALIGN 4 +L_test_for_second_level_dist_mmx: + test al,64 + jnz L_invalid_distance_code + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + mov eax, [esp+12] + add ecx,ebx + mov eax, [eax+ecx*4] + jmp L_dodist_mmx + +ALIGN 4 +L_clip_window_mmx: + + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,ebx + jb L_invalid_distance_too_far + + add ecx,ebx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window_mmx + + sub eax,ecx + add esi,eax + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_wrap_around_window_mmx: + + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window_mmx + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_contiguous_in_window_mmx: + + add esi,eax + sub esi,ecx + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + +L_do_copy1_mmx: + + + mov ecx,edx + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx +; 1174 "inffast.S" +L_invalid_distance_code: + + + + + + mov ecx, invalid_distance_code_msg + mov edx,26 + jmp L_update_stream_state + +L_test_for_end_of_block: + + + + + + test al,32 + jz L_invalid_literal_length_code + + mov ecx,0 + mov edx,11 + jmp L_update_stream_state + +L_invalid_literal_length_code: + + + + + + mov ecx, invalid_literal_length_code_msg + mov edx,26 + jmp L_update_stream_state + +L_invalid_distance_too_far: + + + + mov esi, [esp+44] + mov ecx, invalid_distance_too_far_msg + mov edx,26 + jmp L_update_stream_state + +L_update_stream_state: + + mov eax, [esp+88] + test ecx,ecx + jz L_skip_msg + mov [eax+24],ecx +L_skip_msg: + mov eax, [eax+28] + mov [eax+mode_state],edx + jmp L_break_loop + +ALIGN 4 +L_break_loop: +; 1243 "inffast.S" + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_next_in + + + + mov ebx,ebp + +L_update_next_in: +; 1266 "inffast.S" + mov eax, [esp+88] + mov ecx,ebx + mov edx, [eax+28] + shr ecx,3 + sub esi,ecx + shl ecx,3 + sub ebx,ecx + mov [eax+12],edi + mov [edx+bits_state],ebx + mov ecx,ebx + + lea ebx, [esp+28] + cmp [esp+20],ebx + jne L_buf_not_used + + sub esi,ebx + mov ebx, [eax+0] + mov [esp+20],ebx + add esi,ebx + mov ebx, [eax+4] + sub ebx,11 + add [esp+20],ebx + +L_buf_not_used: + mov [eax+0],esi + + mov ebx,1 + shl ebx,cl + dec ebx + + + + + + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_hold + + + + psrlq mm0,mm1 + movd ebp,mm0 + + emms + +L_update_hold: + + + + and ebp,ebx + mov [edx+hold_state],ebp + + + + + mov ebx, [esp+20] + cmp ebx,esi + jbe L_last_is_smaller + + sub ebx,esi + add ebx,11 + mov [eax+4],ebx + jmp L_fixup_out +L_last_is_smaller: + sub esi,ebx + neg esi + add esi,11 + mov [eax+4],esi + + + + +L_fixup_out: + + mov ebx, [esp+16] + cmp ebx,edi + jbe L_end_is_smaller + + sub ebx,edi + add ebx,257 + mov [eax+16],ebx + jmp L_done +L_end_is_smaller: + sub edi,ebx + neg edi + add edi,257 + mov [eax+16],edi + + + + + +L_done: + add esp,64 + popfd + pop ebx + pop ebp + pop esi + pop edi + ret + + + + +_TEXT ends +end diff --git a/zlib/contrib/masmx86/mkasm.bat b/zlib/contrib/masmx86/mkasm.bat new file mode 100644 index 0000000..f3fa0a0 --- /dev/null +++ b/zlib/contrib/masmx86/mkasm.bat @@ -0,0 +1,3 @@ +cl /I..\.. /O2 /c gvmat32c.c +ml /coff /Zi /c /Flgvmat32.lst gvmat32.asm +ml /coff /Zi /c /Flinffas32.lst inffas32.asm diff --git a/zlib/contrib/masmx86/readme.txt b/zlib/contrib/masmx86/readme.txt new file mode 100644 index 0000000..e2975c5 --- /dev/null +++ b/zlib/contrib/masmx86/readme.txt @@ -0,0 +1,21 @@ + +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(). + + +Use instructions +---------------- +Copy these files into the zlib source directory, then run the +appropriate makefile, as suggested below. + + +Build instructions +------------------ +* With Microsoft C and MASM: +nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="gvmat32c.obj gvmat32.obj inffas32.obj" + +* With Borland C and TASM: +make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="gvmat32c.obj gvmat32.obj inffas32.obj" OBJPA="+gvmat32c.obj+gvmat32.obj+inffas32.obj" + diff --git a/zlib/contrib/minizip/ChangeLogUnzip b/zlib/contrib/minizip/ChangeLogUnzip new file mode 100644 index 0000000..3508eb4 --- /dev/null +++ b/zlib/contrib/minizip/ChangeLogUnzip @@ -0,0 +1,55 @@ +Change in 1.00: (10 sept 03) +- rename to 1.00 +- cosmetic code change + +Change in 0.22: (19 May 03) +- crypting support (unless you define NOCRYPT) +- append file in existing zipfile + +Change in 0.21: (10 Mar 03) +- bug fixes + +Change in 0.17: (27 Jan 02) +- bug fixes + +Change in 0.16: (19 Jan 02) +- Support of ioapi for virtualize zip file access + +Change in 0.15: (19 Mar 98) +- fix memory leak in minizip.c + +Change in 0.14: (10 Mar 98) +- fix bugs in minizip.c sample for zipping big file +- fix problem in month in date handling +- fix bug in unzlocal_GetCurrentFileInfoInternal in unzip.c for + comment handling + +Change in 0.13: (6 Mar 98) +- fix bugs in zip.c +- add real minizip sample + +Change in 0.12: (4 Mar 98) +- add zip.c and zip.h for creates .zip file +- fix change_file_date in miniunz.c for Unix (Jean-loup Gailly) +- fix miniunz.c for file without specific record for directory + +Change in 0.11: (3 Mar 98) +- fix bug in unzGetCurrentFileInfo for get extra field and comment +- enhance miniunz sample, remove the bad unztst.c sample + +Change in 0.10: (2 Mar 98) +- fix bug in unzReadCurrentFile +- rename unzip* to unz* function and structure +- remove Windows-like hungary notation variable name +- modify some structure in unzip.h +- add somes comment in source +- remove unzipGetcCurrentFile function +- replace ZUNZEXPORT by ZEXPORT +- add unzGetLocalExtrafield for get the local extrafield info +- add a new sample, miniunz.c + +Change in 0.4: (25 Feb 98) +- suppress the type unzipFileInZip. + Only on file in the zipfile can be open at the same time +- fix somes typo in code +- added tm_unz structure in unzip_file_info (date/time in readable format) diff --git a/zlib/contrib/minizip/Makefile b/zlib/contrib/minizip/Makefile new file mode 100644 index 0000000..fbba3ac --- /dev/null +++ b/zlib/contrib/minizip/Makefile @@ -0,0 +1,25 @@ +CC=cc +CFLAGS=-O -I../.. + +UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a +ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +all: miniunz minizip + +miniunz: $(UNZ_OBJS) + $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) + +minizip: $(ZIP_OBJS) + $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) + +test: miniunz minizip + ./minizip test readme.txt + ./miniunz -l test.zip + mv readme.txt readme.old + ./miniunz test.zip + +clean: + /bin/rm -f *.o *~ minizip miniunz diff --git a/zlib/contrib/minizip/crypt.h b/zlib/contrib/minizip/crypt.h new file mode 100644 index 0000000..8c95679 --- /dev/null +++ b/zlib/contrib/minizip/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const unsigned long* pcrc_32_tab; + unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/zlib/contrib/minizip/ioapi.c b/zlib/contrib/minizip/ioapi.c new file mode 100644 index 0000000..894fc83 --- /dev/null +++ b/zlib/contrib/minizip/ioapi.c @@ -0,0 +1,177 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + fseek((FILE *)stream, offset, fseek_origin); + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/zlib/contrib/minizip/ioapi.h b/zlib/contrib/minizip/ioapi.h new file mode 100644 index 0000000..bd29cb7 --- /dev/null +++ b/zlib/contrib/minizip/ioapi.h @@ -0,0 +1,75 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/zlib/contrib/minizip/iowin32.c b/zlib/contrib/minizip/iowin32.c new file mode 100644 index 0000000..7c670ab --- /dev/null +++ b/zlib/contrib/minizip/iowin32.c @@ -0,0 +1,270 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + This IO API version uses the Win32 API (for Microsoft Windows) + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +voidpf ZCALLBACK win32_open_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK win32_read_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK win32_write_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK win32_tell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK win32_seek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK win32_close_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK win32_error_file_func OF(( + voidpf opaque, + voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + +voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = 0; + voidpf ret=NULL; + + dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + dwDesiredAccess = GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + dwShareMode = FILE_SHARE_READ; + } + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + } + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + dwCreationDisposition = CREATE_ALWAYS; + } + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, + dwCreationDisposition, dwFlagsAndAttributes, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + hFile = NULL; + + if (hFile != NULL) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + if (ret==NULL) + CloseHandle(hFile); + else *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + + +uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile !=NULL) + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + + return ret; +} + +long ZCALLBACK win32_tell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)dwSet; + } + return ret; +} + +long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque=NULL; +} diff --git a/zlib/contrib/minizip/iowin32.h b/zlib/contrib/minizip/iowin32.h new file mode 100644 index 0000000..17d459a --- /dev/null +++ b/zlib/contrib/minizip/iowin32.h @@ -0,0 +1,21 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + This IO API version uses the Win32 API (for Microsoft Windows) + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/zlib/contrib/minizip/miniunz.c b/zlib/contrib/minizip/miniunz.c new file mode 100644 index 0000000..a5c2f72 --- /dev/null +++ b/zlib/contrib/minizip/miniunz.c @@ -0,0 +1,556 @@ +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef WIN32 + ret = mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.00, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info gi; + int err; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (file_info.compressed_size*100)/file_info.uncompressed_size; + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + string_method="Unkn. "; + + printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + file_info.uncompressed_size,string_method, + charCrypt, + file_info.compressed_size, + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen(write_filename,"wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATA ff32; + + hFind = FindFirstFile(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.00, demo of zLib + Zip package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %x\n",filenameinzip,calculate_crc); + return err; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc_def ffunc; + fill_win32_filefunc(&ffunc); + zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + + free(buf); + return 0; +} diff --git a/zlib/contrib/minizip/unzip.c b/zlib/contrib/minizip/unzip.c new file mode 100644 index 0000000..00cfb9c --- /dev/null +++ b/zlib/contrib/minizip/unzip.c @@ -0,0 +1,1546 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + Read unzip.h for more info +*/ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. Code +woven in by Terry Thorsen 1/2003. +*/ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = + " unzip 1.00 Copyright 1998-2003 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) + const char *path; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + else + return err; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (file, password) + unzFile file; + const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) + unzFile file; + int* method; + int* level; + int raw; +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,size_to_read)!=size_to_read) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/zlib/contrib/minizip/unzip.h b/zlib/contrib/minizip/unzip.h new file mode 100644 index 0000000..19f83b3 --- /dev/null +++ b/zlib/contrib/minizip/unzip.h @@ -0,0 +1,342 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/zlib/contrib/minizip/zip.c b/zlib/contrib/minizip/zip.c new file mode 100644 index 0000000..54f724e --- /dev/null +++ b/zlib/contrib/minizip/zip.c @@ -0,0 +1,1170 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + Read zip.h for more info +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] = + " zip 1.00 Copyright 1998-2003 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + uLong pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralheader; /* size of the central header for cur file */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile_info; + +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile_info ci; /* info on the file curretly writing */ + + uLong begin_pos; /* position of the beginning of the zipfile */ + uLong add_position_when_writting_offset; + uLong number_entry; +} zip_internal; + + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(ldi) + linkedlist_datablock_internal* ldi; +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(ll) + linkedlist_data* ll; +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(ll) + linkedlist_data* ll; +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(ll,buf,len) + linkedlist_data* ll; + const void* buf; + uLong len; +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 or 4 (byte, short or long) +*/ + +local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, uLong x, int nbByte)); +local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong x; + int nbByte; +{ + unsigned char buf[4]; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); +local void ziplocal_putValue_inmemory (dest, x, nbByte) + void* dest; + uLong x; + int nbByte; +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } +} +/****************************************************************************/ + + +local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) + const tm_zip* ptm; + uLong dosDate; +{ + uLong year = (uLong)ptm->tm_year; + if (year>1980) + year-=1980; + else if (year>80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int ziplocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int ziplocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int ziplocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong ziplocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + +/************************************************************/ +extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def) + const char *pathname; + int append; + zipcharpc* globalcomment; + zlib_filefunc_def* pzlib_filefunc_def; +{ + zip_internal ziinit; + zip_internal* zi; + int err=ZIP_OK; + + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&ziinit.z_filefunc); + else + ziinit.z_filefunc = *pzlib_filefunc_def; + + ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) + (ziinit.z_filefunc.opaque, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + zi = (zip_internal*)ALLOC(sizeof(zip_internal)); + if (zi==NULL) + { + ZCLOSE(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + if (append == APPEND_STATUS_ADDINZIP) + { + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory */ + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry; + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong size_comment; + + central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); + if (central_pos==0) + err=ZIP_ERRNO; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* zipfile comment length */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((central_pos0) && (err==ZIP_OK)) + { + uLong read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&ziinit.central_dir,buf_read, + (uLong)read_this); + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + ziinit.begin_pos = byte_before_the_zipfile; + ziinit.number_entry = number_entry_CD; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen (pathname, append) + const char *pathname; + int append; +{ + return zipOpen2(pathname,append,NULL,NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; +{ + zip_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = strlen(comment); + + size_filename = strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); + } + + zi->ci.flag = 0; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + + size_extrafield_global + size_comment; + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); + + ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); + ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + /* write the local header */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); + + if ((err==ZIP_OK) && (size_filename>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + + if ((err==ZIP_OK) && (size_extrafield_local>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) + !=size_extrafield_local) + err = ZIP_ERRNO; + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, + Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = 1; + } +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; +{ + return zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; +{ + return zipOpenNewFileInZip2 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0); +} + +local int zipFlushWriteBuffer(zi) + zip_internal* zi; +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, + zi->ci.buffered_data[i],t); +#endif + } + if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) + !=zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (file, buf, len) + zipFile file; + const void* buf; + unsigned len; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.stream.next_in = (void*)buf; + zi->ci.stream.avail_in = len; + zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + for (i=0;ici.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) + zipFile file; + uLong uncompressed_size; + uLong crc32; +{ + zip_internal* zi; + uLong compressed_size; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + err=deflateEnd(&zi->ci.stream); + zi->ci.stream_initialised = 0; + } + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = (uLong)zi->ci.stream.total_in; + } + compressed_size = (uLong)zi->ci.stream.total_out; +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20, + compressed_size,4); /*compr size*/ + if (zi->ci.stream.data_type == Z_ASCII) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + ziplocal_putValue_inmemory(zi->ci.central_header+24, + uncompressed_size,4); /*uncompr size*/ + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, + (uLong)zi->ci.size_centralheader); + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (ZSEEK(zi->z_filefunc,zi->filestream, + zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + + if (ZSEEK(zi->z_filefunc,zi->filestream, + cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (file) + zipFile file; +{ + return zipCloseFileInZipRaw (file,0,0); +} + +extern int ZEXPORT zipClose (file, global_comment) + zipFile file; + const char* global_comment; +{ + zip_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uLong centraldir_pos_inzip ; + uInt size_global_comment; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + + if (global_comment==NULL) + size_global_comment = 0; + else + size_global_comment = strlen(global_comment); + + + centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + ldi->data,ldi->filled_in_this_block) + !=ldi->filled_in_this_block ) + err = ZIP_ERRNO; + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_datablock(zi->central_dir.first_block); + + if (err==ZIP_OK) /* Magic End */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* size of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the + starting disk number */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, + (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + + if (err==ZIP_OK) /* zipfile comment length */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if ((err==ZIP_OK) && (size_global_comment>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + global_comment,size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + + if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + + TRYFREE(zi); + + return err; +} diff --git a/zlib/contrib/minizip/zip.h b/zlib/contrib/minizip/zip.h new file mode 100644 index 0000000..dd13b57 --- /dev/null +++ b/zlib/contrib/minizip/zip.h @@ -0,0 +1,235 @@ +/* zip.h -- IO for compress .zip files using zlib + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + This unzip package allow creates .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + For uncompress .zip file, look at unzip.h + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.html for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _zip_H +#define _zip_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCtypting)); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCtypting : crc of file to compress (needed for crypting) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); +/* + Close the current file in the zipfile, for fiel opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip_H */ diff --git a/zlib/contrib/pascal/example.pas b/zlib/contrib/pascal/example.pas new file mode 100644 index 0000000..bb04099 --- /dev/null +++ b/zlib/contrib/pascal/example.pas @@ -0,0 +1,599 @@ +(* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Pascal translation + * Copyright (C) 1998 by Jacques Nomssi Nzali. + * For conditions of distribution and use, see copyright notice in readme.txt + * + * Adaptation to the zlibpas interface + * Copyright (C) 2003 by Cosmin Truta. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +program example; + +{$DEFINE TEST_COMPRESS} +{DO NOT $DEFINE TEST_GZIO} +{$DEFINE TEST_DEFLATE} +{$DEFINE TEST_INFLATE} +{$DEFINE TEST_FLUSH} +{$DEFINE TEST_SYNC} +{$DEFINE TEST_DICT} + +uses SysUtils, zlibpas; + +const TESTFILE = 'foo.gz'; + +(* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + *) +const hello: PChar = 'hello, hello!'; + +const dictionary: PChar = 'hello'; + +var dictId: LongInt; (* Adler32 value of the dictionary *) + +procedure CHECK_ERR(err: Integer; msg: String); +begin + if err <> Z_OK then + begin + WriteLn(msg, ' error: ', err); + Halt(1); + end; +end; + +procedure EXIT_ERR(const msg: String); +begin + WriteLn('Error: ', msg); + Halt(1); +end; + +(* =========================================================================== + * Test compress and uncompress + *) +{$IFDEF TEST_COMPRESS} +procedure test_compress(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + err := compress(compr, comprLen, hello, len); + CHECK_ERR(err, 'compress'); + + StrCopy(PChar(uncompr), 'garbage'); + + err := uncompress(uncompr, uncomprLen, compr, comprLen); + CHECK_ERR(err, 'uncompress'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad uncompress') + else + WriteLn('uncompress(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test read/write of .gz files + *) +{$IFDEF TEST_GZIO} +procedure test_gzio(const fname: PChar; (* compressed file name *) + uncompr: Pointer; + uncomprLen: LongInt); +var err: Integer; + len: Integer; + zfile: gzFile; + pos: LongInt; +begin + len := StrLen(hello)+1; + + zfile := gzopen(fname, 'wb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + gzputc(zfile, 'h'); + if gzputs(zfile, 'ello') <> 4 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$IFDEF GZ_FORMAT_STRING} + if gzprintf(zfile, ', %s!', 'hello') <> 8 then + begin + WriteLn('gzprintf err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ELSE} + if gzputs(zfile, ', hello!') <> 8 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ENDIF} + gzseek(zfile, 1, SEEK_CUR); (* add one zero byte *) + gzclose(zfile); + + zfile := gzopen(fname, 'rb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + + StrCopy(PChar(uncompr), 'garbage'); + + if gzread(zfile, uncompr, uncomprLen) <> len then + begin + WriteLn('gzread err: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello) <> 0 then + begin + WriteLn('bad gzread: ', PChar(uncompr)); + Halt(1); + end + else + WriteLn('gzread(): ', PChar(uncompr)); + + pos := gzseek(zfile, -8, SEEK_CUR); + if (pos <> 6) or (gztell(zfile) <> pos) then + begin + WriteLn('gzseek error, pos=', pos, ', gztell=', gztell(zfile)); + Halt(1); + end; + + if gzgetc(zfile) <> ' ' then + begin + WriteLn('gzgetc error'); + Halt(1); + end; + + if gzungetc(' ', zfile) <> ' ' then + begin + WriteLn('gzungetc error'); + Halt(1); + end; + + gzgets(zfile, PChar(uncompr), uncomprLen); + uncomprLen := StrLen(PChar(uncompr)); + if uncomprLen <> 7 then (* " hello!" *) + begin + WriteLn('gzgets err after gzseek: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello + 6) <> 0 then + begin + WriteLn('bad gzgets after gzseek'); + Halt(1); + end + else + WriteLn('gzgets() after gzseek: ', PChar(uncompr)); + + gzclose(zfile); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with small buffers + *) +{$IFDEF TEST_DEFLATE} +procedure test_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + + while (c_stream.total_in <> len) and + (c_stream.total_out < comprLen) do + begin + c_stream.avail_out := 1; { force small buffers } + c_stream.avail_in := 1; + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + end; + + (* Finish the stream, still forcing small buffers: *) + while TRUE do + begin + c_stream.avail_out := 1; + err := deflate(c_stream, Z_FINISH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'deflate'); + end; + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with small buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_inflate(compr: Pointer; comprLen : LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 0; + d_stream.next_out := uncompr; + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while (d_stream.total_out < uncomprLen) and + (d_stream.total_in < comprLen) do + begin + d_stream.avail_out := 1; (* force small buffers *) + d_stream.avail_in := 1; + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate') + else + WriteLn('inflate(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with large buffers and dynamic change of compression level + *) +{$IFDEF TEST_DEFLATE} +procedure test_large_deflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_SPEED); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + (* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + *) + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + if c_stream.avail_in <> 0 then + EXIT_ERR('deflate not greedy'); + + (* Feed in already compressed data and switch to no compression: *) + deflateParams(c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in := compr; + c_stream.avail_in := Integer(comprLen div 2); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + (* Switch back to compressing mode: *) + deflateParams(c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with large buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_large_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while TRUE do + begin + d_stream.next_out := uncompr; (* discard the output *) + d_stream.avail_out := Integer(uncomprLen); + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'large inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if d_stream.total_out <> 2 * uncomprLen + comprLen div 2 then + begin + WriteLn('bad large inflate: ', d_stream.total_out); + Halt(1); + end + else + WriteLn('large_inflate(): OK'); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with full flush + *) +{$IFDEF TEST_FLUSH} +procedure test_flush(compr: Pointer; var comprLen : LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: Integer; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + c_stream.avail_in := 3; + c_stream.avail_out := Integer(comprLen); + err := deflate(c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, 'deflate'); + + Inc(PByteArray(compr)^[3]); (* force an error in first compressed block *) + c_stream.avail_in := len - 3; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + CHECK_ERR(err, 'deflate'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); + + comprLen := c_stream.total_out; +end; +{$ENDIF} + +(* =========================================================================== + * Test inflateSync() + *) +{$IFDEF TEST_SYNC} +procedure test_sync(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 2; (* just read the zlib header *) + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + inflate(d_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'inflate'); + + d_stream.avail_in := Integer(comprLen-2); (* read all compressed data *) + err := inflateSync(d_stream); (* but skip the damaged part *) + CHECK_ERR(err, 'inflateSync'); + + err := inflate(d_stream, Z_FINISH); + if err <> Z_DATA_ERROR then + EXIT_ERR('inflate should report DATA_ERROR'); + (* Because of incorrect adler32 *) + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + WriteLn('after inflateSync(): hel', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + err := deflateSetDictionary(c_stream, dictionary, StrLen(dictionary)); + CHECK_ERR(err, 'deflateSetDictionary'); + + dictId := c_stream.adler; + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + c_stream.next_in := hello; + c_stream.avail_in := StrLen(hello)+1; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with a preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + while TRUE do + begin + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + if err = Z_NEED_DICT then + begin + if d_stream.adler <> dictId then + EXIT_ERR('unexpected dictionary'); + err := inflateSetDictionary(d_stream, dictionary, StrLen(dictionary)); + end; + CHECK_ERR(err, 'inflate with dict'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate with dict') + else + WriteLn('inflate with dictionary: ', PChar(uncompr)); +end; +{$ENDIF} + +var compr, uncompr: Pointer; + comprLen, uncomprLen: LongInt; + +begin + if zlibVersion^ <> ZLIB_VERSION[1] then + EXIT_ERR('Incompatible zlib version'); + + WriteLn('zlib version: ', zlibVersion); + WriteLn('zlib compile flags: ', Format('0x%x', [zlibCompileFlags])); + + comprLen := 10000 * SizeOf(Integer); (* don't overflow on MSDOS *) + uncomprLen := comprLen; + GetMem(compr, comprLen); + GetMem(uncompr, uncomprLen); + if (compr = NIL) or (uncompr = NIL) then + EXIT_ERR('Out of memory'); + (* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + *) + FillChar(compr^, comprLen, 0); + FillChar(uncompr^, uncomprLen, 0); + + {$IFDEF TEST_COMPRESS} + WriteLn('** Testing compress'); + test_compress(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_GZIO} + WriteLn('** Testing gzio'); + if ParamCount >= 1 then + test_gzio(ParamStr(1), uncompr, uncomprLen) + else + test_gzio(TESTFILE, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with small buffers'); + test_deflate(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with small buffers'); + test_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with large buffers'); + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with large buffers'); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_FLUSH} + WriteLn('** Testing deflate with full flush'); + test_flush(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_SYNC} + WriteLn('** Testing inflateSync'); + test_sync(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + comprLen := uncomprLen; + + {$IFDEF TEST_DICT} + WriteLn('** Testing deflate and inflate with preset dictionary'); + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + FreeMem(compr, comprLen); + FreeMem(uncompr, uncomprLen); +end. diff --git a/zlib/contrib/pascal/readme.txt b/zlib/contrib/pascal/readme.txt new file mode 100644 index 0000000..573a4a0 --- /dev/null +++ b/zlib/contrib/pascal/readme.txt @@ -0,0 +1,76 @@ + +This directory contains a Pascal (Delphi, Kylix) interface to the +zlib data compression library. + + +Directory listing +================= + +zlibd32.mak makefile for Borland C++ +example.pas usage example of zlib +zlibpas.pas the Pascal interface to zlib +readme.txt this file + + +Compatibility notes +=================== + +- Although the name "zlib" would have been more normal for the + zlibpas unit, this name is already taken by Borland's ZLib unit. + This is somehow unfortunate, because that unit is not a genuine + interface to the full-fledged zlib functionality, but a suite of + class wrappers around zlib streams. Other essential features, + such as checksums, are missing. + It would have been more appropriate for that unit to have a name + like "ZStreams", or something similar. + +- The C and zlib-supplied types int, uInt, long, uLong, etc. are + translated directly into Pascal types of similar sizes (Integer, + LongInt, etc.), to avoid namespace pollution. In particular, + there is no conversion of unsigned int into a Pascal unsigned + integer. The Word type is non-portable and has the same size + (16 bits) both in a 16-bit and in a 32-bit environment, unlike + Integer. Even if there is a 32-bit Cardinal type, there is no + real need for unsigned int in zlib under a 32-bit environment. + +- Except for the callbacks, the zlib function interfaces are + assuming the calling convention normally used in Pascal + (__pascal for DOS and Windows16, __fastcall for Windows32). + Since the cdecl keyword is used, the old Turbo Pascal does + not work with this interface. + +- The gz* function interfaces are not translated, to avoid + interfacing problems with the C runtime library. Besides, + gzprintf(gzFile file, const char *format, ...) + cannot be translated into Pascal. + + +Legal issues +============ + +The zlibpas interface is: + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler. + Copyright (C) 1998 by Bob Dellaca. + Copyright (C) 2003 by Cosmin Truta. + +The example program is: + Copyright (C) 1995-2003 by Jean-loup Gailly. + Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali. + Copyright (C) 2003 by Cosmin Truta. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + diff --git a/zlib/contrib/pascal/zlibd32.mak b/zlib/contrib/pascal/zlibd32.mak new file mode 100644 index 0000000..6fb10e4 --- /dev/null +++ b/zlib/contrib/pascal/zlibd32.mak @@ -0,0 +1,93 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj +OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj +OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/zlib/contrib/pascal/zlibpas.pas b/zlib/contrib/pascal/zlibpas.pas new file mode 100644 index 0000000..fc89ef8 --- /dev/null +++ b/zlib/contrib/pascal/zlibpas.pas @@ -0,0 +1,236 @@ +(* zlibpas -- Pascal interface to the zlib data compression library + * + * Copyright (C) 2003 Cosmin Truta. + * Derived from original sources by Bob Dellaca. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +unit zlibpas; + +interface + +const + ZLIB_VERSION = '1.2.1'; + +type + alloc_func = function(opaque: Pointer; items, size: Integer): Pointer; + cdecl; + free_func = procedure(opaque, address: Pointer); + cdecl; + + in_func = function(opaque: Pointer; var buf: PByte): Integer; + cdecl; + out_func = function(opaque: Pointer; buf: PByte; size: Integer): Integer; + cdecl; + + z_streamp = ^z_stream; + z_stream = packed record + next_in: PChar; (* next input byte *) + avail_in: Integer; (* number of bytes available at next_in *) + total_in: LongInt; (* total nb of input bytes read so far *) + + next_out: PChar; (* next output byte should be put there *) + avail_out: Integer; (* remaining free space at next_out *) + total_out: LongInt; (* total nb of bytes output so far *) + + msg: PChar; (* last error message, NULL if no error *) + state: Pointer; (* not visible by applications *) + + zalloc: alloc_func; (* used to allocate the internal state *) + zfree: free_func; (* used to free the internal state *) + opaque: Pointer; (* private data object passed to zalloc and zfree *) + + data_type: Integer; (* best guess about the data type: ascii or binary *) + adler: LongInt; (* adler32 value of the uncompressed data *) + reserved: LongInt; (* reserved for future use *) + end; + +(* constants *) +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = -1; + Z_STREAM_ERROR = -2; + Z_DATA_ERROR = -3; + Z_MEM_ERROR = -4; + Z_BUF_ERROR = -5; + Z_VERSION_ERROR = -6; + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = -1; + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + +(* basic functions *) +function zlibVersion: PChar; +function deflateInit(var strm: z_stream; level: Integer): Integer; +function deflate(var strm: z_stream; flush: Integer): Integer; +function deflateEnd(var strm: z_stream): Integer; +function inflateInit(var strm: z_stream): Integer; +function inflate(var strm: z_stream; flush: Integer): Integer; +function inflateEnd(var strm: z_stream): Integer; + +(* advanced functions *) +function deflateInit2(var strm: z_stream; level, method, windowBits, + memLevel, strategy: Integer): Integer; +function deflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function deflateCopy(var dest, source: z_stream): Integer; +function deflateReset(var strm: z_stream): Integer; +function deflateParams(var strm: z_stream; level, strategy: Integer): Integer; +function deflateBound(var strm: z_stream; sourceLen: LongInt): LongInt; +function deflatePrime(var strm: z_stream; bits, value: Integer): Integer; +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +function inflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function inflateSync(var strm: z_stream): Integer; +function inflateCopy(var dest, source: z_stream): Integer; +function inflateReset(var strm: z_stream): Integer; +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +function inflateBack(var strm: z_stream; in_fn: in_func; in_desc: Pointer; + out_fn: out_func; out_desc: Pointer): Integer; +function inflateBackEnd(var strm: z_stream): Integer; +function zlibCompileFlags: LongInt; + +(* utility functions *) +function compress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; +function compress2(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt; + level: Integer): Integer; +function compressBound(sourceLen: LongInt): LongInt; +function uncompress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; + +(* checksum functions *) +function adler32(adler: LongInt; const buf: PChar; len: Integer): LongInt; +function crc32(crc: LongInt; const buf: PChar; len: Integer): LongInt; + +(* various hacks, don't look :) *) +function deflateInit_(var strm: z_stream; level: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit_(var strm: z_stream; const version: PChar; + stream_size: Integer): Integer; +function deflateInit2_(var strm: z_stream; + level, method, windowBits, memLevel, strategy: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit2_(var strm: z_stream; windowBits: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateBackInit_(var strm: z_stream; + windowBits: Integer; window: PChar; + const version: PChar; stream_size: Integer): Integer; + + +implementation + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +function adler32; external; +function compress; external; +function compress2; external; +function compressBound; external; +function crc32; external; +function deflate; external; +function deflateBound; external; +function deflateCopy; external; +function deflateEnd; external; +function deflateInit_; external; +function deflateInit2_; external; +function deflateParams; external; +function deflatePrime; external; +function deflateReset; external; +function deflateSetDictionary; external; +function inflate; external; +function inflateBack; external; +function inflateBackEnd; external; +function inflateBackInit_; external; +function inflateCopy; external; +function inflateEnd; external; +function inflateInit_; external; +function inflateInit2_; external; +function inflateReset; external; +function inflateSetDictionary; external; +function inflateSync; external; +function uncompress; external; +function zlibCompileFlags; external; +function zlibVersion; external; + +function deflateInit(var strm: z_stream; level: Integer): Integer; +begin + Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream)); +end; + +function deflateInit2(var strm: z_stream; level, method, windowBits, memLevel, + strategy: Integer): Integer; +begin + Result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit(var strm: z_stream): Integer; +begin + Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +begin + Result := inflateInit2_(strm, windowBits, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +begin + Result := inflateBackInit_(strm, windowBits, window, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + GetMem(Result, Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + +end. diff --git a/zlib/contrib/puff/Makefile b/zlib/contrib/puff/Makefile new file mode 100644 index 0000000..0c6c7b9 --- /dev/null +++ b/zlib/contrib/puff/Makefile @@ -0,0 +1,8 @@ +puff: puff.c puff.h + cc -DTEST -o puff puff.c + +test: puff + puff zeros.raw + +clean: + rm -f puff puff.o diff --git a/zlib/contrib/puff/README b/zlib/contrib/puff/README new file mode 100644 index 0000000..1dbbc21 --- /dev/null +++ b/zlib/contrib/puff/README @@ -0,0 +1,63 @@ +Puff -- A Simple Inflate +3 Mar 2003 +Mark Adler +madler@alumni.caltech.edu + +What this is -- + +puff.c provides the routine puff() to decompress the deflate data format. It +does so more slowly than zlib, but the code is about one-fifth the size of the +inflate code in zlib, and written to be very easy to read. + +Why I wrote this -- + +puff.c was written to document the deflate format unambiguously, by virtue of +being working C code. It is meant to supplement RFC 1951, which formally +describes the deflate format. I have received many questions on details of the +deflate format, and I hope that reading this code will answer those questions. +puff.c is heavily commented with details of the deflate format, especially +those little nooks and cranies of the format that might not be obvious from a +specification. + +puff.c may also be useful in applications where code size or memory usage is a +very limited resource, and speed is not as important. + +How to use it -- + +Well, most likely you should just be reading puff.c and using zlib for actual +applications, but if you must ... + +Include puff.h in your code, which provides this prototype: + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ + +Then you can call puff() to decompress a deflate stream that is in memory in +its entirety at source, to a sufficiently sized block of memory for the +decompressed data at dest. puff() is the only external symbol in puff.c The +only C library functions that puff.c needs are setjmp() and longjmp(), which +are used to simplify error checking in the code to improve readabilty. puff.c +does no memory allocation, and uses less than 2K bytes off of the stack. + +If destlen is not enough space for the uncompressed data, then inflate will +return an error without writing more than destlen bytes. Note that this means +that in order to decompress the deflate data successfully, you need to know +the size of the uncompressed data ahead of time. + +If needed, puff() can determine the size of the uncompressed data with no +output space. This is done by passing dest equal to (unsigned char *)0. Then +the initial value of *destlen is ignored and *destlen is set to the length of +the uncompressed data. So if the size of the uncompressed data is not known, +then two passes of puff() can be used--first to determine the size, and second +to do the actual inflation after allocating the appropriate memory. Not +pretty, but it works. (This is one of the reasons you should be using zlib.) + +The deflate format is self-terminating. If the deflate stream does not end +in *sourcelen bytes, puff() will return an error without reading at or past +endsource. + +On return, *sourcelen is updated to the amount of input data consumed, and +*destlen is updated to the size of the uncompressed data. See the comments +in puff.c for the possible return codes for puff(). diff --git a/zlib/contrib/puff/puff.c b/zlib/contrib/puff/puff.c new file mode 100644 index 0000000..f1e09d6 --- /dev/null +++ b/zlib/contrib/puff/puff.c @@ -0,0 +1,833 @@ +/* + * puff.c + * Copyright (C) 2002, 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 1.7, 3 Mar 2003 + * + * puff.c is a simple inflate written to be an unambiguous way to specify the + * deflate format. It is not written for speed but rather simplicity. As a + * side benefit, this code might actually be useful when small code is more + * important than speed, such as bootstrap applications. For typical deflate + * data, zlib's inflate() is about four times as fast as puff(). zlib's + * inflate compiles to around 20K on my machine, whereas puff.c compiles to + * around 4K on my machine (a PowerPC using GNU cc). If the faster decode() + * function here is used, then puff() is only twice as slow as zlib's + * inflate(). + * + * All dynamically allocated memory comes from the stack. The stack required + * is less than 2K bytes. This code is compatible with 16-bit int's and + * assumes that long's are at least 32 bits. puff.c uses the short data type, + * assumed to be 16 bits, for arrays in order to to conserve memory. The code + * works whether integers are stored big endian or little endian. + * + * In the comments below are "Format notes" that describe the inflate process + * and document some of the less obvious aspects of the format. This source + * code is meant to supplement RFC 1951, which formally describes the deflate + * format: + * + * http://www.zlib.org/rfc-deflate.html + */ + +/* + * Change history: + * + * 1.0 10 Feb 2002 - First version + * 1.1 17 Feb 2002 - Clarifications of some comments and notes + * - Update puff() dest and source pointers on negative + * errors to facilitate debugging deflators + * - Remove longest from struct huffman -- not needed + * - Simplify offs[] index in construct() + * - Add input size and checking, using longjmp() to + * maintain easy readability + * - Use short data type for large arrays + * - Use pointers instead of long to specify source and + * destination sizes to avoid arbitrary 4 GB limits + * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), + * but leave simple version for readabilty + * - Make sure invalid distances detected if pointers + * are 16 bits + * - Fix fixed codes table error + * - Provide a scanning mode for determining size of + * uncompressed data + * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup] + * - Add a puff.h file for the interface + * - Add braces in puff() for else do [Jean-loup] + * - Use indexes instead of pointers for readability + * 1.4 31 Mar 2002 - Simplify construct() code set check + * - Fix some comments + * - Add FIXLCODES #define + * 1.5 6 Apr 2002 - Minor comment fixes + * 1.6 7 Aug 2002 - Minor format changes + * 1.7 3 Mar 2003 - Added test code for distribution + * - Added zlib-like license + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "puff.h" /* prototype for puff() */ + +#define local static /* for local function definitions */ +#define NIL ((unsigned char *)0) /* for no output option */ + +/* + * Maximums for allocations and loops. It is not useful to change these -- + * they are fixed by the deflate format. + */ +#define MAXBITS 15 /* maximum bits in a code */ +#define MAXLCODES 286 /* maximum number of literal/length codes */ +#define MAXDCODES 30 /* maximum number of distance codes */ +#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ +#define FIXLCODES 288 /* number of fixed literal/length codes */ + +/* input and output state */ +struct state { + /* output state */ + unsigned char *out; /* output buffer */ + unsigned long outlen; /* available space at out */ + unsigned long outcnt; /* bytes written to out so far */ + + /* input state */ + unsigned char *in; /* input buffer */ + unsigned long inlen; /* available input at in */ + unsigned long incnt; /* bytes read so far */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + long val; /* bit accumulator (can use up to 20 bits) */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ + val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = (int)(val >> need); + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return (int)(val & ((1L << need) - 1)); +} + +/* + * Process a stored block. + * + * Format notes: + * + * - After the two-bit stored block type (00), the stored block length and + * stored bytes are byte-aligned for fast copying. Therefore any leftover + * bits in the byte that has the last bit of the type, as many as seven, are + * discarded. The value of the discarded bits are not defined and should not + * be checked against any expectation. + * + * - The second inverted copy of the stored block length does not have to be + * checked, but it's probably a good idea to do so anyway. + * + * - A stored block can have zero length. This is sometimes used to byte-align + * subsets of the compressed data for random access or partial recovery. + */ +local int stored(struct state *s) +{ + unsigned len; /* length of stored block */ + + /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ + s->bitbuf = 0; + s->bitcnt = 0; + + /* get length and check against its one's complement */ + if (s->incnt + 4 > s->inlen) return 2; /* not enough input */ + len = s->in[s->incnt++]; + len |= s->in[s->incnt++] << 8; + if (s->in[s->incnt++] != (~len & 0xff) || + s->in[s->incnt++] != ((~len >> 8) & 0xff)) + return -2; /* didn't match complement! */ + + /* copy len bytes from in to out */ + if (s->incnt + len > s->inlen) return 2; /* not enough input */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; /* not enough output space */ + while (len--) + s->out[s->outcnt++] = s->in[s->incnt++]; + } + else { /* just scanning */ + s->outcnt += len; + s->incnt += len; + } + + /* done with a valid stored block */ + return 0; +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. A table-based decoding + * scheme (as used in zlib) does not need to do this reversal. + * + * - The first code for the shortest length is all zeros. Subsequent codes of + * the same length are simply integer increments of the previous code. When + * moving up a length, a zero bit is appended to the code. For a complete + * code, the last code of the longest length will be all ones. + * + * - Incomplete codes are handled by this decoder, since they are permitted + * in the deflate format. See the format notes for fixed() and dynamic(). + */ +#ifdef SLOW +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + + code = first = index = 0; + for (len = 1; len <= MAXBITS; len++) { + code |= bits(s, 1); /* get next bit */ + count = h->count[len]; + if (code < first + count) /* if length len, return symbol */ + return h->symbol[index + (code - first)]; + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + } + return -9; /* ran out of codes */ +} + +/* + * A faster version of decode() for real applications of this code. It's not + * as readable, but it makes puff() twice as fast. And it only makes the code + * a few percent larger. + */ +#else /* !SLOW */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= bitbuf & 1; + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ + bitbuf = s->in[s->incnt++]; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} +#endif /* SLOW */ + +/* + * Given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + * + * Not used by decode(), but used for error checking, h->count[0] is the number + * of the n symbols not in the code. So n - h->count[0] is the number of + * codes. This is useful for checking for incomplete codes that have more than + * one symbol, which is an error in a dynamic block. + * + * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS + * This is assured by the construction of the length arrays in dynamic() and + * fixed() and is not verified by construct(). + * + * Format notes: + * + * - Permitted and expected examples of incomplete codes are one of the fixed + * codes and any code with a single symbol which in deflate is coded as one + * bit instead of zero bits. See the format notes for fixed() and dynamic(). + * + * - Within a given code length, the symbols are kept in ascending order for + * the code bits definition. + */ +local int construct(struct huffman *h, short *length, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode literal/length and distance codes until an end-of-block code. + * + * Format notes: + * + * - Compressed data that is after the block type if fixed or after the code + * description if dynamic is a combination of literals and length/distance + * pairs terminated by and end-of-block code. Literals are simply Huffman + * coded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - Literals, lengths, and the end-of-block code are combined into a single + * code of up to 286 symbols. They are 256 literals (0..255), 29 length + * symbols (257..285), and the end-of-block symbol (256). + * + * - There are 256 possible lengths (3..258), and so 29 symbols are not enough + * to represent all of those. Lengths 3..10 and 258 are in fact represented + * by just a length symbol. Lengths 11..257 are represented as a symbol and + * some number of extra bits that are added as an integer to the base length + * of the length symbol. The number of extra bits is determined by the base + * length symbol. These are in the static arrays below, lens[] for the base + * lengths and lext[] for the corresponding number of extra bits. + * + * - The reason that 258 gets its own symbol is that the longest length is used + * often in highly redundant files. Note that 258 can also be coded as the + * base value 227 plus the maximum extra value of 31. While a good deflate + * should never do this, it is not an error, and should be decoded properly. + * + * - If a length is decoded, including its extra bits if any, then it is + * followed a distance code. There are up to 30 distance symbols. Again + * there are many more possible distances (1..32768), so extra bits are added + * to a base value represented by the symbol. The distances 1..4 get their + * own symbol, but the rest require extra bits. The base distances and + * corresponding number of extra bits are below in the static arrays dist[] + * and dext[]. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 258 + * simply copies the last byte 258 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. You should not use memcpy() since its behavior is not + * defined for overlapped arrays. You should not use memmove() or bcopy() + * since though their behavior -is- defined for overlapping arrays, it is + * defined to do the wrong thing in this case. + */ +local int codes(struct state *s, + struct huffman *lencode, + struct huffman *distcode) +{ + int symbol; /* decoded symbol */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + static const short lens[29] = { /* Size base for length codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const short lext[29] = { /* Extra bits for length codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const short dists[30] = { /* Offset base for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const short dext[30] = { /* Extra bits for distance codes 0..29 */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + /* decode literals and length/distance pairs */ + do { + symbol = decode(s, lencode); + if (symbol < 0) return symbol; /* invalid symbol */ + if (symbol < 256) { /* literal: symbol is the byte */ + /* write out the literal */ + if (s->out != NIL) { + if (s->outcnt == s->outlen) return 1; + s->out[s->outcnt] = symbol; + } + s->outcnt++; + } + else if (symbol > 256) { /* length */ + /* get and compute length */ + symbol -= 257; + if (symbol >= 29) return -9; /* invalid fixed code */ + len = lens[symbol] + bits(s, lext[symbol]); + + /* get and check distance */ + symbol = decode(s, distcode); + if (symbol < 0) return symbol; /* invalid symbol */ + dist = dists[symbol] + bits(s, dext[symbol]); + if (dist > s->outcnt) + return -10; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) return 1; + while (len--) { + s->out[s->outcnt] = s->out[s->outcnt - dist]; + s->outcnt++; + } + } + else + s->outcnt += len; + } + } while (symbol != 256); /* end of block symbol */ + + /* done with a valid fixed or dynamic block */ + return 0; +} + +/* + * Process a fixed codes block. + * + * Format notes: + * + * - This block type can be useful for compressing small amounts of data for + * which the size of the code descriptions in a dynamic block exceeds the + * benefit of custom codes for that block. For fixed codes, no bits are + * spent on code descriptions. Instead the code lengths for literal/length + * codes and distance codes are fixed. The specific lengths for each symbol + * can be seen in the "for" loops below. + * + * - The literal/length code is complete, but has two symbols that are invalid + * and should result in an error if received. This cannot be implemented + * simply as an incomplete code since those two symbols are in the "middle" + * of the code. They are eight bits long and the longest literal/length\ + * code is nine bits. Therefore the code must be constructed with those + * symbols, and the invalid symbols must be detected after decoding. + * + * - The fixed distance codes also have two invalid symbols that should result + * in an error if received. Since all of the distance codes are the same + * length, this can be implemented as an incomplete code. Then the invalid + * codes are detected while decoding. + */ +local int fixed(struct state *s) +{ + static int virgin = 1; + static short lencnt[MAXBITS+1], lensym[FIXLCODES]; + static short distcnt[MAXBITS+1], distsym[MAXDCODES]; + static struct huffman lencode = {lencnt, lensym}; + static struct huffman distcode = {distcnt, distsym}; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + int symbol; + short lengths[FIXLCODES]; + + /* literal/length table */ + for (symbol = 0; symbol < 144; symbol++) + lengths[symbol] = 8; + for (; symbol < 256; symbol++) + lengths[symbol] = 9; + for (; symbol < 280; symbol++) + lengths[symbol] = 7; + for (; symbol < FIXLCODES; symbol++) + lengths[symbol] = 8; + construct(&lencode, lengths, FIXLCODES); + + /* distance table */ + for (symbol = 0; symbol < MAXDCODES; symbol++) + lengths[symbol] = 5; + construct(&distcode, lengths, MAXDCODES); + + /* do this just once */ + virgin = 0; + } + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Process a dynamic codes block. + * + * Format notes: + * + * - A dynamic block starts with a description of the literal/length and + * distance codes for that block. New dynamic blocks allow the compressor to + * rapidly adapt to changing data with new codes optimized for that data. + * + * - The codes used by the deflate format are "canonical", which means that + * the actual bits of the codes are generated in an unambiguous way simply + * from the number of bits in each code. Therefore the code descriptions + * are simply a list of code lengths for each symbol. + * + * - The code lengths are stored in order for the symbols, so lengths are + * provided for each of the literal/length symbols, and for each of the + * distance symbols. + * + * - If a symbol is not used in the block, this is represented by a zero as + * as the code length. This does not mean a zero-length code, but rather + * that no code should be created for this symbol. There is no way in the + * deflate format to represent a zero-length code. + * + * - The maximum number of bits in a code is 15, so the possible lengths for + * any code are 1..15. + * + * - The fact that a length of zero is not permitted for a code has an + * interesting consequence. Normally if only one symbol is used for a given + * code, then in fact that code could be represented with zero bits. However + * in deflate, that code has to be at least one bit. So for example, if + * only a single distance base symbol appears in a block, then it will be + * represented by a single code of length one, in particular one 0 bit. This + * is an incomplete code, since if a 1 bit is received, it has no meaning, + * and should result in an error. So incomplete distance codes of one symbol + * should be permitted, and the receipt of invalid codes should be handled. + * + * - It is also possible to have a single literal/length code, but that code + * must be the end-of-block code, since every dynamic block has one. This + * is not the most efficient way to create an empty block (an empty fixed + * block is fewer bits), but it is allowed by the format. So incomplete + * literal/length codes of one symbol should also be permitted. + * + * - The list of up to 286 length/literal lengths and up to 30 distance lengths + * are themselves compressed using Huffman codes and run-length encoding. In + * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means + * that length, and the symbols 16, 17, and 18 are run-length instructions. + * Each of 16, 17, and 18 are follwed by extra bits to define the length of + * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 + * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols + * are common, hence the special coding for zero lengths. + * + * - The symbols for 0..18 are Huffman coded, and so that code must be + * described first. This is simply a sequence of up to 19 three-bit values + * representing no code (0) or the code length for that symbol (1..7). + * + * - A dynamic block starts with three fixed-size counts from which is computed + * the number of literal/length code lengths, the number of distance code + * lengths, and the number of code length code lengths (ok, you come up with + * a better name!) in the code descriptions. For the literal/length and + * distance codes, lengths after those provided are considered zero, i.e. no + * code. The code length code lengths are received in a permuted order (see + * the order[] array below) to make a short code length code length list more + * likely. As it turns out, very short and very long codes are less likely + * to be seen in a dynamic code description, hence what may appear initially + * to be a peculiar ordering. + * + * - Given the number of literal/length code lengths (nlen) and distance code + * lengths (ndist), then they are treated as one long list of nlen + ndist + * code lengths. Therefore run-length coding can and often does cross the + * boundary between the two sets of lengths. + * + * - So to summarize, the code description at the start of a dynamic block is + * three counts for the number of code lengths for the literal/length codes, + * the distance codes, and the code length codes. This is followed by the + * code length code lengths, three bits each. This is used to construct the + * code length code which is used to read the remainder of the lengths. Then + * the literal/length code lengths and distance lengths are read as a single + * set of lengths using the code length codes. Codes are constructed from + * the resulting two sets of lengths, and then finally you can start + * decoding actual compressed data in the block. + * + * - For reference, a "typical" size for the code description in a dynamic + * block is around 80 bytes. + */ +local int dynamic(struct state *s) +{ + int nlen, ndist, ncode; /* number of lengths in descriptor */ + int index; /* index of lengths[] */ + int err; /* construct() return value */ + short lengths[MAXCODES]; /* descriptor code lengths */ + short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ + short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ + struct huffman lencode = {lencnt, lensym}; /* length code */ + struct huffman distcode = {distcnt, distsym}; /* distance code */ + static const short order[19] = /* permutation of code length codes */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* get number of lengths in each table, check lengths */ + nlen = bits(s, 5) + 257; + ndist = bits(s, 5) + 1; + ncode = bits(s, 4) + 4; + if (nlen > MAXLCODES || ndist > MAXDCODES) + return -3; /* bad counts */ + + /* read code length code lengths (really), missing lengths are zero */ + for (index = 0; index < ncode; index++) + lengths[order[index]] = bits(s, 3); + for (; index < 19; index++) + lengths[order[index]] = 0; + + /* build huffman table for code lengths codes (use lencode temporarily) */ + err = construct(&lencode, lengths, 19); + if (err != 0) return -4; /* require complete code set here */ + + /* read length/literal and distance code length tables */ + index = 0; + while (index < nlen + ndist) { + int symbol; /* decoded value */ + int len; /* last length to repeat */ + + symbol = decode(s, &lencode); + if (symbol < 16) /* length in 0..15 */ + lengths[index++] = symbol; + else { /* repeat instruction */ + len = 0; /* assume repeating zeros */ + if (symbol == 16) { /* repeat last length 3..6 times */ + if (index == 0) return -5; /* no last length! */ + len = lengths[index - 1]; /* last length */ + symbol = 3 + bits(s, 2); + } + else if (symbol == 17) /* repeat zero 3..10 times */ + symbol = 3 + bits(s, 3); + else /* == 18, repeat zero 11..138 times */ + symbol = 11 + bits(s, 7); + if (index + symbol > nlen + ndist) + return -6; /* too many lengths! */ + while (symbol--) /* repeat last or zero symbol times */ + lengths[index++] = len; + } + } + + /* build huffman table for literal/length codes */ + err = construct(&lencode, lengths, nlen); + if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) + return -7; /* only allow incomplete codes if just one code */ + + /* build huffman table for distance codes */ + err = construct(&distcode, lengths + nlen, ndist); + if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) + return -8; /* only allow incomplete codes if just one code */ + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Inflate source to dest. On return, destlen and sourcelen are updated to the + * size of the uncompressed data and the size of the deflate data respectively. + * On success, the return value of puff() is zero. If there is an error in the + * source data, i.e. it is not in the deflate format, then a negative value is + * returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. In that case, destlen and + * sourcelen are not updated to facilitate retrying from the beginning with the + * provision of more input data or more output space. In the case of invalid + * inflate data (a negative error), the dest and source pointers are updated to + * facilitate the debugging of deflators. + * + * puff() also has a mode to determine the size of the uncompressed output with + * no output written. For this dest must be (unsigned char *)0. In this case, + * the input value of *destlen is ignored, and on return *destlen is set to the + * size of the uncompressed output. + * + * The return codes are: + * + * 2: available inflate data did not terminate + * 1: output space exhausted before completing inflate + * 0: successful inflate + * -1: invalid block type (type == 3) + * -2: stored block length did not match one's complement + * -3: dynamic block code description: too many length or distance codes + * -4: dynamic block code description: code lengths codes incomplete + * -5: dynamic block code description: repeat lengths with no first length + * -6: dynamic block code description: repeat more than specified lengths + * -7: dynamic block code description: invalid literal/length code lengths + * -8: dynamic block code description: invalid distance code lengths + * -9: invalid literal/length or distance code in fixed or dynamic block + * -10: distance is too far back in fixed or dynamic block + * + * Format notes: + * + * - Three bits are read for each block to determine the kind of block and + * whether or not it is the last block. Then the block is decoded and the + * process repeated if it was not the last block. + * + * - The leftover bits in the last byte of the deflate data after the last + * block (if it was a fixed or dynamic block) are undefined and have no + * expected values to check. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen) /* amount of input available */ +{ + struct state s; /* input/output state */ + int last, type; /* block information */ + int err; /* return value */ + + /* initialize output state */ + s.out = dest; + s.outlen = *destlen; /* ignored if dest is NIL */ + s.outcnt = 0; + + /* initialize input state */ + s.in = source; + s.inlen = *sourcelen; + s.incnt = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp() */ + err = 2; /* then skip do-loop, return error */ + else { + /* process blocks until last block or error */ + do { + last = bits(&s, 1); /* one if last block */ + type = bits(&s, 2); /* block type 0..3 */ + err = type == 0 ? stored(&s) : + (type == 1 ? fixed(&s) : + (type == 2 ? dynamic(&s) : + -1)); /* type == 3, invalid */ + if (err != 0) break; /* return with error */ + } while (!last); + } + + /* update the lengths and return */ + if (err <= 0) { + *destlen = s.outcnt; + *sourcelen = s.incnt; + } + return err; +} + +#ifdef TEST +/* Example of how to use puff() */ +#include +#include +#include +#include + +local unsigned char *yank(char *name, unsigned long *len) +{ + unsigned long size; + unsigned char *buf; + FILE *in; + struct stat s; + + *len = 0; + if (stat(name, &s)) return NULL; + if ((s.st_mode & S_IFMT) != S_IFREG) return NULL; + size = (unsigned long)(s.st_size); + if (size == 0 || (off_t)size != s.st_size) return NULL; + in = fopen(name, "r"); + if (in == NULL) return NULL; + buf = malloc(size); + if (buf != NULL && fread(buf, 1, size, in) != size) { + free(buf); + buf = NULL; + } + fclose(in); + *len = size; + return buf; +} + +int main(int argc, char **argv) +{ + int ret; + unsigned char *source; + unsigned long len, sourcelen, destlen; + + if (argc < 2) return 2; + source = yank(argv[1], &len); + if (source == NULL) return 2; + sourcelen = len; + ret = puff(NIL, &destlen, source, &sourcelen); + if (ret) + printf("puff() failed with return code %d\n", ret); + else { + printf("puff() succeeded uncompressing %lu bytes\n", destlen); + if (sourcelen < len) printf("%lu compressed bytes unused\n", + len - sourcelen); + } + free(source); + return ret; +} +#endif diff --git a/zlib/contrib/puff/puff.h b/zlib/contrib/puff/puff.h new file mode 100644 index 0000000..4d5bdc7 --- /dev/null +++ b/zlib/contrib/puff/puff.h @@ -0,0 +1,31 @@ +/* puff.h + Copyright (C) 2002, 2003 Mark Adler, all rights reserved + version 1.7, 3 Mar 2002 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * See puff.c for purpose and usage. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ diff --git a/zlib/contrib/puff/zeros.raw b/zlib/contrib/puff/zeros.raw new file mode 100644 index 0000000..637b7be Binary files /dev/null and b/zlib/contrib/puff/zeros.raw differ diff --git a/zlib/contrib/testzlib/testzlib.c b/zlib/contrib/testzlib/testzlib.c new file mode 100644 index 0000000..caae4ef --- /dev/null +++ b/zlib/contrib/testzlib/testzlib.c @@ -0,0 +1,149 @@ + +#include +#include +#include +#include "zlib.h" + +int ReadFileMemory(const char* filename,long* plFileSize,void** pFilePtr) +{ + FILE* stream; + void* ptr; + int retVal=1; + stream=fopen(filename, "rb"); + if (stream==NULL) + return 0; + + fseek(stream,0,SEEK_END); + + *plFileSize=ftell(stream); + fseek(stream,0,SEEK_SET); + ptr=malloc((*plFileSize)+1); + if (ptr==NULL) + retVal=0; + else + { + if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize)) + retVal=0; + } + fclose(stream); + *pFilePtr=ptr; + return retVal; +} + +int main(int argc, char *argv[]) +{ + int BlockSizeCompress=0x8000; + int BlockSizeUncompress=0x8000; + int cprLevel=Z_DEFAULT_COMPRESSION ; + long lFileSize; + unsigned char* FilePtr; + long lBufferSizeCpr; + long lBufferSizeUncpr; + long lCompressedSize=0; + unsigned char* CprPtr; + unsigned char* UncprPtr; + long lSizeCpr,lSizeUncpr; + DWORD dwGetTick; + + if (argc<=1) + { + printf("run TestZlib [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n"); + return 0; + } + + if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) + { + printf("error reading %s\n",argv[1]); + return 1; + } + else printf("file %s read, %u bytes\n",argv[1],lFileSize); + + if (argc>=3) + BlockSizeCompress=atol(argv[2]); + + if (argc>=4) + BlockSizeUncompress=atol(argv[3]); + + if (argc>=5) + cprLevel=(int)atol(argv[4]); + + lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200; + lBufferSizeUncpr = lBufferSizeCpr; + + CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress); + UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress); + + dwGetTick=GetTickCount(); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lFileSize; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + deflateInit(&zcpr,cprLevel); + + zcpr.next_in = FilePtr; + zcpr.next_out = CprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeCompress); + zcpr.avail_out = BlockSizeCompress; + ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeCpr=zcpr.total_out; + deflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + printf("total compress size = %u, in %u step\n",lSizeCpr,step); + printf("time = %u msec = %f sec\n\n",dwGetTick,dwGetTick/(double)1000.); + } + + dwGetTick=GetTickCount(); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lSizeCpr; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + inflateInit(&zcpr); + + zcpr.next_in = CprPtr; + zcpr.next_out = UncprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress); + zcpr.avail_out = BlockSizeUncompress; + ret=inflate(&zcpr,Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeUncpr=zcpr.total_out; + inflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step); + printf("time = %u msec = %f sec\n\n",dwGetTick,dwGetTick/(double)1000.); + } + + if (lSizeUncpr==lFileSize) + { + if (memcmp(FilePtr,UncprPtr,lFileSize)==0) + printf("compare ok\n"); + + } + + return 0; + +} diff --git a/zlib/contrib/testzlib/testzlib.sln b/zlib/contrib/testzlib/testzlib.sln new file mode 100644 index 0000000..86da716 --- /dev/null +++ b/zlib/contrib/testzlib/testzlib.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/zlib/contrib/testzlib/testzlib.vcproj b/zlib/contrib/testzlib/testzlib.vcproj new file mode 100644 index 0000000..bd9b39b --- /dev/null +++ b/zlib/contrib/testzlib/testzlib.vcproj @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zlib/contrib/untgz/Makefile b/zlib/contrib/untgz/Makefile new file mode 100644 index 0000000..8fd12a0 --- /dev/null +++ b/zlib/contrib/untgz/Makefile @@ -0,0 +1,14 @@ +CC=cc +CFLAGS=-g + +untgz: untgz.o ../../libz.a + $(CC) $(CFLAGS) -o untgz untgz.o -L../.. -lz + +untgz.o: untgz.c ../../zlib.h + $(CC) $(CFLAGS) -c -I../.. untgz.c + +../../libz.a: + cd ../..; ./configure; make + +clean: + rm -f untgz untgz.o *~ diff --git a/zlib/contrib/untgz/Makefile.msc b/zlib/contrib/untgz/Makefile.msc new file mode 100644 index 0000000..786779a --- /dev/null +++ b/zlib/contrib/untgz/Makefile.msc @@ -0,0 +1,17 @@ +CC=cl +CFLAGS=-MD + +untgz.exe: untgz.obj ..\..\zlib.lib + $(CC) $(CFLAGS) untgz.obj ..\..\zlib.lib + +untgz.obj: untgz.c ..\..\zlib.h + $(CC) $(CFLAGS) -c -I..\.. untgz.c + +..\..\zlib.lib: + cd ..\.. + $(MAKE) -f win32\makefile.msc + cd contrib\untgz + +clean: + -del untgz.obj + -del untgz.exe diff --git a/zlib/contrib/untgz/untgz.c b/zlib/contrib/untgz/untgz.c new file mode 100644 index 0000000..49fda21 --- /dev/null +++ b/zlib/contrib/untgz/untgz.c @@ -0,0 +1,569 @@ +/* + * untgz.c -- Display contents and extract files from a gzip'd TAR file + * + * written by "Pedro A. Aranda Guti\irrez" + * adaptation to Unix by Jean-loup Gailly + * various fixes by Cosmin Truta + */ + +#include +#include +#include +#include +#include + +#include "zlib.h" + +#ifdef unix +# include +#else +# include +# include +#endif + +#ifdef WIN32 +#include +# ifndef F_OK +# define F_OK 0 +# endif +# define mkdir(dirname,mode) _mkdir(dirname) +# ifdef _MSC_VER +# define strdup(str) _strdup(str) +# define access(path,mode) _access(path,mode) +# endif +#else +# include +#endif + + +/* values used in typeflag field */ + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved */ + +#define BLOCKSIZE 512 + +struct tar_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +union tar_buffer { + char buffer[BLOCKSIZE]; + struct tar_header header; +}; + +enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; + +char *TGZfname OF((const char *)); +void TGZnotfound OF((const char *)); + +int getoct OF((char *, int)); +char *strtime OF((time_t *)); +int setfiletime OF((char *, time_t)); +int ExprMatch OF((char *, char *)); + +int makedir OF((char *)); +int matchname OF((int, int, char **, char *)); + +void error OF((const char *)); +int tar OF((gzFile, int, int, int, char **)); + +void help OF((int)); +int main OF((int, char **)); + +char *prog; + +const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL }; + +/* return the file name of the TGZ archive */ +/* or NULL if it does not exist */ + +char *TGZfname (const char *arcname) +{ + static char buffer[1024]; + int origlen,i; + + strcpy(buffer,arcname); + origlen = strlen(buffer); + + for (i=0; TGZsuffix[i]; i++) + { + strcpy(buffer+origlen,TGZsuffix[i]); + if (access(buffer,F_OK) == 0) + return buffer; + } + return NULL; +} + + +/* error message for the filename */ + +void TGZnotfound (const char *arcname) +{ + int i; + + fprintf(stderr,"%s: Couldn't find ",prog); + for (i=0;TGZsuffix[i];i++) + fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n", + arcname, + TGZsuffix[i]); + exit(1); +} + + +/* convert octal digits to int */ +/* on error return -1 */ + +int getoct (char *p,int width) +{ + int result = 0; + char c; + + while (width--) + { + c = *p++; + if (c == 0) + break; + if (c == ' ') + continue; + if (c < '0' || c > '7') + return -1; + result = result * 8 + (c - '0'); + } + return result; +} + + +/* convert time_t to string */ +/* use the "YYYY/MM/DD hh:mm:ss" format */ + +char *strtime (time_t *t) +{ + struct tm *local; + static char result[32]; + + local = localtime(t); + sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d", + local->tm_year+1900, local->tm_mon+1, local->tm_mday, + local->tm_hour, local->tm_min, local->tm_sec); + return result; +} + + +/* set file time */ + +int setfiletime (char *fname,time_t ftime) +{ +#ifdef WIN32 + static int isWinNT = -1; + SYSTEMTIME st; + FILETIME locft, modft; + struct tm *loctm; + HANDLE hFile; + int result; + + loctm = localtime(&ftime); + if (loctm == NULL) + return -1; + + st.wYear = (WORD)loctm->tm_year + 1900; + st.wMonth = (WORD)loctm->tm_mon + 1; + st.wDayOfWeek = (WORD)loctm->tm_wday; + st.wDay = (WORD)loctm->tm_mday; + st.wHour = (WORD)loctm->tm_hour; + st.wMinute = (WORD)loctm->tm_min; + st.wSecond = (WORD)loctm->tm_sec; + st.wMilliseconds = 0; + if (!SystemTimeToFileTime(&st, &locft) || + !LocalFileTimeToFileTime(&locft, &modft)) + return -1; + + if (isWinNT < 0) + isWinNT = (GetVersion() < 0x80000000) ? 1 : 0; + hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0), + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1; + CloseHandle(hFile); + return result; +#else + struct utimbuf settime; + + settime.actime = settime.modtime = ftime; + return utime(fname,&settime); +#endif +} + + +/* regular expression matching */ + +#define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) + +int ExprMatch (char *string,char *expr) +{ + while (1) + { + if (ISSPECIAL(*expr)) + { + if (*expr == '/') + { + if (*string != '\\' && *string != '/') + return 0; + string ++; expr++; + } + else if (*expr == '*') + { + if (*expr ++ == 0) + return 1; + while (*++string != *expr) + if (*string == 0) + return 0; + } + } + else + { + if (*string != *expr) + return 0; + if (*expr++ == 0) + return 1; + string++; + } + } +} + + +/* recursive mkdir */ +/* abort on ENOENT; ignore other errors like "directory already exists" */ +/* return 1 if OK */ +/* 0 on error */ + +int makedir (char *newdir) +{ + char *buffer = strdup(newdir); + char *p; + int len = strlen(buffer); + + if (len <= 0) { + free(buffer); + return 0; + } + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mkdir(buffer, 0755) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT)) + { + fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + + +int matchname (int arg,int argc,char **argv,char *fname) +{ + if (arg == argc) /* no arguments given (untgz tgzarchive) */ + return 1; + + while (arg < argc) + if (ExprMatch(fname,argv[arg++])) + return 1; + + return 0; /* ignore this for the moment being */ +} + + +/* tar file list or extract */ + +int tar (gzFile in,int action,int arg,int argc,char **argv) +{ + union tar_buffer buffer; + int len; + int err; + int getheader = 1; + int remaining = 0; + FILE *outfile = NULL; + char fname[BLOCKSIZE]; + int tarmode; + time_t tartime; + + if (action == TGZ_LIST) + printf(" date time size file\n" + " ---------- -------- --------- -------------------------------------\n"); + while (1) + { + len = gzread(in, &buffer, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + /* + * Always expect complete blocks to process + * the tar information. + */ + if (len != BLOCKSIZE) + { + action = TGZ_INVALID; /* force error exit */ + remaining = 0; /* force I/O cleanup */ + } + + /* + * If we have to get a tar header + */ + if (getheader == 1) + { + /* + * if we met the end of the tar + * or the end-of-tar block, + * we are done + */ + if ((len == 0) || (buffer.header.name[0] == 0)) break; + + tarmode = getoct(buffer.header.mode,8); + tartime = (time_t)getoct(buffer.header.mtime,12); + if (tarmode == -1 || tartime == (time_t)-1) + { + buffer.header.name[0] = 0; + action = TGZ_INVALID; + } + + strcpy(fname,buffer.header.name); + + switch (buffer.header.typeflag) + { + case DIRTYPE: + if (action == TGZ_LIST) + printf(" %s %s\n",strtime(&tartime),fname); + if (action == TGZ_EXTRACT) + { + makedir(fname); + setfiletime(fname,tartime); + } + break; + case REGTYPE: + case AREGTYPE: + remaining = getoct(buffer.header.size,12); + if (remaining == -1) + { + action = TGZ_INVALID; + break; + } + if (action == TGZ_LIST) + printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); + else if (action == TGZ_EXTRACT) + { + if (matchname(arg,argc,argv,fname)) + { + outfile = fopen(fname,"wb"); + if (outfile == NULL) { + /* try creating directory */ + char *p = strrchr(fname, '/'); + if (p != NULL) { + *p = '\0'; + makedir(fname); + *p = '/'; + outfile = fopen(fname,"wb"); + } + } + if (outfile != NULL) + printf("Extracting %s\n",fname); + else + fprintf(stderr, "%s: Couldn't create %s",prog,fname); + } + else + outfile = NULL; + } + getheader = 0; + break; + default: + if (action == TGZ_LIST) + printf(" %s <---> %s\n",strtime(&tartime),fname); + break; + } + } + else + { + unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; + + if (outfile != NULL) + { + if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) + { + fprintf(stderr,"%s: Error writing %s -- skipping\n",prog,fname); + fclose(outfile); + outfile = NULL; + remove(fname); + } + } + remaining -= bytes; + } + + if (remaining == 0) + { + getheader = 1; + if (outfile != NULL) + { + fclose(outfile); + outfile = NULL; + if (action != TGZ_INVALID) + setfiletime(fname,tartime); + } + } + + /* + * Abandon if errors are found + */ + if (action == TGZ_INVALID) + { + error("broken archive"); + break; + } + } + + if (gzclose(in) != Z_OK) + error("failed gzclose"); + + return 0; +} + + +/* ============================================================ */ + +void help(int exitval) +{ + printf("untgz version 0.2\n" + " using zlib version %s\n\n", + zlibVersion()); + printf("Usage: untgz file.tgz extract all files\n" + " untgz file.tgz fname ... extract selected files\n" + " untgz -l file.tgz list archive contents\n" + " untgz -h display this help\n"); + exit(exitval); +} + +void error(const char *msg) +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + + +/* ============================================================ */ + +#if defined(WIN32) && defined(__GNUC__) +int _CRT_glob = 0; /* disable argument globbing in MinGW */ +#endif + +int main(int argc,char **argv) +{ + int action = TGZ_EXTRACT; + int arg = 1; + char *TGZfile; + gzFile *f; + + prog = strrchr(argv[0],'\\'); + if (prog == NULL) + { + prog = strrchr(argv[0],'/'); + if (prog == NULL) + { + prog = strrchr(argv[0],':'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + } + else + prog++; + } + else + prog++; + + if (argc == 1) + help(0); + + if (strcmp(argv[arg],"-l") == 0) + { + action = TGZ_LIST; + if (argc == ++arg) + help(0); + } + else if (strcmp(argv[arg],"-h") == 0) + { + help(0); + } + + if ((TGZfile = TGZfname(argv[arg])) == NULL) + TGZnotfound(argv[arg]); + + ++arg; + if ((action == TGZ_LIST) && (arg != argc)) + help(1); + +/* + * Process the TGZ file + */ + switch(action) + { + case TGZ_LIST: + case TGZ_EXTRACT: + f = gzopen(TGZfile,"rb"); + if (f == NULL) + { + fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile); + return 1; + } + exit(tar(f, action, arg, argc, argv)); + break; + + default: + error("Unknown option"); + exit(1); + } + + return 0; +} diff --git a/zlib/contrib/visual-basic.txt b/zlib/contrib/visual-basic.txt new file mode 100644 index 0000000..bb275af --- /dev/null +++ b/zlib/contrib/visual-basic.txt @@ -0,0 +1,160 @@ +See below some functions declarations for Visual Basic. + +Frequently Asked Question: + +Q: Each time I use the compress function I get the -5 error (not enough + room in the output buffer). + +A: Make sure that the length of the compressed buffer is passed by + reference ("as any"), not by value ("as long"). Also check that + before the call of compress this length is equal to the total size of + the compressed buffer and not zero. + + +From: "Jon Caruana" +Subject: Re: How to port zlib declares to vb? +Date: Mon, 28 Oct 1996 18:33:03 -0600 + +Got the answer! (I haven't had time to check this but it's what I got, and +looks correct): + +He has the following routines working: + compress + uncompress + gzopen + gzwrite + gzread + gzclose + +Declares follow: (Quoted from Carlos Rios , in Vb4 form) + +#If Win16 Then 'Use Win16 calls. +Declare Function compress Lib "ZLIB.DLL" (ByVal compr As + String, comprLen As Any, ByVal buf As String, ByVal buflen + As Long) As Integer +Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr + As String, uncomprLen As Any, ByVal compr As String, ByVal + lcompr As Long) As Integer +Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As + String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As + Long) As Integer +#Else +Declare Function compress Lib "ZLIB32.DLL" + (ByVal compr As String, comprLen As Any, ByVal buf As + String, ByVal buflen As Long) As Integer +Declare Function uncompress Lib "ZLIB32.DLL" + (ByVal uncompr As String, uncomprLen As Any, ByVal compr As + String, ByVal lcompr As Long) As Long +Declare Function gzopen Lib "ZLIB32.DLL" + (ByVal file As String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzwrite Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzclose Lib "ZLIB32.DLL" + (ByVal file As Long) As Long +#End If + +-Jon Caruana +jon-net@usa.net +Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member + + +Here is another example from Michael that he +says conforms to the VB guidelines, and that solves the problem of not +knowing the uncompressed size by storing it at the end of the file: + +'Calling the functions: +'bracket meaning: [optional] {Range of possible values} +'Call subCompressFile( [, , [level of compression {1..9}]]) +'Call subUncompressFile() + +Option Explicit +Private lngpvtPcnSml As Long 'Stores value for 'lngPercentSmaller' +Private Const SUCCESS As Long = 0 +Private Const strFilExt As String = ".cpr" +Private Declare Function lngfncCpr Lib "zlib.dll" Alias "compress2" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long, +ByVal level As Integer) As Long +Private Declare Function lngfncUcp Lib "zlib.dll" Alias "uncompress" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long) +As Long + +Public Sub subCompressFile(ByVal strargOriFilPth As String, Optional ByVal +strargCprFilPth As String, Optional ByVal intLvl As Integer = 9) + Dim strCprPth As String + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim bytaryOri() As Byte + Dim bytaryCpr() As Byte + lngOriSiz = FileLen(strargOriFilPth) + ReDim bytaryOri(lngOriSiz - 1) + Open strargOriFilPth For Binary Access Read As #1 + Get #1, , bytaryOri() + Close #1 + strCprPth = IIf(strargCprFilPth = "", strargOriFilPth, strargCprFilPth) +'Select file path and name + strCprPth = strCprPth & IIf(Right(strCprPth, Len(strFilExt)) = +strFilExt, "", strFilExt) 'Add file extension if not exists + lngCprSiz = (lngOriSiz * 1.01) + 12 'Compression needs temporary a bit +more space then original file size + ReDim bytaryCpr(lngCprSiz - 1) + If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) = +SUCCESS Then + lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100 + ReDim Preserve bytaryCpr(lngCprSiz - 1) + Open strCprPth For Binary Access Write As #1 + Put #1, , bytaryCpr() + Put #1, , lngOriSiz 'Add the the original size value to the end +(last 4 bytes) + Close #1 + Else + MsgBox "Compression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub + +Public Sub subUncompressFile(ByVal strargFilPth As String) + Dim bytaryCpr() As Byte + Dim bytaryOri() As Byte + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim strOriPth As String + lngCprSiz = FileLen(strargFilPth) + ReDim bytaryCpr(lngCprSiz - 1) + Open strargFilPth For Binary Access Read As #1 + Get #1, , bytaryCpr() + Close #1 + 'Read the original file size value: + lngOriSiz = bytaryCpr(lngCprSiz - 1) * (2 ^ 24) _ + + bytaryCpr(lngCprSiz - 2) * (2 ^ 16) _ + + bytaryCpr(lngCprSiz - 3) * (2 ^ 8) _ + + bytaryCpr(lngCprSiz - 4) + ReDim Preserve bytaryCpr(lngCprSiz - 5) 'Cut of the original size value + ReDim bytaryOri(lngOriSiz - 1) + If lngfncUcp(bytaryOri(0), lngOriSiz, bytaryCpr(0), lngCprSiz) = SUCCESS +Then + strOriPth = Left(strargFilPth, Len(strargFilPth) - Len(strFilExt)) + Open strOriPth For Binary Access Write As #1 + Put #1, , bytaryOri() + Close #1 + Else + MsgBox "Uncompression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub +Public Property Get lngPercentSmaller() As Long + lngPercentSmaller = lngpvtPcnSml +End Property diff --git a/zlib/contrib/vstudio/readme.txt b/zlib/contrib/vstudio/readme.txt new file mode 100644 index 0000000..3a4b85c --- /dev/null +++ b/zlib/contrib/vstudio/readme.txt @@ -0,0 +1,55 @@ +Building instructions for the DLL versions of Zlib 1.21 +======================================================= + +This directory contains projects that build zlib and minizip using +Microsoft Visual C++ 7.0/7.1. + +You don't need to build these projects yourself. You can download the +binaries from: + http://www.winimage.com/zLibDll + +More information can be found at this site. + + +Build instructions +------------------ +- Unzip zlib*.zip and copy the files from contrib\vstudio\vc7, + from contrib\vstudio\masmx86 and from contrib\minizip into the same + directory. +- Download the crtdll library from + http://www.winimage.com/zLibDll/crtdll.zip + Unzip crtdll.zip to extract crtdll.lib. +- If you are using x86, use the Release target. +- Open zlibvc.sln with Microsoft Visual C++ 7.0 or 7.1 + (Visual Studio .Net 2002 or 2003). + + +Important +--------- +- To use zlibwapi.dll in your application, you must define the + macro ZLIB_WINAPI when compiling your application's source files. + + +Additional notes +---------------- +- This DLL, named zlibwapi.dll, is compatible to the old zlib.dll built + by Gilles Vollant from the zlib 1.1.x sources, and distributed at + http://www.winimage.com/zLibDll + It uses the WINAPI calling convention for the exported functions, and + includes the minizip functionality. If your application needs that + particular build of zlib.dll, you can rename zlibwapi.dll to zlib.dll. + +- The new DLL was renamed because there exist several incompatible + versions of zlib.dll on the Internet. + +- There is also an official DLL build of zlib, named zlib1.dll. This one + is exporting the functions using the CDECL convention. See the file + win32\DLL_FAQ.txt found in this zlib distribution. + +- There used to be a ZLIB_DLL macro in zlib 1.1.x, but now this symbol + has a slightly different effect. To avoid compatibility problems, do + not define it here. + + +Gilles Vollant +info@winimage.com diff --git a/zlib/contrib/vstudio/vc7/gvmat32.obj b/zlib/contrib/vstudio/vc7/gvmat32.obj new file mode 100644 index 0000000..5b2f856 Binary files /dev/null and b/zlib/contrib/vstudio/vc7/gvmat32.obj differ diff --git a/zlib/contrib/vstudio/vc7/inffas32.obj b/zlib/contrib/vstudio/vc7/inffas32.obj new file mode 100644 index 0000000..a541a5a Binary files /dev/null and b/zlib/contrib/vstudio/vc7/inffas32.obj differ diff --git a/zlib/contrib/vstudio/vc7/miniunz.vcproj b/zlib/contrib/vstudio/vc7/miniunz.vcproj new file mode 100644 index 0000000..935c250 --- /dev/null +++ b/zlib/contrib/vstudio/vc7/miniunz.vcproj @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zlib/contrib/vstudio/vc7/minizip.vcproj b/zlib/contrib/vstudio/vc7/minizip.vcproj new file mode 100644 index 0000000..e6f9107 --- /dev/null +++ b/zlib/contrib/vstudio/vc7/minizip.vcproj @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zlib/contrib/vstudio/vc7/zlib.rc b/zlib/contrib/vstudio/vc7/zlib.rc new file mode 100644 index 0000000..6c51679 --- /dev/null +++ b/zlib/contrib/vstudio/vc7/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,1,0 + PRODUCTVERSION 1,2,1,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", "1.2.1.0\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlib.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2003 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/zlib/contrib/vstudio/vc7/zlibstat.vcproj b/zlib/contrib/vstudio/vc7/zlibstat.vcproj new file mode 100644 index 0000000..eb182f7 --- /dev/null +++ b/zlib/contrib/vstudio/vc7/zlibstat.vcproj @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zlib/contrib/vstudio/vc7/zlibvc.def b/zlib/contrib/vstudio/vc7/zlibvc.def new file mode 100644 index 0000000..b5db6da --- /dev/null +++ b/zlib/contrib/vstudio/vc7/zlibvc.def @@ -0,0 +1,92 @@ + +VERSION 1.21 + +HEAPSIZE 1048576,8192 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 diff --git a/zlib/contrib/vstudio/vc7/zlibvc.sln b/zlib/contrib/vstudio/vc7/zlibvc.sln new file mode 100644 index 0000000..5a007ff --- /dev/null +++ b/zlib/contrib/vstudio/vc7/zlibvc.sln @@ -0,0 +1,66 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + ConfigName.2 = ReleaseAxp + ConfigName.3 = ReleaseWithoutAsm + ConfigName.4 = ReleaseWithoutCrtdll + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseAxp.ActiveCfg = ReleaseAxp|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseAxp.Build.0 = ReleaseAxp|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutCrtdll.ActiveCfg = ReleaseAxp|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutCrtdll.Build.0 = ReleaseAxp|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseAxp.ActiveCfg = ReleaseAxp|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseAxp.Build.0 = ReleaseAxp|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutCrtdll.ActiveCfg = ReleaseWithoutCrtdll|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutCrtdll.Build.0 = ReleaseWithoutCrtdll|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseAxp.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseAxp.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutCrtdll.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutCrtdll.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseAxp.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseAxp.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutCrtdll.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutCrtdll.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/zlib/contrib/vstudio/vc7/zlibvc.vcproj b/zlib/contrib/vstudio/vc7/zlibvc.vcproj new file mode 100644 index 0000000..4e57bcd --- /dev/null +++ b/zlib/contrib/vstudio/vc7/zlibvc.vcproj @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zlib/crc32.c b/zlib/crc32.c new file mode 100644 index 0000000..235fa9e --- /dev/null +++ b/zlib/crc32.c @@ -0,0 +1,311 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/zlib/crc32.h b/zlib/crc32.h new file mode 100644 index 0000000..5de49bc --- /dev/null +++ b/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/zlib/deflate.c b/zlib/deflate.c new file mode 100644 index 0000000..022d6b8 --- /dev/null +++ b/zlib/deflate.c @@ -0,0 +1,1502 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/zlib/deflate.h b/zlib/deflate.h new file mode 100644 index 0000000..ee00773 --- /dev/null +++ b/zlib/deflate.h @@ -0,0 +1,326 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/zlib/example.c b/zlib/example.c new file mode 100644 index 0000000..24a5d42 --- /dev/null +++ b/zlib/example.c @@ -0,0 +1,567 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#else + extern void exit OF((int)); +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/zlib/gzio.c b/zlib/gzio.c new file mode 100644 index 0000000..26f2da1 --- /dev/null +++ b/zlib/gzio.c @@ -0,0 +1,1005 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/zlib/infback.c b/zlib/infback.c new file mode 100644 index 0000000..5cf5d22 --- /dev/null +++ b/zlib/infback.c @@ -0,0 +1,619 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + 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}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/zlib/inffast.c b/zlib/inffast.c new file mode 100644 index 0000000..63aa440 --- /dev/null +++ b/zlib/inffast.c @@ -0,0 +1,305 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + 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); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/zlib/inffast.h b/zlib/inffast.h new file mode 100644 index 0000000..614fa78 --- /dev/null +++ b/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/zlib/inffixed.h b/zlib/inffixed.h new file mode 100644 index 0000000..423d5c5 --- /dev/null +++ b/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/zlib/inflate.c b/zlib/inflate.c new file mode 100644 index 0000000..71fe3cc --- /dev/null +++ b/zlib/inflate.c @@ -0,0 +1,1270 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + 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 || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + 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); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/zlib/inflate.h b/zlib/inflate.h new file mode 100644 index 0000000..b696512 --- /dev/null +++ b/zlib/inflate.h @@ -0,0 +1,117 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/zlib/inftrees.c b/zlib/inftrees.c new file mode 100644 index 0000000..55fd27b --- /dev/null +++ b/zlib/inftrees.c @@ -0,0 +1,321 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/zlib/inftrees.h b/zlib/inftrees.h new file mode 100644 index 0000000..1dbfe53 --- /dev/null +++ b/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/zlib/minigzip.c b/zlib/minigzip.c new file mode 100644 index 0000000..0a58a0a --- /dev/null +++ b/zlib/minigzip.c @@ -0,0 +1,322 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#else + extern void exit OF((int)); +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + uInt len = (uInt)strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + return 0; +} diff --git a/zlib/msdos/Makefile.bor b/zlib/msdos/Makefile.bor new file mode 100644 index 0000000..27444cc --- /dev/null +++ b/zlib/msdos/Makefile.bor @@ -0,0 +1,109 @@ +# Makefile for zlib +# Borland C++ +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.bor" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C++, Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# memory model: one of s, m, c, l (small, medium, compact, large) +MODEL=l + +# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version +CC=bcc +LD=bcc +AR=tlib + +# compiler flags +# replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0 +CFLAGS=-O2 -Z -m$(MODEL) $(LOC) + +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj +OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj +OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/zlib/msdos/Makefile.dj2 b/zlib/msdos/Makefile.dj2 new file mode 100644 index 0000000..50ac8dc --- /dev/null +++ b/zlib/msdos/Makefile.dj2 @@ -0,0 +1,104 @@ +# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.dj2; make test -fmakefile.dj2 +# +# To install libz.a, zconf.h and zlib.h in the djgpp directories, type: +# +# make install -fmakefile.dj2 +# +# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as +# in the sample below if the pattern of the DJGPP distribution is to +# be followed. Remember that, while 'es around <=> are ignored in +# makefiles, they are *not* in batch files or in djgpp.env. +# - - - - - +# [make] +# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include +# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib +# BUTT=-m486 +# - - - - - +# Alternately, these variables may be defined below, overriding the values +# in djgpp.env, as +# INCLUDE_PATH=c:\usr\include +# LIBRARY_PATH=c:\usr\lib + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lz +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=libz.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +check: test +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + +# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env . + +.PHONY : uninstall clean + +install: $(INCL) $(LIBS) + -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH) + -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH) + $(INSTALL) zlib.h $(INCLUDE_PATH) + $(INSTALL) zconf.h $(INCLUDE_PATH) + $(INSTALL) libz.a $(LIBRARY_PATH) + +uninstall: + $(RM) $(INCLUDE_PATH)\zlib.h + $(RM) $(INCLUDE_PATH)\zconf.h + $(RM) $(LIBRARY_PATH)\libz.a + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) libz.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/zlib/msdos/Makefile.emx b/zlib/msdos/Makefile.emx new file mode 100644 index 0000000..d58fcab --- /dev/null +++ b/zlib/msdos/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/zlib/msdos/Makefile.msc b/zlib/msdos/Makefile.msc new file mode 100644 index 0000000..579a814 --- /dev/null +++ b/zlib/msdos/Makefile.msc @@ -0,0 +1,106 @@ +# Makefile for zlib +# Microsoft C 5.1 or later +# Last updated: 19-Mar-2003 + +# To use, do "make makefile.msc" +# To compile in small model, set below: MODEL=S + +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------- Microsoft C 5.1 and later ------------- + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# Memory model: one of S, M, C, L (small, medium, compact, large) +MODEL=L + +CC=cl +CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC) +#-Ox generates bad code with MSC 5.1 +LIB_CFLAGS=-Zl $(CFLAGS) + +LD=link +LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode +# "/farcall/packcode" are only useful for `large code' memory models +# but should be a "no-op" for small code models. + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj +OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(LIB_CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + +minigzip.obj: minigzip.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + if exist $(ZLIB_LIB) del $(ZLIB_LIB) + lib $(ZLIB_LIB) $(OBJ1); + lib $(ZLIB_LIB) $(OBJ2); + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB); + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB); + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del *.map + -del zlib_*.bak + -del foo.gz diff --git a/zlib/msdos/Makefile.tc b/zlib/msdos/Makefile.tc new file mode 100644 index 0000000..da523c9 --- /dev/null +++ b/zlib/msdos/Makefile.tc @@ -0,0 +1,94 @@ +# Makefile for zlib +# Turbo C 2.01, Turbo C++ 1.01 +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.tc" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to CFLAGS below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C 2.01, Turbo C++ 1.01 ------------ +MODEL=l +CC=tcc +LD=tcc +AR=tlib +# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +CFLAGS=-O2 -G -Z -m$(MODEL) +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj +OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj +OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/zlib/old/Make_vms.com b/zlib/old/Make_vms.com new file mode 100644 index 0000000..60d6585 --- /dev/null +++ b/zlib/old/Make_vms.com @@ -0,0 +1,115 @@ +$! make libz under VMS +$! written by Martin P.J. Zinser +$! +$! Look for the compiler used +$! +$ ccopt = "" +$ if f$getsyi("HW_MODEL").ge.1024 +$ then +$ ccopt = "/prefix=all"+ccopt +$ comp = "__decc__=1" +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ else +$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs."" +$ then +$ comp = "__vaxc__=1" +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ else +$ if f$trnlnm("SYS").eqs."" then define sys decc$library_include: +$ ccopt = "/decc/prefix=all"+ccopt +$ comp = "__decc__=1" +$ endif +$ endif +$! +$! Build the thing plain or with mms +$! +$ write sys$output "Compiling Zlib sources ..." +$ if f$search("SYS$SYSTEM:MMS.EXE").eqs."" +$ then +$ dele example.obj;*,minigzip.obj;* +$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - + adler32.c zlib.h zconf.h +$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - + compress.c zlib.h zconf.h +$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - + crc32.c zlib.h zconf.h +$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - + deflate.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" - + gzio.c zutil.h zlib.h zconf.h +$ CALL MAKE infblock.OBJ "CC ''CCOPT' infblock" - + infblock.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE infcodes.OBJ "CC ''CCOPT' infcodes" - + infcodes.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - + inffast.c zutil.h zlib.h zconf.h inffast.h +$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - + inflate.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - + inftrees.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE infutil.OBJ "CC ''CCOPT' infutil" - + infutil.c zutil.h zlib.h zconf.h inftrees.h infutil.h +$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - + trees.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - + uncompr.c zlib.h zconf.h +$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - + zutil.c zutil.h zlib.h zconf.h +$ write sys$output "Building Zlib ..." +$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ +$ write sys$output "Building example..." +$ CALL MAKE example.OBJ "CC ''CCOPT' example" - + example.c zlib.h zconf.h +$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb +$ write sys$output "Building minigzip..." +$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" - + minigzip.c zlib.h zconf.h +$ call make minigzip.exe - + "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" - + minigzip.obj libz.olb +$ else +$ mms/macro=('comp') +$ endif +$ write sys$output "Zlib build completed" +$ exit +$! +$! +$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES +$ V = 'F$Verify(0) +$! P1 = What we are trying to make +$! P2 = Command to make it +$! P3 - P8 What it depends on +$ +$ If F$Search(P1) .Eqs. "" Then Goto Makeit +$ Time = F$CvTime(F$File(P1,"RDT")) +$arg=3 +$Loop: +$ Argument = P'arg +$ If Argument .Eqs. "" Then Goto Exit +$ El=0 +$Loop2: +$ File = F$Element(El," ",Argument) +$ If File .Eqs. " " Then Goto Endl +$ AFile = "" +$Loop3: +$ OFile = AFile +$ AFile = F$Search(File) +$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl +$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit +$ Goto Loop3 +$NextEL: +$ El = El + 1 +$ Goto Loop2 +$EndL: +$ arg=arg+1 +$ If arg .Le. 8 Then Goto Loop +$ Goto Exit +$ +$Makeit: +$ VV=F$VERIFY(0) +$ write sys$output P2 +$ 'P2 +$ VV='F$Verify(VV) +$Exit: +$ If V Then Set Verify +$ENDSUBROUTINE diff --git a/zlib/old/Makefile.riscos b/zlib/old/Makefile.riscos new file mode 100644 index 0000000..8ba72ca --- /dev/null +++ b/zlib/old/Makefile.riscos @@ -0,0 +1,151 @@ +# Project: zlib_1_03 +# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430 +# test works out-of-the-box, installs `somewhere' on demand + +# Toolflags: +CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah +C++flags = -c -depend !Depend -IC: -throwback +Linkflags = -aif -c++ -o $@ +ObjAsmflags = -throwback -NoCache -depend !Depend +CMHGflags = +LibFileflags = -c -l -o $@ +Squeezeflags = -o $@ + +# change the line below to where _you_ want the library installed. +libdest = lib:zlib + +# Final targets: +@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \ + @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \ + @.o.uncompr @.o.zutil + LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \ + @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \ + @.o.trees @.o.uncompr @.o.zutil +test: @.minigzip @.example @.lib + @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV + @echo running tests: hang on. + @/@.minigzip -f -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -f -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -1 libc + @/@.minigzip -d libc-gz + @diff @.lib @.libc + @echo that should have reported '@.lib and @.libc identical' if you have diff. + @/@.example @.fred @.fred + @echo that will have given lots of hello!'s. + +@.minigzip: @.o.minigzip @.lib C:o.Stubs + Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs +@.example: @.o.example @.lib C:o.Stubs + Link $(Linkflags) @.o.example @.lib C:o.Stubs + +install: @.lib + cdir $(libdest) + cdir $(libdest).h + @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV + @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV + @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV + @echo okay, installed zlib in $(libdest) + +clean:; remove @.minigzip + remove @.example + remove @.libc + -wipe @.o.* F~r~cV + remove @.fred + +# User-editable dependencies: +.c.o: + cc $(ccflags) -o $@ $< + +# Static dependencies: + +# Dynamic dependencies: +o.example: c.example +o.example: h.zlib +o.example: h.zconf +o.minigzip: c.minigzip +o.minigzip: h.zlib +o.minigzip: h.zconf +o.adler32: c.adler32 +o.adler32: h.zlib +o.adler32: h.zconf +o.compress: c.compress +o.compress: h.zlib +o.compress: h.zconf +o.crc32: c.crc32 +o.crc32: h.zlib +o.crc32: h.zconf +o.deflate: c.deflate +o.deflate: h.deflate +o.deflate: h.zutil +o.deflate: h.zlib +o.deflate: h.zconf +o.gzio: c.gzio +o.gzio: h.zutil +o.gzio: h.zlib +o.gzio: h.zconf +o.infblock: c.infblock +o.infblock: h.zutil +o.infblock: h.zlib +o.infblock: h.zconf +o.infblock: h.infblock +o.infblock: h.inftrees +o.infblock: h.infcodes +o.infblock: h.infutil +o.infcodes: c.infcodes +o.infcodes: h.zutil +o.infcodes: h.zlib +o.infcodes: h.zconf +o.infcodes: h.inftrees +o.infcodes: h.infblock +o.infcodes: h.infcodes +o.infcodes: h.infutil +o.infcodes: h.inffast +o.inffast: c.inffast +o.inffast: h.zutil +o.inffast: h.zlib +o.inffast: h.zconf +o.inffast: h.inftrees +o.inffast: h.infblock +o.inffast: h.infcodes +o.inffast: h.infutil +o.inffast: h.inffast +o.inflate: c.inflate +o.inflate: h.zutil +o.inflate: h.zlib +o.inflate: h.zconf +o.inflate: h.infblock +o.inftrees: c.inftrees +o.inftrees: h.zutil +o.inftrees: h.zlib +o.inftrees: h.zconf +o.inftrees: h.inftrees +o.inftrees: h.inffixed +o.infutil: c.infutil +o.infutil: h.zutil +o.infutil: h.zlib +o.infutil: h.zconf +o.infutil: h.infblock +o.infutil: h.inftrees +o.infutil: h.infcodes +o.infutil: h.infutil +o.trees: c.trees +o.trees: h.deflate +o.trees: h.zutil +o.trees: h.zlib +o.trees: h.zconf +o.trees: h.trees +o.uncompr: c.uncompr +o.uncompr: h.zlib +o.uncompr: h.zconf +o.zutil: c.zutil +o.zutil: h.zutil +o.zutil: h.zlib +o.zutil: h.zconf diff --git a/zlib/old/README b/zlib/old/README new file mode 100644 index 0000000..d445fc4 --- /dev/null +++ b/zlib/old/README @@ -0,0 +1,3 @@ +This directory contains files that have not been updated for zlib 1.2.1 + +(Volunteers are encouraged to help clean this up. Thanks.) diff --git a/zlib/old/descrip.mms b/zlib/old/descrip.mms new file mode 100644 index 0000000..4f9e699 --- /dev/null +++ b/zlib/old/descrip.mms @@ -0,0 +1,48 @@ +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser + +cc_defs = +c_deb = + +.ifdef __DECC__ +pref = /prefix=all +.endif + +OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\ + inftrees.obj, infcodes.obj, infutil.obj, inffast.obj + +CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF) + +all : example.exe minigzip.exe + @ write sys$output " Example applications available" +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;* + + +# Other dependencies. +adler32.obj : zutil.h zlib.h zconf.h +compress.obj : zlib.h zconf.h +crc32.obj : zutil.h zlib.h zconf.h +deflate.obj : deflate.h zutil.h zlib.h zconf.h +example.obj : zlib.h zconf.h +gzio.obj : zutil.h zlib.h zconf.h +infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h +inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h +inflate.obj : zutil.h zlib.h zconf.h infblock.h +inftrees.obj : zutil.h zlib.h zconf.h inftrees.h +infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h +minigzip.obj : zlib.h zconf.h +trees.obj : deflate.h zutil.h zlib.h zconf.h +uncompr.obj : zlib.h zconf.h +zutil.obj : zutil.h zlib.h zconf.h diff --git a/zlib/old/os2/Makefile.os2 b/zlib/old/os2/Makefile.os2 new file mode 100644 index 0000000..7ce217e --- /dev/null +++ b/zlib/old/os2/Makefile.os2 @@ -0,0 +1,136 @@ +# Makefile for zlib under OS/2 using GCC (PGCC) +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# cp Makefile.os2 .. +# cd .. +# make -f Makefile.os2 test + +# This makefile will build a static library z.lib, a shared library +# z.dll and a import library zdll.lib. You can use either z.lib or +# zdll.lib by specifying either -lz or -lzdll on gcc's command line + +CC=gcc -Zomf -s + +CFLAGS=-O6 -Wall +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +#################### BUG WARNING: ##################### +## infcodes.c hits a bug in pgcc-1.0, so you have to use either +## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem) +## This bug is reportedly fixed in pgcc >1.0, but this was not tested +CFLAGS+=-fno-force-mem + +LDFLAGS=-s -L. -lzdll -Zcrtdll +LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll + +VER=1.1.0 +ZLIB=z.lib +SHAREDLIB=z.dll +SHAREDLIBIMP=zdll.lib +LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP) + +AR=emxomfar cr +IMPLIB=emximp +RANLIB=echo +TAR=tar +SHELL=bash + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +TEST_OBJS = example.o minigzip.o + +DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \ + algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \ + nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \ + contrib/asm386/*.asm contrib/asm386/*.c \ + contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \ + contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \ + contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 + +all: example.exe minigzip.exe + +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +$(ZLIB): $(OBJS) + $(AR) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +$(SHAREDLIB): $(OBJS) os2/z.def + $(LDSHARED) -o $@ $^ + +$(SHAREDLIBIMP): os2/z.def + $(IMPLIB) -o $@ $^ + +example.exe: example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip.exe: minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +clean: + rm -f *.o *~ example minigzip libz.a libz.so* foo.gz + +distclean: clean + +zip: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + zip -ul9 zlib$$v $(DISTFILES) + mv Makefile~ Makefile + +dist: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + rm -f $$d.tar.gz; \ + if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \ + files=""; \ + for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \ + cd ..; \ + GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \ + if test ! -d $$d; then rm -f $$d; fi + mv Makefile~ Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/old/os2/zlib.def b/zlib/old/os2/zlib.def new file mode 100644 index 0000000..438e8c0 --- /dev/null +++ b/zlib/old/os2/zlib.def @@ -0,0 +1,51 @@ +; +; Slightly modified version of ../nt/zlib.dnt :-) +; + +LIBRARY Z +DESCRIPTION "Zlib compression library for OS/2" +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE + +EXPORTS + adler32 + compress + crc32 + deflate + deflateCopy + deflateEnd + deflateInit2_ + deflateInit_ + deflateParams + deflateReset + deflateSetDictionary + gzclose + gzdopen + gzerror + gzflush + gzopen + gzread + gzwrite + inflate + inflateEnd + inflateInit2_ + inflateInit_ + inflateReset + inflateSetDictionary + inflateSync + uncompress + zlibVersion + gzprintf + gzputc + gzgetc + gzseek + gzrewind + gztell + gzeof + gzsetparams + zError + inflateSyncPoint + get_crc_table + compress2 + gzputs + gzgets diff --git a/zlib/old/zlib.html b/zlib/old/zlib.html new file mode 100644 index 0000000..6574dff --- /dev/null +++ b/zlib/old/zlib.html @@ -0,0 +1,971 @@ + + + + zlib general purpose compression library version 1.1.4 + + + + + +

zlib 1.1.4 Manual

+
+

Contents

+
    +
  1. Prologue +
  2. Introduction +
  3. Utility functions +
  4. Basic functions +
  5. Advanced functions +
  6. Constants +
  7. struct z_stream_s +
  8. Checksum functions +
  9. Misc +
+
+

Prologue

+ 'zlib' general purpose compression library version 1.1.4, March 11th, 2002 +

+ Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler +

+ This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. +

+ Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: +

    +
  1. The origin of this software must not be misrepresented ; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +
  2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +
  3. This notice may not be removed or altered from any source distribution. +
+ +
+
Jean-loup Gailly +
jloup@gzip.org +
Mark Adler +
madler@alumni.caltech.edu +
+ + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files + + ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), + + rfc1951.txt + (deflate format) and + + rfc1952.txt + (gzip format). +

+ This manual is converted from zlib.h by + piaip +

+ Visit + http://ftp.cdrom.com/pub/infozip/zlib/ + for the official zlib web page. +

+ +


+

Introduction

+ The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. +

+ + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. +

+ + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. +

+ + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +

+ +


+

Utility functions

+ The following utility functions are implemented on top of the +
basic stream-oriented functions. + To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +

Function list

+
    +
  • int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); +
  • int compress2 (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level); +
  • int uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); +
  • typedef voidp gzFile; +
  • gzFile gzopen (const char *path, const char *mode); +
  • gzFile gzdopen (int fd, const char *mode); +
  • int gzsetparams (gzFile file, int level, int strategy); +
  • int gzread (gzFile file, voidp buf, unsigned len); +
  • int gzwrite (gzFile file, const voidp buf, unsigned len); +
  • int VA gzprintf (gzFile file, const char *format, ...); +
  • int gzputs (gzFile file, const char *s); +
  • char * gzgets (gzFile file, char *buf, int len); +
  • int gzputc (gzFile file, int c); +
  • int gzgetc (gzFile file); +
  • int gzflush (gzFile file, int flush); +
  • z_off_t gzseek (gzFile file, z_off_t offset, int whence); +
  • z_off_t gztell (gzFile file); +
  • int gzrewind (gzFile file); +
  • int gzeof (gzFile file); +
  • int gzclose (gzFile file); +
  • const char * gzerror (gzFile file, int *errnum); +
+

Function description

+
+
int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); +
+ Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer.

+ This function can be used to compress a whole file at once if the + input file is mmap'ed.

+ compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer.

+ +

int compress2 (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level); +
+ Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. +

+ + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +

+ +

int uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); +
+ Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer.

+ This function can be used to decompress a whole file at once if the + input file is mmap'ed. +

+ + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +

+ +

typedef voidp gzFile; +

+ +

gzFile gzopen (const char *path, const char *mode); +
+ Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) +

+ + gzopen can be used to read a file which is not in gzip format ; in this + case gzread will directly read from the file without decompression. +

+ + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state ; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +

+ +

gzFile gzdopen (int fd, const char *mode); +
+ gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. +

+ The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). +

+ gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +

+ +

int gzsetparams (gzFile file, int level, int strategy); +
+ Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. +

+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +

+ +

int gzread (gzFile file, voidp buf, unsigned len); +
+ Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. +

+ gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). +

+ +

int gzwrite (gzFile file, const voidp buf, unsigned len); +
+ Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +

+ +

int VA gzprintf (gzFile file, const char *format, ...); +
+ Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +

+ +

int gzputs (gzFile file, const char *s); +
+ Writes the given null-terminated string to the compressed file, excluding + the terminating null character. +

+ gzputs returns the number of characters written, or -1 in case of error. +

+ +

char * gzgets (gzFile file, char *buf, int len); +
+ Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. +

+ gzgets returns buf, or Z_NULL in case of error. +

+ +

int gzputc (gzFile file, int c); +
+ Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +

+ +

int gzgetc (gzFile file); +
+ Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +

+ +

int gzflush (gzFile file, int flush); +
+ Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. +

+ gzflush should be called only when strictly necessary because it can + degrade compression. +

+ +

z_off_t gzseek (gzFile file, z_off_t offset, int whence); +
+ Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. +

+ If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported ; gzseek then compresses a sequence of zeroes up to the new + starting position. +

+ gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +

+ +

int gzrewind (gzFile file); +
+ Rewinds the given file. This function is supported only for reading. +

+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +

+ +

z_off_t gztell (gzFile file); +
+ Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +

+ + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +

+ +

int gzeof (gzFile file); +
+ Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +

+ +

int gzclose (gzFile file); +
+ Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +

+ +

const char * gzerror (gzFile file, int *errnum); +
+ Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +

+

+
+

Basic functions

+

Function list

+
+ +

Function description

+
+
const char * zlibVersion (void); +
The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. +

+ +

int deflateInit (z_streamp strm, int level); +
+ Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. +

+ + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). +

+ + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). +

+ + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +

+ +

int deflate (z_streamp strm, int flush); +
+ deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush.

+ + The detailed semantics are as follows. deflate performs one or both of the + following actions: + +

    +
  • Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + +
  • + Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. +

+ + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly ; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. +

+ + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. +

+ + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. +

+ + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). +

+ + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space ; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. +

+ + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. +

+ + deflate() sets strm-> adler to the adler32 checksum of all input read + so far (that is, total_in bytes). +

+ + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. +

+ + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +

+ +

int deflateEnd (z_streamp strm); +
+ All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. +

+ + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +

+ +

int inflateInit (z_streamp strm); +
+ Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly ; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. +

+ + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +

+ +

int inflate (z_streamp strm, int flush); +
+ inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. +

+ + The detailed semantics are as follows. inflate performs one or both of the + following actions: + +

    +
  • Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + +
  • Provide more output starting at next_out and update next_out and + avail_out accordingly. inflate() provides as much output as possible, + until there is no more input data or no more space in the output buffer + (see below about the flush parameter). +

+ + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. +

+ + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. +

+ + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed ; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. +

+ + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT ; otherwise + it sets strm-> adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. +

+ + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +

+ +

int inflateEnd (z_streamp strm); +
+ All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. +

+ + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +

+
+

Advanced functions

+ The following functions are needed only in some special applications. +

Function list

+
+

Function description

+
+
int deflateInit2 (z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy); + +
This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller.

+ + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library.

+ + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead.

+ + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio ; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel.

+ + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching ; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately.

+ + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate().

+ +

int deflateSetDictionary (z_streamp strm, const Bytef *dictionary, uInt dictLength); +
+ Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary).

+ + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy ; the data can then be compressed better than + with the default empty dictionary.

+ + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front.

+ + Upon return of this function, strm-> adler is set to the Adler32 value + of the dictionary ; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.)

+ + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate().

+ +

int deflateCopy (z_streamp dest, z_streamp source); +
+ Sets the destination stream as a complete copy of the source stream.

+ + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory.

+ + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination.

+ +

int deflateReset (z_streamp strm); +
This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2.

+ + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL).

+ +

int deflateParams (z_streamp strm, int level, int strategy); +
+ Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate().

+ + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm-> avail_out must be + non-zero.

+ + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero.

+ +

int inflateInit2 (z_streamp strm, int windowBits); + +
This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller.

+ + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window.

+ + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.)

+ +

int inflateSetDictionary (z_streamp strm, const Bytef *dictionary, uInt dictLength); +
+ Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary).

+ + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate().

+ +

int inflateSync (z_streamp strm); + +
Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided.

+ + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data.

+ +

int inflateReset (z_streamp strm); +
+ This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. +

+ + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +

+

+ +
+

Checksum functions

+ These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +

Function list

+
+

Function description

+
+
uLong adler32 (uLong adler, const Bytef *buf, uInt len); +
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. +

+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: +

+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+   
+ +
uLong crc32 (uLong crc, const Bytef *buf, uInt len); +
+ Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: +
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+   
+
+
+

struct z_stream_s

+ +
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream ;
+
+typedef z_stream FAR * z_streamp;  ÿ
+
+
+ The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application.

+ + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value.

+ + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe.

+ + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). +

+ + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step).

+ +


+

Constants

+ +
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+	/* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values ; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy ; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions less than 1.0.2 */
+
+
+ +
+

Misc

+
deflateInit and inflateInit are macros to allow checking the zlib version + and the compiler's view of z_stream. +

+ Other functions: +

+
const char * zError (int err); +
int inflateSyncPoint (z_streamp z); +
const uLongf * get_crc_table (void); +
+
+ + Last update: Wed Oct 13 20:42:34 1999
+ piapi@csie.ntu.edu.tw +
+ + + diff --git a/zlib/qnx/package.qpg b/zlib/qnx/package.qpg new file mode 100644 index 0000000..327ca44 --- /dev/null +++ b/zlib/qnx/package.qpg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Library + + Medium + + 2.0 + + + + zlib + zlib + alain.bonnefoy@icbt.com + Public + public + www.gzip.org/zlib + + + Jean-Loup Gailly,Mark Adler + www.gzip.org/zlib + + zlib@gzip.org + + + A massively spiffy yet delicately unobtrusive compression library. + zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system. + http://www.gzip.org/zlib + + + + + 1.2.1 + Medium + Stable + + + + + + + No License + + + + Software Development/Libraries and Extensions/C Libraries + zlib,compression + qnx6 + qnx6 + None + Developer + + + + + + + + + + + + + + Install + Post + No + Ignore + + No + Optional + + + + + + + + + + + + + InstallOver + zlib + + + + + + + + + + + + + InstallOver + zlib-dev + + + + + + + + + diff --git a/zlib/trees.c b/zlib/trees.c new file mode 100644 index 0000000..1d36eaa --- /dev/null +++ b/zlib/trees.c @@ -0,0 +1,1215 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/zlib/trees.h b/zlib/trees.h new file mode 100644 index 0000000..1ca868b --- /dev/null +++ b/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/zlib/uncompr.c b/zlib/uncompr.c new file mode 100644 index 0000000..ad6db0a --- /dev/null +++ b/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/zlib/win32/DLL_FAQ.txt b/zlib/win32/DLL_FAQ.txt new file mode 100644 index 0000000..564969f --- /dev/null +++ b/zlib/win32/DLL_FAQ.txt @@ -0,0 +1,371 @@ + + Frequently Asked Questions about ZLIB1.DLL + + +This document describes the design, the rationale, and the usage +of the official DLL build of zlib, named ZLIB1.DLL. If you have +general questions about zlib, you should see the file "FAQ" found +in the zlib distribution, or at the following location: + http://www.gzip.org/zlib/zlib_faq.html + + + 1. What is ZLIB1.DLL, and how can I get it? + + - ZLIB1.DLL is the official build of zlib as a DLL. + (Please remark the symbol '1' in the name.) + + Pointers to a precompiled ZLIB1.DLL can be found in the zlib + web site at: + http://www.zlib.org/ + + Applications that link to ZLIB1.DLL can rely on the following + specification: + + * The exported symbols are exclusively defined in the source + files "zlib.h" and "zlib.def", found in an official zlib + source distribution. + * The symbols are exported by name, not by ordinal. + * The exported names are undecorated. + * The calling convention of functions is "C" (CDECL). + * The ZLIB1.DLL binary is linked to MSVCRT.DLL. + + The archive in which ZLIB1.DLL is bundled contains compiled + test programs that must run with a valid build of ZLIB1.DLL. + It is recommended to download the prebuilt DLL from the zlib + web site, instead of building it yourself, to avoid potential + incompatibilities that could be introduced by your compiler + and build settings. If you do build the DLL yourself, please + make sure that it complies with all the above requirements, + and it runs with the precompiled test programs, bundled with + the original ZLIB1.DLL distribution and available at the zlib + web site. + + If, for any reason, you need to build an incompatible DLL, + please use a different name. + + + 2. Why did you change the name of the DLL to ZLIB1.DLL? + What happened to the old ZLIB.DLL? + + - The old ZLIB.DLL, built from zlib-1.1.x and earlier, required + compilation settings that were incompatible to those used by a + static build. The DLL settings were supposed to be enabled by + defining the macro ZLIB_DLL, before including "zlib.h". + Incorrect handling of this macro was silently accepted at + build time, resulting in two major problems: + + * ZLIB_DLL was missing from the old makefile. When building + the DLL, not all people added it to the build options. In + consequence, incompatible incarnations of ZLIB.DLL started + to circulate around the net. + + * When switching from using the static library to using the + DLL, applications had to define the ZLIB_DLL macro and + to recompile all the sources that contained calls to zlib + functions. Failure to do so resulted in creating binaries + that were unable to run with the official ZLIB.DLL build. + + The only possible solution that we could foresee was to make a + binary-incompatible change in the DLL interfacing, in order to + remove the dependency on the ZLIB_DLL macro, and to release + the new DLL under a different name. + + We chose the name ZLIB1.DLL, where '1' indicates the major + zlib version number. We hope that we will not have to break + the binary compatibility again, at least not as long as the + zlib-1.x series will last. + + There is still a ZLIB_DLL macro, that can trigger a more + efficient build and use of the DLL, but compatibility no + longer dependents on it. + + + 3. Can I build ZLIB.DLL from the new zlib sources, and replace + an old ZLIB.DLL, that was built from zlib-1.1.4 or earlier? + + - In principle, you can do it by assigning calling convention + keywords to the macros ZEXPORT and ZEXPORTVA. In practice, + it depends on what you mean by "an old ZLIB.DLL", because + the old DLL exists in several mutually-incompatible versions. + + If you have a compiled application that works with a certain + ZLIB.DLL without any known security issues, there is hardly + a need to rebuild the DLL from new sources only to link it to + the old app binary. But if you really want to do it, you have + to find out first what kind of calling convention uses your + particular ZLIB.DLL build, and to use the same one in the new + build. If you don't know what this is all about, you might be + better off if you would just forget it. + + + 4. Can I compile my application using the new zlib interface, and + link it to an old ZLIB.DLL, that was built from zlib-1.1.4 or + earlier? + + - The official answer is "no"; the real answer depends again on + what kind of ZLIB.DLL you have. Even if you are lucky, this + course of action is unreliable. + + If you rebuild your application and you intend to use a newer + version of zlib (post- 1.1.4), it is strongly recommended to + link it to the new ZLIB1.DLL. + + + 5. Why are the zlib symbols exported by name, and not by ordinal? + + - Although exporting symbols by ordinal is a little faster, it + is risky. Any single glitch in the maintenance or use of the + DEF file that contains the ordinals can result in incompatible + builds and frustrating crashes. Simply put, the benefits of + exporting symbols by ordinal do not justify the risks. + + Technically, it should be possible to maintain ordinals in + the DEF file, and still export the symbols by name. Ordinals + exist in every DLL, and even if the dynamic linking performed + at the DLL startup is searching for names, ordinals serve as + hints, for a faster name lookup. However, if the DEF file + contains ordinals, the Microsoft linker automatically builds + an implib that will cause the executables linked to it to use + those ordinals, and not the names. It is interesting to + notice that the GNU linker for Win32 does not suffer from this + problem. + + It is possible to avoid the DEF file if the exported symbols + are accompanied by a "__declspec(dllexport)" attribute in the + source files. You can do this in zlib by predefining the + ZLIB_DLL macro. + + + 6. I see that the ZLIB1.DLL functions use the "C" (CDECL) calling + convention. Why not use the STDCALL convention? + STDCALL is the standard convention in Win32, and I need it in + my Visual Basic project! + + (For readability, we use CDECL to refer to the convention + triggered by the "__cdecl" keyword, STDCALL to refer to + the convention triggered by "__stdcall", and FASTCALL to + refer to the convention triggered by "__fastcall".) + + - Most of the native Windows API functions (without varargs) use + indeed the WINAPI convention (which translates to STDCALL in + Win32), but the standard C functions use CDECL. If a user + application is intrinsically tied to the Windows API (e.g. + it calls native Windows API functions such as CreateFile()), + sometimes it makes sense to decorate its own functions with + WINAPI. But if ANSI C or POSIX portability is a goal (e.g. + it calls standard C functions such as fopen()), it is not a + sound decision to request the inclusion of , or to + use non-ANSI constructs, for the sole purpose to make the user + functions STDCALL-able. + + The functionality offered by zlib is not in the category of + "Windows functionality", but is more like "C functionality". + + Technically, STDCALL is not bad; in fact, it is slightly + faster than CDECL, and it works with variable-argument + functions, just like CDECL. It is unfortunate that, in spite + of using STDCALL in the Windows API, it is not the default + convention used by the C compilers that run under Windows. + The roots of the problem reside deep inside the unsafety of + the K&R-style function prototypes, where the argument types + are not specified; but that is another story for another day. + + The fact that remains is that CDECL is the default convention. + Even if an explicit convention (such as STDCALL or FASTCALL) + is hard-coded into the function prototypes inside C headers, + problems may appear. One problem, for example, deals with the + necessity to expose the convention in users' callbacks. + + The calling convention issues are also important when using + zlib in other programming languages. Some of them, like Ada + (GNAT) and Fortran (GNU G77), have C bindings implemented + initially on Unix, and relying on the C calling convention. + On the other hand, the pre- .NET versions of Microsoft Visual + Basic require STDCALL, while Borland Delphi prefers (although + it does not require) FASTCALL. + + In fairness to all possible uses of zlib outside the C + programming language, we choose the default "C" convention. + Anyone interested in different bindings or conventions is + encouraged to maintain specialized projects. The "contrib/" + directory from the zlib distribution already holds a couple + of foreign bindings, such as Ada, C++, and Delphi. + + + 7. I need a DLL for my Visual Basic project. What can I do? + + - Define the ZLIB_WINAPI macro before including "zlib.h", when + building both the DLL and the user application (except that + you don't need to define anything when using the DLL in Visual + Basic). The ZLIB_WINAPI macro will switch on the WINAPI + (STDCALL) convention. The name of this DLL must be different + than the official ZLIB1.DLL. + + Gilles Vollant has contributed a build named ZLIBWAPI.DLL, + with the ZLIB_WINAPI macro turned on, and with the minizip + functionality built in. For more information, please read + the notes inside "contrib/vstudio/readme.txt", found in the + zlib distribution. + + + 8. If my application uses ZLIB1.DLL, should I link it to + MSVCRT.DLL? Why? + + - It is not required, but it is recommended to link your + application to MSVCRT.DLL, if it uses ZLIB1.DLL. + + The executables (.EXE, .DLL, etc.) that are involved in the + same process and are using the C run-time library (i.e. they + are calling standard C functions), must link to the same + library. There are several libraries in the Win32 system: + CRTDLL.DLL, MSVCRT.DLL, the static C libraries, etc. + Since ZLIB1.DLL is linked to MSVCRT.DLL, the executables that + depend on it should also be linked to MSVCRT.DLL. + + + 9. Why are you saying that ZLIB1.DLL and my application must be + linked to the same C run-time (CRT) library? I linked my + application and my DLLs to different C libraries (e.g. my + application to a static library, and my DLLs to MSVCRT.DLL), + and everything works fine. + + - If a user library invokes only pure Win32 API (accessible via + and the related headers), its DLL build will work + in any context. But if this library invokes standard C API, + things get more complicated. + + There is a single Win32 library in a Win32 system. Every + function in this library resides in a single DLL module, that + is safe to call from anywhere. On the other hand, there are + multiple versions of the C library, and each of them has its + own separate internal state. Standalone executables and user + DLLs that call standard C functions must link to a C run-time + (CRT) library, be it static or shared (DLL). Intermixing + occurs when an executable (not necessarily standalone) and a + DLL are linked to different CRTs, and both are running in the + same process. + + Intermixing multiple CRTs is possible, as long as their + internal states are kept intact. The Microsoft Knowledge Base + articles KB94248 "HOWTO: Use the C Run-Time" and KB140584 + "HOWTO: Link with the Correct C Run-Time (CRT) Library" + mention the potential problems raised by intermixing. + + If intermixing works for you, it's because your application + and DLLs are avoiding the corruption of each of the CRTs' + internal states, maybe by careful design, or maybe by fortune. + + Also note that linking ZLIB1.DLL to non-Microsoft CRTs (such + as those provided by Borland) raises similar problems. + + +10. Why are you linking ZLIB1.DLL to MSVCRT.DLL? + + - MSVCRT.DLL exists on every Windows 95 with a new service pack + installed, or with Microsoft Internet Explorer 4 or later, and + on all other Windows 4.x or later (Windows 98, Windows NT 4, + or later). It is freely distributable; if not present in the + system, it can be downloaded from Microsoft or from other + software provider for free. + + The fact that MSVCRT.DLL does not exist on a virgin Windows 95 + is not so problematic. The number of Windows 95 installations + is rapidly decreasing, Microsoft stopped supporting it a long + time ago, and many recent applications from various vendors, + including Microsoft, do not even run on it. Furthermore, no + serious user should run Windows 95 without a proper update + installed. + + There is also the fact that the mainstream C compilers for + Windows are Microsoft Visual C++ 6.0, and gcc/MinGW. Both + are producing executables that link to MSVCRT.DLL by default, + without offering other dynamic CRTs as alternatives easy to + select by users. + + +11. Why are you not linking ZLIB1.DLL to + <> ? + + - We considered and abandoned the following alternatives: + + * Linking ZLIB1.DLL to a static C library (LIBC.LIB, or + LIBCMT.LIB) is not a good option. People are using the DLL + mainly to save disk space. If you are linking your program + to a static C library, you may as well consider linking zlib + in statically, too. + + * Linking ZLIB1.DLL to CRTDLL.DLL looks very appealing, + because CRTDLL.DLL is present on every Win32 installation. + Unfortunately, it has a series of problems: it raises + difficulties when using it with C++ code, it does not work + with 64-bit file offsets, (and so on...), and Microsoft + discontinued its support a long time ago. + + * Linking ZLIB1.DLL to MSVCR70.DLL, supplied with the + Microsoft .NET platform and Visual C++ 7.0 or newer, is not + a good option. Although it is available for free download + and distribution, its presence is scarce on today's Win32 + installations. If it will ever become more popular than + MSVCRT.DLL and will be pre-installed on the future Win32 + systems, we will probably think again about it. + + * Linking ZLIB1.DLL to NTDLL.DLL is not possible. + NTDLL.DLL exports only a part of the C library, and only on + Windows NT systems. + + +12. I need to link my own DLL build to a CRT different than + MSVCRT.DLL. What can I do? + + - Feel free to rebuild the DLL from the zlib sources, and link + it the way you want. You should, however, clearly state that + your build is unofficial. You should give it a different file + name, and/or install it in a private directory that can be + accessed by your application only, and is not visible to the + others (e.g. it's not in the SYSTEM or the SYSTEM32 directory, + and it's not in the PATH). Otherwise, your build may clash + with applications that link to the official build. + + For example, in Cygwin, zlib is linked to the Cygwin runtime + CYGWIN1.DLL, and it is distributed under the name CYGZ.DLL. + + +13. May I include additional pieces of code that I find useful, + link them in ZLIB1.DLL, and export them? + + - No. A legitimate build of ZLIB1.DLL must not include code + that does not originate from the official zlib source code. + But you can make your own private DLL build, under a different + file name, as suggested in the previous answer. + + For example, in Borland Delphi and C++ Builder, zlib is a part + of the standard VCL library. If an application links to VCL + dynamically, the name of the distributable binary (VCLxx.DLL) + does not posess any danger of clashing with a legitimate but + incompatible ZLIB1.DLL. + + +14. May I remove some functionality out of ZLIB1.DLL, by enabling + macros like NO_GZCOMPRESS or NO_GZIP at compile time? + + - No. A legitimate build of ZLIB1.DLL must provide the complete + zlib functionality, as implemented in the official zlib source + code. But you can make your own private DLL build, under a + different file name, as suggested in the previous answer. + + +15. I made my own ZLIB1.DLL build. Can I test it for compliance? + + - We prefer that you download the official DLL from the zlib + web site. If you need something peculiar from this DLL, you + can send your suggestion to the zlib mailing list. + + However, in case you do rebuild the DLL yourself, you can run + it with the test programs found in the DLL distribution. + Running these test programs is not a guarantee of compliance, + but a failure can imply a detected problem. + +** + +This document is written and maintained by +Cosmin Truta diff --git a/zlib/win32/Makefile.bor b/zlib/win32/Makefile.bor new file mode 100644 index 0000000..f7ba86a --- /dev/null +++ b/zlib/win32/Makefile.bor @@ -0,0 +1,107 @@ +# Makefile for zlib +# Borland C++ for Win32 +# +# Updated for zlib 1.2.x by Cosmin Truta, 11-Mar-2003 +# Last updated: 28-Aug-2003 +# +# Usage: +# make -f win32/Makefile.bor +# make -f win32/Makefile.bor LOCAL_ZLIB=-DASMV OBJA=match.obj OBJPA=+match.obj + +# ------------ Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or +# added to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +CC = bcc32 +AS = bcc32 +LD = bcc32 +AR = tlib +CFLAGS = -a -d -k- -O2 $(LOC) +ASFLAGS = $(LOC) +LDFLAGS = $(LOC) + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj +OBJ2 = inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +#OBJA = +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzio.obj+infback.obj +OBJP2 = +inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj +#OBJPA= + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $< + +.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) $(OBJA) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + $(AR) $(ZLIB_LIB) $(OBJPA) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.lib + -del *.exe + -del *.tds + -del zlib.bak + -del foo.gz diff --git a/zlib/win32/Makefile.emx b/zlib/win32/Makefile.emx new file mode 100644 index 0000000..98d0253 --- /dev/null +++ b/zlib/win32/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx/rsxnt by Chr. Spieler, 6/16/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc -Zwin32 + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/zlib/win32/Makefile.gcc b/zlib/win32/Makefile.gcc new file mode 100644 index 0000000..2fbfe14 --- /dev/null +++ b/zlib/win32/Makefile.gcc @@ -0,0 +1,141 @@ +# Makefile for zlib, derived from Makefile.dj2. +# Modified for mingw32 by C. Spieler, 6/16/98. +# Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003. +# Last updated: 1-Aug-2003. +# Tested under Cygwin and MinGW. + +# Copyright (C) 1995-2003 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.gcc; make test testdll -fmakefile.gcc +# +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o -fmakefile.gcc +# +# To install libz.a, zconf.h and zlib.h in the system directories, type: +# +# make install -fmakefile.gcc + +# Note: +# If the platform is *not* MinGW (e.g. it is Cygwin or UWIN), +# the DLL name should be changed from "zlib1.dll". + +STATICLIB = libz.a +SHAREDLIB = zlib1.dll +IMPLIB = libzdll.a + +#LOC = -DASMV +#LOC = -DDEBUG -g + +CC = gcc +CFLAGS = $(LOC) -O3 -Wall + +AS = $(CC) +ASFLAGS = $(LOC) -Wall + +LD = $(CC) +LDFLAGS = $(LOC) -s + +AR = ar +ARFLAGS = rcs + +RC = windres +RCFLAGS = --define GCC_WINDRES + +CP = cp -fp +# If GNU install is available, replace $(CP) with install. +INSTALL = $(CP) +RM = rm -f + +prefix = /usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzio.o infback.o \ + inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o +OBJA = + +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) example minigzip example_d minigzip_d + +test: example minigzip + ./example + echo hello world | ./minigzip | ./minigzip -d + +testdll: example_d minigzip_d + ./example_d + echo hello world | ./minigzip_d | ./minigzip_d -d + +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +.S.o: + $(AS) $(ASFLAGS) -c -o $@ $< + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) $@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + dllwrap --driver-name $(CC) --def win32/zlib.def \ + --implib $(IMPLIB) -o $@ $(OBJS) $(OBJA) zlibrc.o + strip $@ + +example: example.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(STATICLIB) + +minigzip: minigzip.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(STATICLIB) + +example_d: example.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(IMPLIB) + +minigzip_d: minigzip.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(IMPLIB) + +zlibrc.o: win32/zlib1.rc + $(RC) $(RCFLAGS) -o $@ win32/zlib1.rc + + +# INCLUDE_PATH and LIBRARY_PATH must be set. + +.PHONY: install uninstall clean + +install: zlib.h zconf.h $(LIB) + -@if not exist $(INCLUDE_PATH)/nul mkdir $(INCLUDE_PATH) + -@if not exist $(LIBRARY_PATH)/nul mkdir $(LIBRARY_PATH) + -$(INSTALL) zlib.h $(INCLUDE_PATH) + -$(INSTALL) zconf.h $(INCLUDE_PATH) + -$(INSTALL) $(STATICLIB) $(LIBRARY_PATH) + -$(INSTALL) $(IMPLIB) $(LIBRARY_PATH) + +uninstall: + -$(RM) $(INCLUDE_PATH)/zlib.h + -$(RM) $(INCLUDE_PATH)/zconf.h + -$(RM) $(LIBRARY_PATH)/$(STATICLIB) + -$(RM) $(LIBRARY_PATH)/$(IMPLIB) + +clean: + -$(RM) $(STATICLIB) + -$(RM) $(SHAREDLIB) + -$(RM) $(IMPLIB) + -$(RM) *.o + -$(RM) *.exe + -$(RM) foo.gz + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/zlib/win32/Makefile.msc b/zlib/win32/Makefile.msc new file mode 100644 index 0000000..cf17f1e --- /dev/null +++ b/zlib/win32/Makefile.msc @@ -0,0 +1,126 @@ +# Makefile for zlib -- Microsoft (Visual) C +# +# Authors: +# Cosmin Truta, 11-Mar-2003 +# Christian Spieler, 19-Mar-2003 +# +# Last updated: +# Cosmin Truta, 27-Aug-2003 +# +# Usage: +# nmake -f win32/Makefile.msc (standard build) +# nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) +# nmake -f win32/Makefile.msc LOC=-DASMV OBJA=match.obj (use ASM code) + + +# optional build flags +LOC = + + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib + +CC = cl +AS = ml +LD = link +AR = lib +RC = rc +CFLAGS = -nologo -MD -O2 $(LOC) +ASFLAGS = -coff +LDFLAGS = -nologo -release +ARFLAGS = -nologo +RCFLAGS = /dWIN32 /r + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj \ + inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJA = + + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlib1.res + $(LD) $(LDFLAGS) -def:win32/zlib.def -dll -implib:$(IMPLIB) \ + -out:$@ $(OBJS) $(OBJA) zlib1.res + +example.exe: example.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj $(STATICLIB) + +minigzip.exe: minigzip.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj $(STATICLIB) + +example_d.exe: example.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj $(IMPLIB) + +minigzip_d.exe: minigzip.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj $(IMPLIB) + +.c.obj: + $(CC) -c $(CFLAGS) $< + +.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzio.obj: gzio.c zutil.h zlib.h zconf.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: example.c zlib.h zconf.h + +minigzip.obj: minigzip.c zlib.h zconf.h + +zlib1.res: win32/zlib1.rc + $(RC) $(RCFLAGS) /fo$@ win32/zlib1.rc + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del foo.gz diff --git a/zlib/win32/zlib.def b/zlib/win32/zlib.def new file mode 100644 index 0000000..03bcf1c --- /dev/null +++ b/zlib/win32/zlib.def @@ -0,0 +1,60 @@ +LIBRARY +; zlib data compression library + +EXPORTS +; basic functions + zlibVersion + deflate + deflateEnd + inflate + inflateEnd +; advanced functions + deflateSetDictionary + deflateCopy + deflateReset + deflateParams + deflateBound + deflatePrime + inflateSetDictionary + inflateSync + inflateCopy + inflateReset + inflateBack + inflateBackEnd + zlibCompileFlags +; utility functions + compress + compress2 + compressBound + uncompress + gzopen + gzdopen + gzsetparams + gzread + gzwrite + gzprintf + gzputs + gzgets + gzputc + gzgetc + gzungetc + gzflush + gzseek + gzrewind + gztell + gzeof + gzclose + gzerror + gzclearerr +; checksum functions + adler32 + crc32 +; various hacks, don't look :) + deflateInit_ + deflateInit2_ + inflateInit_ + inflateInit2_ + inflateBackInit_ + inflateSyncPoint + get_crc_table + zError diff --git a/zlib/win32/zlib1.rc b/zlib/win32/zlib1.rc new file mode 100644 index 0000000..8669c44 --- /dev/null +++ b/zlib/win32/zlib1.rc @@ -0,0 +1,39 @@ +#include + +#ifdef GCC_WINDRES +VS_VERSION_INFO VERSIONINFO +#else +VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE +#endif + FILEVERSION 1,2,1,0 + PRODUCTVERSION 1,2,1,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS 1 +#else + FILEFLAGS 0 +#endif + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", "1.2.1\0" + VALUE "InternalName", "zlib1.dll\0" + VALUE "LegalCopyright", "(C) 1995-2003 Jean-loup Gailly & Mark Adler\0" + VALUE "OriginalFilename", "zlib1.dll\0" + VALUE "ProductName", "zlib\0" + VALUE "ProductVersion", "1.2.1\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/zlib/zconf.h b/zlib/zconf.h new file mode 100644 index 0000000..759d757 --- /dev/null +++ b/zlib/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/zlib/zconf.in.h b/zlib/zconf.in.h new file mode 100644 index 0000000..759d757 --- /dev/null +++ b/zlib/zconf.in.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/zlib/zlib.3 b/zlib/zlib.3 new file mode 100644 index 0000000..9fea5a8 --- /dev/null +++ b/zlib/zlib.3 @@ -0,0 +1,159 @@ +.TH ZLIB 3 "17 November 2003" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms will be added later +and will have the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +(for example if an input file is mmap'ed), +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I example.c +and +.IR minigzip.c . +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source, +and are concerned primarily with bug fixes and portability enhancements. +.LP +A Java implementation of +.I zlib +is available in the Java Development Kit 1.1: +.IP +http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://www.cpan.org/modules/by-module/Compress/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://www.python.org/doc/lib/module-zlib.html +.LP +A +.I zlib +binding for +.IR tcl (1), +written by Andreas Kupries (a.kupries@westend.com), +is availlable at: +.IP +http://www.westend.com/~kupries/doc/trf/man/man.html +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/unzip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +web site. +.SH "SEE ALSO" +The +.I zlib +web site can be found at either of these locations: +.IP +http://www.zlib.org +.br +http://www.gzip.org/zlib/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format) +.br +http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format) +.br +http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format) +.LP +These documents are also available in other formats from: +.IP +ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html +.LP +Mark Nelson (markn@ieee.org) wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://dogma.net/markn/articles/zlibtool/zlibtool.htm +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://www.gzip.org/zlib/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.1 +Copyright (C) 1995-2003 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/zlib/zlib.h b/zlib/zlib.h new file mode 100644 index 0000000..d54ac94 --- /dev/null +++ b/zlib/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/zlib/zutil.c b/zlib/zutil.c new file mode 100644 index 0000000..a94cdb8 --- /dev/null +++ b/zlib/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/zlib/zutil.h b/zlib/zutil.h new file mode 100644 index 0000000..06cb62e --- /dev/null +++ b/zlib/zutil.h @@ -0,0 +1,258 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# 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 ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */