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