From 5c8fc16b34871807b11553849a751057f2f1eaba Mon Sep 17 00:00:00 2001
From: Chris Danford
Date: Mon, 28 Jan 2002 21:24:17 +0000
Subject: [PATCH] checked in package manager
---
stepmania/src/RageBitmapTexture.cpp | 45 +-
stepmania/src/RageTexture.cpp | 37 +-
stepmania/src/ThemeManager.cpp | 16 +-
.../src/smpackage/SMPackageInstallDlg.cpp | 172 ++
stepmania/src/smpackage/SMPackageInstallDlg.h | 54 +
stepmania/src/smpackage/StdAfx.cpp | 8 +
stepmania/src/smpackage/StdAfx.h | 26 +
.../src/smpackage/ZipArchive/Appnote.txt | 1192 ++++++++++++++
.../src/smpackage/ZipArchive/CodeProject.html | 380 +++++
stepmania/src/smpackage/ZipArchive/StdAfx.cpp | 6 +
stepmania/src/smpackage/ZipArchive/StdAfx.h | 23 +
.../src/smpackage/ZipArchive/ZipArchive.cpp | 1381 +++++++++++++++++
.../src/smpackage/ZipArchive/ZipArchive.dsp | 283 ++++
.../src/smpackage/ZipArchive/ZipArchive.dsw | 29 +
.../src/smpackage/ZipArchive/ZipArchive.h | 698 +++++++++
.../src/smpackage/ZipArchive/ZipArchive.opt | Bin 0 -> 48640 bytes
.../smpackage/ZipArchive/ZipAutoBuffer.cpp | 104 ++
.../src/smpackage/ZipArchive/ZipAutoBuffer.h | 63 +
.../src/smpackage/ZipArchive/ZipBigFile.cpp | 41 +
.../src/smpackage/ZipArchive/ZipBigFile.h | 22 +
.../smpackage/ZipArchive/ZipCentralDir.cpp | 677 ++++++++
.../src/smpackage/ZipArchive/ZipCentralDir.h | 156 ++
.../src/smpackage/ZipArchive/ZipException.cpp | 78 +
.../src/smpackage/ZipArchive/ZipException.h | 71 +
.../smpackage/ZipArchive/ZipFileHeader.cpp | 329 ++++
.../src/smpackage/ZipArchive/ZipFileHeader.h | 106 ++
.../smpackage/ZipArchive/ZipInternalInfo.cpp | 28 +
.../smpackage/ZipArchive/ZipInternalInfo.h | 32 +
.../src/smpackage/ZipArchive/ZipStorage.cpp | 428 +++++
.../src/smpackage/ZipArchive/ZipStorage.h | 134 ++
stepmania/src/smpackage/ZipArchive/zconf.h | 279 ++++
stepmania/src/smpackage/install.bmp | Bin 0 -> 31578 bytes
stepmania/src/smpackage/manage.bmp | Bin 0 -> 31578 bytes
stepmania/src/smpackage/resource.h | 26 +
stepmania/src/smpackage/smpackage.ICO | Bin 0 -> 6006 bytes
stepmania/src/smpackage/smpackage.clw | 66 +
stepmania/src/smpackage/smpackage.cpp | 120 ++
stepmania/src/smpackage/smpackage.dsp | 170 ++
stepmania/src/smpackage/smpackage.h | 49 +
stepmania/src/smpackage/smpackage.opt | Bin 0 -> 54784 bytes
stepmania/src/smpackage/smpackage.rc | 209 +++
stepmania/src/smpackage/smpackageDlg.cpp | 210 +++
stepmania/src/smpackage/smpackageDlg.h | 57 +
43 files changed, 7760 insertions(+), 45 deletions(-)
create mode 100644 stepmania/src/smpackage/SMPackageInstallDlg.cpp
create mode 100644 stepmania/src/smpackage/SMPackageInstallDlg.h
create mode 100644 stepmania/src/smpackage/StdAfx.cpp
create mode 100644 stepmania/src/smpackage/StdAfx.h
create mode 100644 stepmania/src/smpackage/ZipArchive/Appnote.txt
create mode 100644 stepmania/src/smpackage/ZipArchive/CodeProject.html
create mode 100644 stepmania/src/smpackage/ZipArchive/StdAfx.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/StdAfx.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipArchive.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipArchive.dsp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipArchive.dsw
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipArchive.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipArchive.opt
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipBigFile.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipBigFile.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipCentralDir.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipCentralDir.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipException.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipException.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipFileHeader.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipFileHeader.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipInternalInfo.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipInternalInfo.h
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipStorage.cpp
create mode 100644 stepmania/src/smpackage/ZipArchive/ZipStorage.h
create mode 100644 stepmania/src/smpackage/ZipArchive/zconf.h
create mode 100644 stepmania/src/smpackage/install.bmp
create mode 100644 stepmania/src/smpackage/manage.bmp
create mode 100644 stepmania/src/smpackage/resource.h
create mode 100644 stepmania/src/smpackage/smpackage.ICO
create mode 100644 stepmania/src/smpackage/smpackage.clw
create mode 100644 stepmania/src/smpackage/smpackage.cpp
create mode 100644 stepmania/src/smpackage/smpackage.dsp
create mode 100644 stepmania/src/smpackage/smpackage.h
create mode 100644 stepmania/src/smpackage/smpackage.opt
create mode 100644 stepmania/src/smpackage/smpackage.rc
create mode 100644 stepmania/src/smpackage/smpackageDlg.cpp
create mode 100644 stepmania/src/smpackage/smpackageDlg.h
diff --git a/stepmania/src/RageBitmapTexture.cpp b/stepmania/src/RageBitmapTexture.cpp
index 98714eb639..d26fa58a81 100644
--- a/stepmania/src/RageBitmapTexture.cpp
+++ b/stepmania/src/RageBitmapTexture.cpp
@@ -62,38 +62,49 @@ void RageBitmapTexture::Create()
{
HRESULT hr;
+ ///////////////////////
+ // Figure out which texture format to use
+ ///////////////////////
D3DFORMAT fmtTexture;
- if( !GAMEINFO )
+
+ // look in the file name for a hint
+ m_sFilePath.MakeLower();
+ if( -1 != m_sFilePath.Find("(no alpha)") )
+ {
+ fmtTexture = D3DFMT_R5G6B5;
+ }
+ else if( -1 != m_sFilePath.Find("(1 alpha)") )
+ {
+ fmtTexture = D3DFMT_A1R5G5B5;
+ }
+ else // no hint, assume full alpha
{
fmtTexture = D3DFMT_A4R4G4B4;
}
- else if( GAMEINFO->m_GameOptions.m_iDisplayColor == 16 )
+
+ // if the user has requested high color textures, use the higher color
+ if( GAMEINFO != NULL
+ && GAMEINFO->m_GameOptions.m_iDisplayColor == 32
+ && GAMEINFO->m_GameOptions.m_iTextureColor == 32 )
{
- fmtTexture = D3DFMT_A4R4G4B4;
- }
- else
- {
- switch( GAMEINFO->m_GameOptions.m_iTextureColor )
- {
- case 16: fmtTexture = D3DFMT_A4R4G4B4; break;
- case 32: fmtTexture = D3DFMT_A8R8G8B8; break;
- default: ASSERT( true ); // invalid iTextureColor value
- }
+ fmtTexture = D3DFMT_A8R8G8B8;
}
+
+
+ // load texture and get image info
D3DXIMAGE_INFO ddii;
- // load texture
if( FAILED( hr = D3DXCreateTextureFromFileEx(
m_pd3dDevice, // device
m_sFilePath, // soure file
D3DX_DEFAULT, D3DX_DEFAULT, // width, height
- 3, // mip map levels
+ 4, // mip map levels
0, // usage (is a render target?)
- fmtTexture, // our preferred texture format
+ fmtTexture, // our preferred texture format
D3DPOOL_MANAGED, // which memory pool
- D3DX_FILTER_BOX | D3DX_FILTER_DITHER, // filter
- D3DX_FILTER_BOX | D3DX_FILTER_DITHER, // mip filter
+ D3DX_FILTER_BOX, // filter
+ D3DX_FILTER_BOX, // mip filter
0, // no color key
&ddii, // struct to fill with source image info
NULL, // no palette
diff --git a/stepmania/src/RageTexture.cpp b/stepmania/src/RageTexture.cpp
index d500d7e2b6..bf0132b95e 100644
--- a/stepmania/src/RageTexture.cpp
+++ b/stepmania/src/RageTexture.cpp
@@ -75,35 +75,32 @@ void RageTexture::CreateFrameRects()
#include "string.h"
void RageTexture::GetFrameDimensionsFromFileName( CString sPath, UINT* puFramesWide, UINT* puFramesHigh ) const
{
- *puFramesWide = *puFramesHigh = 1; // initialize in case we don't find dimensions in the file name
+ *puFramesWide = *puFramesHigh = 1; // set default values in case we don't find the dimension in the file name
sPath.MakeLower();
CString sDir, sFName, sExt;
splitrelpath( sPath, sDir, sFName, sExt);
- CStringArray sFileNameBits;
- split( sFName, " ", sFileNameBits, false );
+ CStringArray arrayBits;
+ split( sFName, " ", arrayBits, false );
- if( sFileNameBits.GetSize() < 2 )
- return; // there can't be dimensions in the file name if there's no space
-
- CString sDimensionsPart = sFileNameBits[ sFileNameBits.GetSize()-1 ]; // looks like "10x5"
-
- CStringArray sDimensionsBits;
- split( sDimensionsPart, "x", sDimensionsBits, false );
-
- if( sDimensionsBits.GetSize() != 2 )
+ for( int i=0; iLoadIcon(IDR_MAINFRAME);
+
+ m_sPackagePath = sPackagePath;
+}
+
+
+void CSMPackageInstallDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CSMPackageInstallDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CSMPackageInstallDlg, CDialog)
+ //{{AFX_MSG_MAP(CSMPackageInstallDlg)
+ ON_WM_PAINT()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSMPackageInstallDlg message handlers
+
+BOOL CSMPackageInstallDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ // Set the icon for this dialog. The framework does this automatically
+ // when the application's main window is not a dialog
+ SetIcon(m_hIcon, TRUE); // Set big icon
+ SetIcon(m_hIcon, FALSE); // Set small icon
+
+ // TODO: Add extra initialization here
+
+ CString sMessage;
+ sMessage += ssprintf(
+ "You have chosen to install the Stepmania package:\r\n"
+ "\t%s\r\n"
+ "\r\n"
+ "This package contains the following files:\r\n",
+ m_sPackagePath
+ );
+
+ // add all the files in the zip to the message
+ try
+ {
+ m_zip.Open( m_sPackagePath );
+ }
+ catch (CException* e)
+ {
+ AfxMessageBox( ssprintf("'%s' is not a valid zip archive.", m_sPackagePath), MB_ICONSTOP );
+ e->Delete();
+ exit( 1 );
+ }
+
+ for( int i=0; iSetWindowText( sMessage );
+
+
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+
+void CSMPackageInstallDlg::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ // TODO: Add your message handler code here
+
+ if (IsIconic())
+ {
+ CPaintDC dc(this); // device context for painting
+
+ SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
+
+ // Center icon in client rectangle
+ int cxIcon = GetSystemMetrics(SM_CXICON);
+ int cyIcon = GetSystemMetrics(SM_CYICON);
+ CRect rect;
+ GetClientRect(&rect);
+ int x = (rect.Width() - cxIcon + 1) / 2;
+ int y = (rect.Height() - cyIcon + 1) / 2;
+
+ // Draw the icon
+ dc.DrawIcon(x, y, m_hIcon);
+ }
+ else
+ {
+ CDialog::OnPaint();
+ }
+}
+
+
+void CSMPackageInstallDlg::OnOK()
+{
+ // TODO: Add extra validation here
+
+ TCHAR szCurrentDirectory[MAX_PATH];
+ GetCurrentDirectory( MAX_PATH, szCurrentDirectory );
+
+ // Unzip the SMzip package into the Stepmania installation folder
+ for( int i=0; iDelete();
+ exit( 1 );
+ }
+ }
+
+ AfxMessageBox( "Package installed successfully!" );
+
+ // close the dialog
+ CDialog::OnOK();
+}
diff --git a/stepmania/src/smpackage/SMPackageInstallDlg.h b/stepmania/src/smpackage/SMPackageInstallDlg.h
new file mode 100644
index 0000000000..e5bce89590
--- /dev/null
+++ b/stepmania/src/smpackage/SMPackageInstallDlg.h
@@ -0,0 +1,54 @@
+#if !defined(AFX_SMPACKAGEINSTALLDLG_H__5E362C4C_CA11_4071_A8AB_A0231E985DAF__INCLUDED_)
+#define AFX_SMPACKAGEINSTALLDLG_H__5E362C4C_CA11_4071_A8AB_A0231E985DAF__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// SMPackageInstallDlg.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CSMPackageInstallDlg dialog
+
+#include "ZipArchive\ZipArchive.h"
+
+
+class CSMPackageInstallDlg : public CDialog
+{
+// Construction
+public:
+ CSMPackageInstallDlg(CString sPackagePath, CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CSMPackageInstallDlg)
+ enum { IDD = IDD_INSTALL };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSMPackageInstallDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ HICON m_hIcon;
+ CString m_sPackagePath;
+ CZipArchive m_zip;
+
+ // Generated message map functions
+ //{{AFX_MSG(CSMPackageInstallDlg)
+ virtual BOOL OnInitDialog();
+ virtual void OnOK();
+ afx_msg void OnPaint();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_SMPACKAGEINSTALLDLG_H__5E362C4C_CA11_4071_A8AB_A0231E985DAF__INCLUDED_)
diff --git a/stepmania/src/smpackage/StdAfx.cpp b/stepmania/src/smpackage/StdAfx.cpp
new file mode 100644
index 0000000000..7b6205853b
--- /dev/null
+++ b/stepmania/src/smpackage/StdAfx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// smpackage.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+
+
diff --git a/stepmania/src/smpackage/StdAfx.h b/stepmania/src/smpackage/StdAfx.h
new file mode 100644
index 0000000000..ea8977ee42
--- /dev/null
+++ b/stepmania/src/smpackage/StdAfx.h
@@ -0,0 +1,26 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__D450D5ED_5C49_4A8B_B887_076F62424F1F__INCLUDED_)
+#define AFX_STDAFX_H__D450D5ED_5C49_4A8B_B887_076F62424F1F__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include // MFC core and standard components
+#include // MFC extensions
+#include // MFC support for Internet Explorer 4 Common Controls
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__D450D5ED_5C49_4A8B_B887_076F62424F1F__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/Appnote.txt b/stepmania/src/smpackage/ZipArchive/Appnote.txt
new file mode 100644
index 0000000000..7b96643cad
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/Appnote.txt
@@ -0,0 +1,1192 @@
+Revised: 03/01/1999
+
+Disclaimer
+----------
+
+Although PKWARE will attempt to supply current and accurate
+information relating to its file formats, algorithms, and the
+subject programs, the possibility of error can not be eliminated.
+PKWARE therefore expressly disclaims any warranty that the
+information contained in the associated materials relating to the
+subject programs and/or the format of the files created or
+accessed by the subject programs and/or the algorithms used by
+the subject programs, or any other matter, is current, correct or
+accurate as delivered. Any risk of damage due to any possible
+inaccurate information is assumed by the user of the information.
+Furthermore, the information relating to the subject programs
+and/or the file formats created or accessed by the subject
+programs and/or the algorithms used by the subject programs is
+subject to change without notice.
+
+General Format of a ZIP file
+----------------------------
+
+ Files stored in arbitrary order. Large zipfiles can span multiple
+ diskette media.
+
+ Overall zipfile format:
+
+ [local file header + file data + data_descriptor] . . .
+ [central directory] end of central directory record
+
+
+ A. Local file header:
+
+ local file header signature 4 bytes (0x04034b50)
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ filename length 2 bytes
+ extra field length 2 bytes
+
+ filename (variable size)
+ extra field (variable size)
+
+ B. Data descriptor:
+
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+
+ This descriptor exists only if bit 3 of the general
+ purpose bit flag is set (see below). It is byte aligned
+ and immediately follows the last byte of compressed data.
+ This descriptor is used only when it was not possible to
+ seek in the output zip file, e.g., when the output zip file
+ was standard output or a non seekable device.
+
+ C. Central directory structure:
+
+ [file header] . . . end of central dir record
+
+ File header:
+
+ central file header signature 4 bytes (0x02014b50)
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ filename length 2 bytes
+ extra field length 2 bytes
+ file comment length 2 bytes
+ disk number start 2 bytes
+ internal file attributes 2 bytes
+ external file attributes 4 bytes
+ relative offset of local header 4 bytes
+
+ filename (variable size)
+ extra field (variable size)
+ file comment (variable size)
+
+ End of central dir record:
+
+ end of central dir signature 4 bytes (0x06054b50)
+ number of this disk 2 bytes
+ number of the disk with the
+ start of the central directory 2 bytes
+ total number of entries in
+ the central dir on this disk 2 bytes
+ total number of entries in
+ the central dir 2 bytes
+ size of the central directory 4 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 4 bytes
+ zipfile comment length 2 bytes
+ zipfile comment (variable size)
+
+ D. Explanation of fields:
+
+ version made by (2 bytes)
+
+ The upper byte indicates the compatibility of the file
+ attribute information. If the external file attributes
+ are compatible with MS-DOS and can be read by PKZIP for
+ DOS version 2.04g then this value will be zero. If these
+ attributes are not compatible, then this value will
+ identify the host system on which the attributes are
+ compatible. Software can use this information to determine
+ the line record format for text files etc. The current
+ mappings are:
+
+ 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)
+ 1 - Amiga 2 - VAX/VMS
+ 3 - Unix 4 - VM/CMS
+ 5 - Atari ST 6 - OS/2 H.P.F.S.
+ 7 - Macintosh 8 - Z-System
+ 9 - CP/M 10 - Windows NTFS
+ 11 thru 255 - unused
+
+ The lower byte indicates the version number of the
+ software used to encode the file. The value/10
+ indicates the major version number, and the value
+ mod 10 is the minor version number.
+
+ version needed to extract (2 bytes)
+
+ The minimum software version needed to extract the
+ file, mapped as above.
+
+ general purpose bit flag: (2 bytes)
+
+ Bit 0: If set, indicates that the file is encrypted.
+
+ (For Method 6 - Imploding)
+ Bit 1: If the compression method used was type 6,
+ Imploding, then this bit, if set, indicates
+ an 8K sliding dictionary was used. If clear,
+ then a 4K sliding dictionary was used.
+ Bit 2: If the compression method used was type 6,
+ Imploding, then this bit, if set, indicates
+ 3 Shannon-Fano trees were used to encode the
+ sliding dictionary output. If clear, then 2
+ Shannon-Fano trees were used.
+
+ (For Method 8 - Deflating)
+ Bit 2 Bit 1
+ 0 0 Normal (-en) compression option was used.
+ 0 1 Maximum (-ex) compression option was used.
+ 1 0 Fast (-ef) compression option was used.
+ 1 1 Super Fast (-es) compression option was used.
+
+ Note: Bits 1 and 2 are undefined if the compression
+ method is any other.
+
+ Bit 3: If this bit is set, the fields crc-32, compressed
+ size and uncompressed size are set to zero in the
+ local header. The correct values are put in the
+ data descriptor immediately following the compressed
+ data. (Note: PKZIP version 2.04g for DOS only
+ recognizes this bit for method 8 compression, newer
+ versions of PKZIP recognize this bit for any
+ compression method.)
+
+ Bit 4: Reserved for use with method 8, for enhanced
+ deflating.
+
+ Bit 5: If this bit is set, this indicates that the file is
+ compressed patched data. (Note: Requires PKZIP
+ version 2.70 or greater)
+
+ Bit 6: Currently unused.
+
+ Bit 7: Currently unused.
+
+ Bit 8: Currently unused.
+
+ Bit 9: Currently unused.
+
+ Bit 10: Currently unused.
+
+ Bit 11: Currently unused.
+
+ Bit 12: Reserved by PKWARE for enhanced compression.
+
+ Bit 13: Reserved by PKWARE.
+
+ Bit 14: Reserved by PKWARE.
+
+ Bit 15: Reserved by PKWARE.
+
+ compression method: (2 bytes)
+
+ (see accompanying documentation for algorithm
+ descriptions)
+
+ 0 - The file is stored (no compression)
+ 1 - The file is Shrunk
+ 2 - The file is Reduced with compression factor 1
+ 3 - The file is Reduced with compression factor 2
+ 4 - The file is Reduced with compression factor 3
+ 5 - The file is Reduced with compression factor 4
+ 6 - The file is Imploded
+ 7 - Reserved for Tokenizing compression algorithm
+ 8 - The file is Deflated
+ 9 - Reserved for enhanced Deflating
+ 10 - PKWARE Date Compression Library Imploding
+
+ date and time fields: (2 bytes each)
+
+ The date and time are encoded in standard MS-DOS format.
+ If input came from standard input, the date and time are
+ those at which compression was started for this data.
+
+ CRC-32: (4 bytes)
+
+ The CRC-32 algorithm was generously contributed by
+ David Schwaderer and can be found in his excellent
+ book "C Programmers Guide to NetBIOS" published by
+ Howard W. Sams & Co. Inc. The 'magic number' for
+ the CRC is 0xdebb20e3. The proper CRC pre and post
+ conditioning is used, meaning that the CRC register
+ is pre-conditioned with all ones (a starting value
+ of 0xffffffff) and the value is post-conditioned by
+ taking the one's complement of the CRC residual.
+ If bit 3 of the general purpose flag is set, this
+ field is set to zero in the local header and the correct
+ value is put in the data descriptor and in the central
+ directory.
+
+ compressed size: (4 bytes)
+ uncompressed size: (4 bytes)
+
+ The size of the file compressed and uncompressed,
+ respectively. If bit 3 of the general purpose bit flag
+ is set, these fields are set to zero in the local header
+ and the correct values are put in the data descriptor and
+ in the central directory.
+
+ filename length: (2 bytes)
+ extra field length: (2 bytes)
+ file comment length: (2 bytes)
+
+ The length of the filename, extra field, and comment
+ fields respectively. The combined length of any
+ directory record and these three fields should not
+ generally exceed 65,535 bytes. If input came from standard
+ input, the filename length is set to zero.
+
+ disk number start: (2 bytes)
+
+ The number of the disk on which this file begins.
+
+ internal file attributes: (2 bytes)
+
+ The lowest bit of this field indicates, if set, that
+ the file is apparently an ASCII or text file. If not
+ set, that the file apparently contains binary data.
+ The remaining bits are unused in version 1.0.
+
+ Bits 1 and 2 are reserved for use by PKWARE.
+
+ external file attributes: (4 bytes)
+
+ The mapping of the external attributes is
+ host-system dependent (see 'version made by'). For
+ MS-DOS, the low order byte is the MS-DOS directory
+ attribute byte. If input came from standard input, this
+ field is set to zero.
+
+ relative offset of local header: (4 bytes)
+
+ This is the offset from the start of the first disk on
+ which this file appears, to where the local header should
+ be found.
+
+ filename: (Variable)
+
+ The name of the file, with optional relative path.
+ The path stored should not contain a drive or
+ device letter, or a leading slash. All slashes
+ should be forward slashes '/' as opposed to
+ backwards slashes '\' for compatibility with Amiga
+ and Unix file systems etc. If input came from standard
+ input, there is no filename field.
+
+ extra field: (Variable)
+
+ This is for future expansion. If additional information
+ needs to be stored in the future, it should be stored
+ here. Earlier versions of the software can then safely
+ skip this file, and find the next file or header. This
+ field will be 0 length in version 1.0.
+
+ In order to allow different programs and different types
+ of information to be stored in the 'extra' field in .ZIP
+ files, the following structure should be used for all
+ programs storing data in this field:
+
+ header1+data1 + header2+data2 . . .
+
+ Each header should consist of:
+
+ Header ID - 2 bytes
+ Data Size - 2 bytes
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ The Header ID field indicates the type of data that is in
+ the following data block.
+
+ Header ID's of 0 thru 31 are reserved for use by PKWARE.
+ The remaining ID's can be used by third party vendors for
+ proprietary usage.
+
+ The current Header ID mappings defined by PKWARE are:
+
+ 0x0007 AV Info
+ 0x0009 OS/2
+ 0x000a NTFS
+ 0x000c VAX/VMS
+ 0x000d Unix
+ 0x000f Patch Descriptor
+
+ Several third party mappings commonly used are:
+
+ 0x4b46 FWKCS MD5 (see below)
+ 0x07c8 Macintosh
+ 0x4341 Acorn/SparkFS
+ 0x4453 Windows NT security descriptor (binary ACL)
+ 0x4704 VM/CMS
+ 0x470f MVS
+ 0x4c41 OS/2 access control list (text ACL)
+ 0x4d49 Info-ZIP VMS (VAX or Alpha)
+ 0x5455 extended timestamp
+ 0x5855 Info-ZIP Unix (original, also OS/2, NT, etc)
+ 0x6542 BeOS/BeBox
+ 0x756e ASi Unix
+ 0x7855 Info-ZIP Unix (new)
+ 0xfd4a SMS/QDOS
+
+ The Data Size field indicates the size of the following
+ data block. Programs can use this value to skip to the
+ next header block, passing over any data blocks that are
+ not of interest.
+
+ Note: As stated above, the size of the entire .ZIP file
+ header, including the filename, comment, and extra
+ field should not exceed 64K in size.
+
+ In case two different programs should appropriate the same
+ Header ID value, it is strongly recommended that each
+ program place a unique signature of at least two bytes in
+ size (and preferably 4 bytes or bigger) at the start of
+ each data area. Every program should verify that its
+ unique signature is present, in addition to the Header ID
+ value being correct, before assuming that it is a block of
+ known type.
+
+ -OS/2 Extra Field:
+
+ The following is the layout of the OS/2 attributes "extra"
+ block. (Last Revision 09/05/95)
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (OS/2) 0x0009 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size for the following data block
+ BSize 4 bytes Uncompressed Block Size
+ CType 2 bytes Compression type
+ EACRC 4 bytes CRC value for uncompress block
+ (var) variable Compressed block
+
+ The OS/2 extended attribute structure (FEA2LIST) is
+ compressed and then stored in it's entirety within this
+ structure. There will only ever be one "block" of data in
+ VarFields[].
+
+ -UNIX Extra Field:
+
+ The following is the layout of the Unix "extra" block.
+ Note: all fields are stored in Intel low-byte/high-byte
+ order.
+
+ Value Size Description
+ ----- ---- -----------
+ (UNIX) 0x000d 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size for the following data block
+ Atime 4 bytes File last access time
+ Mtime 4 bytes File last modification time
+ Uid 2 bytes File user ID
+ Gid 2 bytes File group ID
+ (var) variable Variable length data field
+
+ The variable length data field will contain file type
+ specific data. Currently the only values allowed are
+ the original "linked to" file names for hard or symbolic
+ links.
+
+ -VAX/VMS Extra Field:
+
+ The following is the layout of the VAX/VMS attributes
+ "extra" block.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (VMS) 0x000c 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the total "extra" block
+ CRC 4 bytes 32-bit CRC for remainder of the block
+ Tag1 2 bytes VMS attribute tag value #1
+ Size1 2 bytes Size of attribute #1, in bytes
+ (var.) Size1 Attribute #1 data
+ .
+ .
+ .
+ TagN 2 bytes VMS attribute tage value #N
+ SizeN 2 bytes Size of attribute #N, in bytes
+ (var.) SizeN Attribute #N data
+
+ Rules:
+
+ 1. There will be one or more of attributes present, which
+ will each be preceded by the above TagX & SizeX values.
+ These values are identical to the ATR$C_XXXX and
+ ATR$S_XXXX constants which are defined in ATR.H under
+ VMS C. Neither of these values will ever be zero.
+
+ 2. No word alignment or padding is performed.
+
+ 3. A well-behaved PKZIP/VMS program should never produce
+ more than one sub-block with the same TagX value. Also,
+ there will never be more than one "extra" block of type
+ 0x000c in a particular directory record.
+
+ -NTFS Extra Field:
+
+ The following is the layout of the NTFS attributes
+ "extra" block.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (NTFS) 0x000a 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the total "extra" block
+ Reserved 4 bytes Reserved for future use
+ Tag1 2 bytes NTFS attribute tag value #1
+ Size1 2 bytes Size of attribute #1, in bytes
+ (var.) Size1 Attribute #1 data
+ .
+ .
+ .
+ TagN 2 bytes NTFS attribute tage value #N
+ SizeN 2 bytes Size of attribute #N, in bytes
+ (var.) SizeN Attribute #N data
+
+ For NTFS, values for Tag1 through TagN are as follows:
+ (currently only one set of attributes is defined for NTFS)
+
+ Tag Size Description
+ ----- ---- -----------
+ 0x0001 2 bytes Tag for attribute #1
+ Size1 2 bytes Size of attribute #1, in bytes
+ Mtime 8 bytes File last modification time
+ Atime 8 bytes File last access time
+ Ctime 8 bytes File creation time
+
+ -PATCH Descriptor Extra Field:
+
+ The following is the layout of the Patch Descriptor "extra"
+ block.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (Patch) 0x000f 2 bytes Tag for this "extra" block type
+ TSize 2 bytes Size of the total "extra" block
+ Version 2 bytes Version of the descriptor
+ Flags 4 bytes Actions and reactions (see below)
+ OldSize 4 bytes Size of the file about to be patched
+ OldCRC 4 bytes 32-bit CRC of the file to be patched
+ NewSize 4 bytes Size of the resulting file
+ NewCRC 4 bytes 32-bit CRC of the resulting file
+
+ Actions and reactions
+
+ Bits Description
+ ---- ----------------
+ 0 Use for autodetection
+ 1 Treat as selfpatch
+ 2-3 RESERVED
+ 4-5 Action (see below)
+ 6-7 RESERVED
+ 8-9 Reaction (see below) to absent file
+ 10-11 Reaction (see below) to newer file
+ 12-13 Reaction (see below) to unknown file
+ 14-15 RESERVED
+ 16-31 RESERVED
+
+ Actions
+
+ Action Value
+ ------ -----
+ none 0
+ add 1
+ delete 2
+ patch 3
+
+ Reactions
+
+ Reaction Value
+ -------- -----
+ ask 0
+ skip 1
+ ignore 2
+ fail 3
+
+ - FWKCS MD5 Extra Field:
+
+ The FWKCS Contents_Signature System, used in
+ automatically identifying files independent of filename,
+ optionally adds and uses an extra field to support the
+ rapid creation of an enhanced contents_signature:
+
+ Header ID = 0x4b46
+ Data Size = 0x0013
+ Preface = 'M','D','5'
+ followed by 16 bytes containing the uncompressed file's
+ 128_bit MD5 hash(1), low byte first.
+
+ When FWKCS revises a zipfile central directory to add
+ this extra field for a file, it also replaces the
+ central directory entry for that file's uncompressed
+ filelength with a measured value.
+
+ FWKCS provides an option to strip this extra field, if
+ present, from a zipfile central directory. In adding
+ this extra field, FWKCS preserves Zipfile Authenticity
+ Verification; if stripping this extra field, FWKCS
+ preserves all versions of AV through PKZIP version 2.04g.
+
+ FWKCS, and FWKCS Contents_Signature System, are
+ trademarks of Frederick W. Kantor.
+
+ (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer
+ Science and RSA Data Security, Inc., April 1992.
+ ll.76-77: "The MD5 algorithm is being placed in the
+ public domain for review and possible adoption as a
+ standard."
+
+ file comment: (Variable)
+
+ The comment for this file.
+
+ number of this disk: (2 bytes)
+
+ The number of this disk, which contains central
+ directory end record.
+
+ number of the disk with the start of the central
+ directory: (2 bytes)
+
+ The number of the disk on which the central
+ directory starts.
+
+ total number of entries in the central dir on
+ this disk: (2 bytes)
+
+ The number of central directory entries on this disk.
+
+ total number of entries in the central dir: (2 bytes)
+
+ The total number of files in the zipfile.
+
+ size of the central directory: (4 bytes)
+
+ The size (in bytes) of the entire central directory.
+
+ offset of start of central directory with respect to
+ the starting disk number: (4 bytes)
+
+ Offset of the start of the central directory on the
+ disk on which the central directory starts.
+
+ zipfile comment length: (2 bytes)
+
+ The length of the comment for this zipfile.
+
+ zipfile comment: (Variable)
+
+ The comment for this zipfile.
+
+ D. General notes:
+
+ 1) All fields unless otherwise noted are unsigned and stored
+ in Intel low-byte:high-byte, low-word:high-word order.
+
+ 2) String fields are not null terminated, since the
+ length is given explicitly.
+
+ 3) Local headers should not span disk boundaries. Also, even
+ though the central directory can span disk boundaries, no
+ single record in the central directory should be split
+ across disks.
+
+ 4) The entries in the central directory may not necessarily
+ be in the same order that files appear in the zipfile.
+
+UnShrinking - Method 1
+----------------------
+
+Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
+with partial clearing. The initial code size is 9 bits, and
+the maximum code size is 13 bits. Shrinking differs from
+conventional Dynamic Ziv-Lempel-Welch implementations in several
+respects:
+
+1) The code size is controlled by the compressor, and is not
+ automatically increased when codes larger than the current
+ code size are created (but not necessarily used). When
+ the decompressor encounters the code sequence 256
+ (decimal) followed by 1, it should increase the code size
+ read from the input stream to the next bit size. No
+ blocking of the codes is performed, so the next code at
+ the increased size should be read from the input stream
+ immediately after where the previous code at the smaller
+ bit size was read. Again, the decompressor should not
+ increase the code size used until the sequence 256,1 is
+ encountered.
+
+2) When the table becomes full, total clearing is not
+ performed. Rather, when the compressor emits the code
+ sequence 256,2 (decimal), the decompressor should clear
+ all leaf nodes from the Ziv-Lempel tree, and continue to
+ use the current code size. The nodes that are cleared
+ from the Ziv-Lempel tree are then re-used, with the lowest
+ code value re-used first, and the highest code value
+ re-used last. The compressor can emit the sequence 256,2
+ at any time.
+
+Expanding - Methods 2-5
+-----------------------
+
+The Reducing algorithm is actually a combination of two
+distinct algorithms. The first algorithm compresses repeated
+byte sequences, and the second algorithm takes the compressed
+stream from the first algorithm and applies a probabilistic
+compression method.
+
+The probabilistic compression stores an array of 'follower
+sets' S(j), for j=0 to 255, corresponding to each possible
+ASCII character. Each set contains between 0 and 32
+characters, to be denoted as S(j)[0],...,S(j)[m], where m<32.
+The sets are stored at the beginning of the data area for a
+Reduced file, in reverse order, with S(255) first, and S(0)
+last.
+
+The sets are encoded as { N(j), S(j)[0],...,S(j)[N(j)-1] },
+where N(j) is the size of set S(j). N(j) can be 0, in which
+case the follower set for S(j) is empty. Each N(j) value is
+encoded in 6 bits, followed by N(j) eight bit character values
+corresponding to S(j)[0] to S(j)[N(j)-1] respectively. If
+N(j) is 0, then no values for S(j) are stored, and the value
+for N(j-1) immediately follows.
+
+Immediately after the follower sets, is the compressed data
+stream. The compressed data stream can be interpreted for the
+probabilistic decompression as follows:
+
+let Last-Character <- 0.
+loop until done
+ if the follower set S(Last-Character) is empty then
+ read 8 bits from the input stream, and copy this
+ value to the output stream.
+ otherwise if the follower set S(Last-Character) is non-empty then
+ read 1 bit from the input stream.
+ if this bit is not zero then
+ read 8 bits from the input stream, and copy this
+ value to the output stream.
+ otherwise if this bit is zero then
+ read B(N(Last-Character)) bits from the input
+ stream, and assign this value to I.
+ Copy the value of S(Last-Character)[I] to the
+ output stream.
+
+ assign the last value placed on the output stream to
+ Last-Character.
+end loop
+
+B(N(j)) is defined as the minimal number of bits required to
+encode the value N(j)-1.
+
+The decompressed stream from above can then be expanded to
+re-create the original file as follows:
+
+let State <- 0.
+
+loop until done
+ read 8 bits from the input stream into C.
+ case State of
+ 0: if C is not equal to DLE (144 decimal) then
+ copy C to the output stream.
+ otherwise if C is equal to DLE then
+ let State <- 1.
+
+ 1: if C is non-zero then
+ let V <- C.
+ let Len <- L(V)
+ let State <- F(Len).
+ otherwise if C is zero then
+ copy the value 144 (decimal) to the output stream.
+ let State <- 0
+
+ 2: let Len <- Len + C
+ let State <- 3.
+
+ 3: move backwards D(V,C) bytes in the output stream
+ (if this position is before the start of the output
+ stream, then assume that all the data before the
+ start of the output stream is filled with zeros).
+ copy Len+3 bytes from this position to the output stream.
+ let State <- 0.
+ end case
+end loop
+
+The functions F,L, and D are dependent on the 'compression
+factor', 1 through 4, and are defined as follows:
+
+For compression factor 1:
+ L(X) equals the lower 7 bits of X.
+ F(X) equals 2 if X equals 127 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 1 bit of X) * 256 + Y + 1.
+For compression factor 2:
+ L(X) equals the lower 6 bits of X.
+ F(X) equals 2 if X equals 63 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 2 bits of X) * 256 + Y + 1.
+For compression factor 3:
+ L(X) equals the lower 5 bits of X.
+ F(X) equals 2 if X equals 31 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 3 bits of X) * 256 + Y + 1.
+For compression factor 4:
+ L(X) equals the lower 4 bits of X.
+ F(X) equals 2 if X equals 15 otherwise F(X) equals 3.
+ D(X,Y) equals the (upper 4 bits of X) * 256 + Y + 1.
+
+Imploding - Method 6
+--------------------
+
+The Imploding algorithm is actually a combination of two distinct
+algorithms. The first algorithm compresses repeated byte
+sequences using a sliding dictionary. The second algorithm is
+used to compress the encoding of the sliding dictionary output,
+using multiple Shannon-Fano trees.
+
+The Imploding algorithm can use a 4K or 8K sliding dictionary
+size. The dictionary size used can be determined by bit 1 in the
+general purpose flag word; a 0 bit indicates a 4K dictionary
+while a 1 bit indicates an 8K dictionary.
+
+The Shannon-Fano trees are stored at the start of the compressed
+file. The number of trees stored is defined by bit 2 in the
+general purpose flag word; a 0 bit indicates two trees stored, a
+1 bit indicates three trees are stored. If 3 trees are stored,
+the first Shannon-Fano tree represents the encoding of the
+Literal characters, the second tree represents the encoding of
+the Length information, the third represents the encoding of the
+Distance information. When 2 Shannon-Fano trees are stored, the
+Length tree is stored first, followed by the Distance tree.
+
+The Literal Shannon-Fano tree, if present is used to represent
+the entire ASCII character set, and contains 256 values. This
+tree is used to compress any data not compressed by the sliding
+dictionary algorithm. When this tree is present, the Minimum
+Match Length for the sliding dictionary is 3. If this tree is
+not present, the Minimum Match Length is 2.
+
+The Length Shannon-Fano tree is used to compress the Length part
+of the (length,distance) pairs from the sliding dictionary
+output. The Length tree contains 64 values, ranging from the
+Minimum Match Length, to 63 plus the Minimum Match Length.
+
+The Distance Shannon-Fano tree is used to compress the Distance
+part of the (length,distance) pairs from the sliding dictionary
+output. The Distance tree contains 64 values, ranging from 0 to
+63, representing the upper 6 bits of the distance value. The
+distance values themselves will be between 0 and the sliding
+dictionary size, either 4K or 8K.
+
+The Shannon-Fano trees themselves are stored in a compressed
+format. The first byte of the tree data represents the number of
+bytes of data representing the (compressed) Shannon-Fano tree
+minus 1. The remaining bytes represent the Shannon-Fano tree
+data encoded as:
+
+ High 4 bits: Number of values at this bit length + 1. (1 - 16)
+ Low 4 bits: Bit Length needed to represent value + 1. (1 - 16)
+
+The Shannon-Fano codes can be constructed from the bit lengths
+using the following algorithm:
+
+1) Sort the Bit Lengths in ascending order, while retaining the
+ order of the original lengths stored in the file.
+
+2) Generate the Shannon-Fano trees:
+
+ Code <- 0
+ CodeIncrement <- 0
+ LastBitLength <- 0
+ i <- number of Shannon-Fano codes - 1 (either 255 or 63)
+
+ loop while i >= 0
+ Code = Code + CodeIncrement
+ if BitLength(i) <> LastBitLength then
+ LastBitLength=BitLength(i)
+ CodeIncrement = 1 shifted left (16 - LastBitLength)
+ ShannonCode(i) = Code
+ i <- i - 1
+ end loop
+
+3) Reverse the order of all the bits in the above ShannonCode()
+ vector, so that the most significant bit becomes the least
+ significant bit. For example, the value 0x1234 (hex) would
+ become 0x2C48 (hex).
+
+4) Restore the order of Shannon-Fano codes as originally stored
+ within the file.
+
+Example:
+
+ This example will show the encoding of a Shannon-Fano tree
+ of size 8. Notice that the actual Shannon-Fano trees used
+ for Imploding are either 64 or 256 entries in size.
+
+Example: 0x02, 0x42, 0x01, 0x13
+
+ The first byte indicates 3 values in this table. Decoding the
+ bytes:
+ 0x42 = 5 codes of 3 bits long
+ 0x01 = 1 code of 2 bits long
+ 0x13 = 2 codes of 4 bits long
+
+ This would generate the original bit length array of:
+ (3, 3, 3, 3, 3, 2, 4, 4)
+
+ There are 8 codes in this table for the values 0 thru 7. Using
+ the algorithm to obtain the Shannon-Fano codes produces:
+
+ Reversed Order Original
+Val Sorted Constructed Code Value Restored Length
+--- ------ ----------------- -------- -------- ------
+0: 2 1100000000000000 11 101 3
+1: 3 1010000000000000 101 001 3
+2: 3 1000000000000000 001 110 3
+3: 3 0110000000000000 110 010 3
+4: 3 0100000000000000 010 100 3
+5: 3 0010000000000000 100 11 2
+6: 4 0001000000000000 1000 1000 4
+7: 4 0000000000000000 0000 0000 4
+
+The values in the Val, Order Restored and Original Length columns
+now represent the Shannon-Fano encoding tree that can be used for
+decoding the Shannon-Fano encoded data. How to parse the
+variable length Shannon-Fano values from the data stream is beyond
+the scope of this document. (See the references listed at the end of
+this document for more information.) However, traditional decoding
+schemes used for Huffman variable length decoding, such as the
+Greenlaw algorithm, can be successfully applied.
+
+The compressed data stream begins immediately after the
+compressed Shannon-Fano data. The compressed data stream can be
+interpreted as follows:
+
+loop until done
+ read 1 bit from input stream.
+
+ if this bit is non-zero then (encoded data is literal data)
+ if Literal Shannon-Fano tree is present
+ read and decode character using Literal Shannon-Fano tree.
+ otherwise
+ read 8 bits from input stream.
+ copy character to the output stream.
+ otherwise (encoded data is sliding dictionary match)
+ if 8K dictionary size
+ read 7 bits for offset Distance (lower 7 bits of offset).
+ otherwise
+ read 6 bits for offset Distance (lower 6 bits of offset).
+
+ using the Distance Shannon-Fano tree, read and decode the
+ upper 6 bits of the Distance value.
+
+ using the Length Shannon-Fano tree, read and decode
+ the Length value.
+
+ Length <- Length + Minimum Match Length
+
+ if Length = 63 + Minimum Match Length
+ read 8 bits from the input stream,
+ add this value to Length.
+
+ move backwards Distance+1 bytes in the output stream, and
+ copy Length characters from this position to the output
+ stream. (if this position is before the start of the output
+ stream, then assume that all the data before the start of
+ the output stream is filled with zeros).
+end loop
+
+Tokenizing - Method 7
+--------------------
+
+This method is not used by PKZIP.
+
+Deflating - Method 8
+-----------------
+
+The Deflate algorithm is similar to the Implode algorithm using
+a sliding dictionary of up to 32K with secondary compression
+from Huffman/Shannon-Fano codes.
+
+The compressed data is stored in blocks with a header describing
+the block and the Huffman codes used in the data block. The header
+format is as follows:
+
+ Bit 0: Last Block bit This bit is set to 1 if this is the last
+ compressed block in the data.
+ Bits 1-2: Block type
+ 00 (0) - Block is stored - All stored data is byte aligned.
+ Skip bits until next byte, then next word = block
+ length, followed by the ones compliment of the block
+ length word. Remaining data in block is the stored
+ data.
+
+ 01 (1) - Use fixed Huffman codes for literal and distance codes.
+ Lit Code Bits Dist Code Bits
+ --------- ---- --------- ----
+ 0 - 143 8 0 - 31 5
+ 144 - 255 9
+ 256 - 279 7
+ 280 - 287 8
+
+ Literal codes 286-287 and distance codes 30-31 are
+ never used but participate in the huffman construction.
+
+ 10 (2) - Dynamic Huffman codes. (See expanding Huffman codes)
+
+ 11 (3) - Reserved - Flag a "Error in compressed data" if seen.
+
+Expanding Huffman Codes
+-----------------------
+If the data block is stored with dynamic Huffman codes, the Huffman
+codes are sent in the following compressed format:
+
+ 5 Bits: # of Literal codes sent - 256 (256 - 286)
+ All other codes are never sent.
+ 5 Bits: # of Dist codes - 1 (1 - 32)
+ 4 Bits: # of Bit Length codes - 3 (3 - 19)
+
+The Huffman codes are sent as bit lengths and the codes are built as
+described in the implode algorithm. The bit lengths themselves are
+compressed with Huffman codes. There are 19 bit length codes:
+
+ 0 - 15: Represent bit lengths of 0 - 15
+ 16: Copy the previous bit length 3 - 6 times.
+ The next 2 bits indicate repeat length (0 = 3, ... ,3 = 6)
+ Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will
+ expand to 12 bit lengths of 8 (1 + 6 + 5)
+ 17: Repeat a bit length of 0 for 3 - 10 times. (3 bits of length)
+ 18: Repeat a bit length of 0 for 11 - 138 times (7 bits of length)
+
+The lengths of the bit length codes are sent packed 3 bits per value
+(0 - 7) in the following order:
+
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+
+The Huffman codes should be built as described in the Implode algorithm
+except codes are assigned starting at the shortest bit length, i.e. the
+shortest code should be all 0's rather than all 1's. Also, codes with
+a bit length of zero do not participate in the tree construction. The
+codes are then used to decode the bit lengths for the literal and
+distance tables.
+
+The bit lengths for the literal tables are sent first with the number
+of entries sent described by the 5 bits sent earlier. There are up
+to 286 literal characters; the first 256 represent the respective 8
+bit character, code 256 represents the End-Of-Block code, the remaining
+29 codes represent copy lengths of 3 thru 258. There are up to 30
+distance codes representing distances from 1 thru 32k as described
+below.
+
+ Length Codes
+ ------------
+ Extra Extra Extra Extra
+ Code Bits Length Code Bits Lengths Code Bits Lengths Code Bits Length(s)
+ ---- ---- ------ ---- ---- ------- ---- ---- ------- ---- ---- ---------
+ 257 0 3 265 1 11,12 273 3 35-42 281 5 131-162
+ 258 0 4 266 1 13,14 274 3 43-50 282 5 163-194
+ 259 0 5 267 1 15,16 275 3 51-58 283 5 195-226
+ 260 0 6 268 1 17,18 276 3 59-66 284 5 227-257
+ 261 0 7 269 2 19-22 277 4 67-82 285 0 258
+ 262 0 8 270 2 23-26 278 4 83-98
+ 263 0 9 271 2 27-30 279 4 99-114
+ 264 0 10 272 2 31-34 280 4 115-130
+
+ Distance Codes
+ --------------
+ Extra Extra Extra Extra
+ Code Bits Dist Code Bits Dist Code Bits Distance Code Bits Distance
+ ---- ---- ---- ---- ---- ------ ---- ---- -------- ---- ---- --------
+ 0 0 1 8 3 17-24 16 7 257-384 24 11 4097-6144
+ 1 0 2 9 3 25-32 17 7 385-512 25 11 6145-8192
+ 2 0 3 10 4 33-48 18 8 513-768 26 12 8193-12288
+ 3 0 4 11 4 49-64 19 8 769-1024 27 12 12289-16384
+ 4 1 5,6 12 5 65-96 20 9 1025-1536 28 13 16385-24576
+ 5 1 7,8 13 5 97-128 21 9 1537-2048 29 13 24577-32768
+ 6 2 9-12 14 6 129-192 22 10 2049-3072
+ 7 2 13-16 15 6 193-256 23 10 3073-4096
+
+The compressed data stream begins immediately after the
+compressed header data. The compressed data stream can be
+interpreted as follows:
+
+do
+ read header from input stream.
+
+ if stored block
+ skip bits until byte aligned
+ read count and 1's compliment of count
+ copy count bytes data block
+ otherwise
+ loop until end of block code sent
+ decode literal character from input stream
+ if literal < 256
+ copy character to the output stream
+ otherwise
+ if literal = end of block
+ break from loop
+ otherwise
+ decode distance from input stream
+
+ move backwards distance bytes in the output stream, and
+ copy length characters from this position to the output
+ stream.
+ end loop
+while not last block
+
+if data descriptor exists
+ skip bits until byte aligned
+ read crc and sizes
+endif
+
+Decryption
+----------
+
+The encryption used in PKZIP was generously supplied by Roger
+Schlafly. PKWARE is grateful to Mr. Schlafly for his expert
+help and advice in the field of data encryption.
+
+PKZIP encrypts the compressed data stream. Encrypted files must
+be decrypted before they can be extracted.
+
+Each encrypted file has an extra 12 bytes stored at the start of
+the data area defining the encryption header for that file. The
+encryption header is originally set to random values, and then
+itself encrypted, using three, 32-bit keys. The key values are
+initialized using the supplied encryption password. After each byte
+is encrypted, the keys are then updated using pseudo-random number
+generation techniques in combination with the same CRC-32 algorithm
+used in PKZIP and described elsewhere in this document.
+
+The following is the basic steps required to decrypt a file:
+
+1) Initialize the three 32-bit keys with the password.
+2) Read and decrypt the 12-byte encryption header, further
+ initializing the encryption keys.
+3) Read and decrypt the compressed data stream using the
+ encryption keys.
+
+Step 1 - Initializing the encryption keys
+-----------------------------------------
+
+Key(0) <- 305419896
+Key(1) <- 591751049
+Key(2) <- 878082192
+
+loop for i <- 0 to length(password)-1
+ update_keys(password(i))
+end loop
+
+Where update_keys() is defined as:
+
+update_keys(char):
+ Key(0) <- crc32(key(0),char)
+ Key(1) <- Key(1) + (Key(0) & 000000ffH)
+ Key(1) <- Key(1) * 134775813 + 1
+ Key(2) <- crc32(key(2),key(1) >> 24)
+end update_keys
+
+Where crc32(old_crc,char) is a routine that given a CRC value and a
+character, returns an updated CRC value after applying the CRC-32
+algorithm described elsewhere in this document.
+
+Step 2 - Decrypting the encryption header
+-----------------------------------------
+
+The purpose of this step is to further initialize the encryption
+keys, based on random data, to render a plaintext attack on the
+data ineffective.
+
+Read the 12-byte encryption header into Buffer, in locations
+Buffer(0) thru Buffer(11).
+
+loop for i <- 0 to 11
+ C <- buffer(i) ^ decrypt_byte()
+ update_keys(C)
+ buffer(i) <- C
+end loop
+
+Where decrypt_byte() is defined as:
+
+unsigned char decrypt_byte()
+ local unsigned short temp
+ temp <- Key(2) | 2
+ decrypt_byte <- (temp * (temp ^ 1)) >> 8
+end decrypt_byte
+
+After the header is decrypted, the last 1 or 2 bytes in Buffer
+should be the high-order word/byte of the CRC for the file being
+decrypted, stored in Intel low-byte/high-byte order. Versions of
+PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is
+used on versions after 2.0. This can be used to test if the password
+supplied is correct or not.
+
+Step 3 - Decrypting the compressed data stream
+----------------------------------------------
+
+The compressed data stream can be decrypted as follows:
+
+loop until done
+ read a character into C
+ Temp <- C ^ decrypt_byte()
+ update_keys(temp)
+ output Temp
+end loop
+
+In addition to the above mentioned contributors to PKZIP and PKUNZIP,
+I would like to extend special thanks to Robert Mahoney for suggesting
+the extension .ZIP for this software.
+
+References:
+
+ Fiala, Edward R., and Greene, Daniel H., "Data compression with
+ finite windows", Communications of the ACM, Volume 32, Number 4,
+ April 1989, pages 490-505.
+
+ Held, Gilbert, "Data Compression, Techniques and Applications,
+ Hardware and Software Considerations", John Wiley & Sons, 1987.
+
+ Huffman, D.A., "A method for the construction of minimum-redundancy
+ codes", Proceedings of the IRE, Volume 40, Number 9, September 1952,
+ pages 1098-1101.
+
+ Nelson, Mark, "LZW Data Compression", Dr. Dobbs Journal, Volume 14,
+ Number 10, October 1989, pages 29-37.
+
+ Nelson, Mark, "The Data Compression Book", M&T Books, 1991.
+
+ Storer, James A., "Data Compression, Methods and Theory",
+ Computer Science Press, 1988
+
+ Welch, Terry, "A Technique for High-Performance Data Compression",
+ IEEE Computer, Volume 17, Number 6, June 1984, pages 8-19.
+
+ Ziv, J. and Lempel, A., "A universal algorithm for sequential data
+ compression", Communications of the ACM, Volume 30, Number 6,
+ June 1987, pages 520-540.
+
+ Ziv, J. and Lempel, A., "Compression of individual sequences via
+ variable-rate coding", IEEE Transactions on Information Theory,
+ Volume 24, Number 5, September 1978, pages 530-536.
diff --git a/stepmania/src/smpackage/ZipArchive/CodeProject.html b/stepmania/src/smpackage/ZipArchive/CodeProject.html
new file mode 100644
index 0000000000..82a927b70b
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/CodeProject.html
@@ -0,0 +1,380 @@
+
+
+
+
+The Code Project
+
+
+
+
+
+
+
+
+Title: Zip and Unzip in the MFC way
+Author: Tadeusz Dracz
+Email: tdracz@artpol.com.pl
+Environment: VC++ 6.0, MFC, Windows 95/98/NT/2000/Me
+Keywords: Zip, Unzip, MFC
+Level: Intermediate
+Description: The library to create, modify and extract zip archives
+Section Miscellaneous
+SubSection General
+
+
+
+
+
+
+ - Download source - 110 Kb
+ - Download demo project - 40 Kb
+Overview
+This library allows creating, modifying and extracting zip archives in the
+compatible way with PKZIP (2.5 and higher) and WinZip. Supported are all
+possible operations on the zip archive: creating, extracting, adding, deleting
+files from the archive, modifications of the existing archive. There is also the
+support for creating and extracting multiple disk archives (on non-removable
+devices as well) and for password encryption and decryption. This module uses
+compression and decompression functions from zlib library by Jean-loup Gailly
+and Mark Adler.
+How to integrate with the project
+Zip is a static library and statically links to compiled zlib.lib (version
+1.13 nowadays). The zlib library can be replaced with a newer version providing
+you also replace the files: "zlib.h" and "zconf.h" in the
+Zip project. The Zip library uses MFC in a shared library as a Release and Debug
+Configuration. Your project must use MFC in the same way in the appropriate
+project configuration. You may need to adapt this to your needs. To add Zip
+library functionality to your project you need to link the library to the
+project. You can do this in at least two ways (in both cases you need to include
+ZipArchive.h header in your sources like this: #include "ZipArchive.h"):
+Method 1
+Add "..\Zip\debug(release)\Zip.lib" to Project
+Settings->Link->Input->Object/library modules and add Zip
+directory to the preprocessor searches (Project Settings -> C++ ->
+Preprocessor -> Additional include directories).
+Method 2 (simpler)
+Insert Zip project into workspace and set project dependencies (your project
+dependent on Zip project).
+How to use
+The details about using this library are in the sources. The example
+available for download at the bottom of the page is an almost complete
+compression\decompression program. There are only main issues mentioned below
+about using this library. If you have a question about using the library and you
+can't find the answer here, don't hesitate to ask.
+Compression and decompression
+There are some functions defined for fast operations on archive; among
+others: AddNewFile(), ExtractFile(), DeleteFile(). You only need to call
+functions Open() - before and Close() - after using them.
+Remember to call Close() function when you finish working with CZipArchive
+class.
+Multi-disk archives
+This library supports two kinds of multi-disk archives:
+1. Disk spanning performed in the compatible way with all other main zip
+programs. It means that the archive can only be created on a removable device,
+the size of the volume is auto-detected and the label is written to the disk. To
+use this kind of disk spanning you need to define a static callback function for
+changing disks and set it with SetSpanCallback() function.
+2. Disk spanning performed in the internal mode, called in the sources TD span
+mode. This allows creating multi disk archives also on non-removable devices and
+with user-defined volume size. There is no need to set callback function in this
+mode.
+This two disk spanning modes create volumes with compatible internal
+structure. It means that you can easily convert the volumes created in one mode
+to the other one by renaming the files (in TD mode each volume but last has a
+number as an extension). To convert the archive from TD to PKZIP compatible
+archive, copy each file to the removable media, giving them the extension
+".zip". You should also label each disk with the appropriate label
+starting from "pkback# 001".
+There is a limited functions set available during work with multi-disk
+archives. Only adding is allowed when creating an archive and only extracting
+and testing when opening an existing one. Deleting files from these archives
+isn't allowed in any of these cases.
+Class CZipArchive uses write buffer to make write operations extremely fast.
+You can change its size with SetAdvanced() function. While creating a multi-disk
+archive, set the size of the buffer to the maximum size of the volume for
+the best performance.
+The popular archivers such as PKZIP and WinZip cannot operate on archive in
+TD span mode. You need to convert them to PKZIP span mode (have a look above).
+Remember about copying the files to the removable media (it does not comply with
+Winzip, which can extract a multi-disk archive from any media but only from the
+fixed location on the drive).
+Password encryption and decryption
+ This library supports creating and extracting of the
+password protected archives. There are several issues you should be aware of
+when using this feature. To set the password for the file to be added or
+extracted call the function SetPassword() with the password as the argument. To
+clear the password call this function without arguments or with an empty string
+argument. The function has no effect on a closed archive and on the currently
+opened file (whether new or existing) inside archive. During opening an archive
+the password is cleared and it is not changed if the file inside archive is
+opened. You can set different passwords for different files inside the same
+archive, but remember to set it BEFORE opening the file. You cannot use ASCII
+characters with codes above 127 in a password, if you do so, the function
+SetPassword() returns false and the password is cleared. If the password is
+cleared, no encryption or decryption take place.
+ You can find out what files are password encrypted by calling
+CZipArchive::GetFileInfo() which fills the structrure CZipFileHeader with data,
+and then the method IsEncrypted() of this structure. If it returns true, the
+file needs a password to extract.
+ The successful extraction of the encrypted file doesn't always mean
+that the password is correct. CZipArchive doesn't check for a crc if
+m_info.m_uUncomprLeft is not zero in the function CZipArchive::CloseFile(). In
+some cases bad password causes that this value is not zero, so you have to check
+also for the return value of this function (it returns -1 in this case). You can
+also check the size of the extracted file since it is smaller than it should be.
+Self extract support
+The library automatically detects self-extracting archives. This is the
+simplest self-extract code :
+
+
+int APIENTRY WinMain(HINSTANCE hInstance,
+HINSTANCE hPrevInstance,
+LPSTR lpCmdLine,
+int nCmdShow)
+{
+ CZipArchive zip;
+
+ // get path of executable
+ TCHAR szBuff[_MAX_PATH];
+ if (!::GetModuleFileName(hInstance, szBuff, _MAX_PATH))
+ return -1;
+
+ CString szDest;
+ // ...
+ // add the code here to get the destination directory from the user
+ // for example:
+ /* CBrowseForFolder bf;
+ bf.strTitle = _T("Select directory to extract files");
+ if (!bf.GetFolder(szDest))
+ return -1;
+ */
+ // class CBrowseForFolder is included in the example project
+ // remember about including the header!
+
+ zip.Open(szBuff, CZipArchive::openReadOnly);
+ // openReadOnly mode is necessary for self extract archives
+ for (WORD i = 0; i < zip.GetNoEntries(); i++)
+ zip.ExtractFile(i, szDest);
+
+ zip.Close();
+ return 0;
+ // this code will not work for the encrypted archives since it is needed
+ // to get the password from the user ( a small addition to the
+ // existing code I suppose )
+}
+
+
+
+After compiling it and appending a zip archive to it (e.g. with the DOS
+command: copy /b SelfExtract.exe + ZipFile.zip FinalFile.exe) we have a
+self extracting archive.
+Testing the integrity of the archive
+The new functions has been provided to allow the testing of the integrity of
+the archive. The first one is CZipArchive::TestFile which is a
+comprehensive testing function, but if you need a different functionality, you
+can make your own by taking advantage of the second function provided: CZipArchive::CloseFileAfterTestFailed.
+The detailed description and the example of use are provided in the sources
+and in the example project.
+Exceptions
+The library throws the following exceptions: CMemoryException, CFileExeption
+and CZipException. The first two don't need an explanation. The last is thrown
+when some internal error occurs. Handling them may be done in the following way:
+
+try
+{
+ // ...
+ // some operations on Zip library
+}
+catch (CException* e)
+{
+ if (e->IsKindOf( RUNTIME_CLASS( CZipException )))
+ {
+ CZipException* p = (CZipException*) e;
+ //... and so on
+ }
+ else if (e->IsKindOf( RUNTIME_CLASS( CFileException )))
+ {
+ CFileException* p = (CFileException*) e;
+ //... and so on
+ }
+ else
+ {
+ // the only possibility is a memory exception I suppose
+ //... and so on
+ }
+ e->Delete();
+}
+
+Handling the extra field
+The extra field of the file can be different in the local and central
+headers. To set the extra filed in the local header set it in header
+parameter of CZipArchive::OpenNewFile function. After
+that the extra field is written to the local header and cleared. You should call
+CZipArchive::SetExtraField function anytime after opening the new file
+(but before closing it) to set the file extra field in the central directory.
+Sample application
+To run the example, integrate first Zip library into it (Zip library is not
+included in the example, you must download it separately); you should be asked
+at the beginning about the location of the Zip project, if not, use one of the
+integration methods described above. If you don't put Zip library project at the
+same directory level what the sample application is, you also have to change the path pointing
+to ZipArchive.h in the file testzipdlgdlg.h.
+ Linking errors
+ When you experience linking errors (mostly LNK2005) you need to
+ make sure that the library and your program are both using
+ single-threaded or both multithreaded library. The option "Project->Settings->
+ c/c++ ->Code Generation->Use run-time library" should be set
+ to the same value in the ZipArchive library and the program project options.
+
If it doesn't help, try recompiling the zlib library ( zlib.lib
+ provided with the project is compiled from a release configuration and using Multithreaded
+ DLL run-time library ). You can download the zlib library
+ sources from http://software.artpol.com.pl/d_zip.html.
+ Use zlibstat project. Set "Use run-time library"
+ option to the same value as you set it in ZipArchve library and your program
+ configurations. Compile the Release configuration of the zlib library and
+ replace with it the file zlib.lib in the ZipArchive folder. You may
+ however experience linking warnings or errors while compiling the Debug
+ configuration. To eliminate them do as follows:
+
+ - compile Debug and Release configuraions of the zlib library
+
- copy zlib_d.lib from Debug and zlib.lib from Release
+ directories to the ZipArchive directory
+
- add these files to the ZipArchive project (Project -> Add To
+ Project -> Files...)
+
- go to the project setting dialog (Project -> Settings)
+
- select debug configurations (Setting For -> Multiple
+ Configurations) such as Debug and Unicode Debug
+
- select zlib.lib file, then the General tab, and check the box "Exclude
+ file from build"
+
- select release configurations
+
- select zlib_.lib and exclude it from these builds
+
+
+To Do and updates
+I currently work on the non-MFC version of the library and a multi-platform
+support. Make sure to check out the site http://software.artpol.com.pl
+which is more likely to have an updated version.
+Downloads
+
+
+Download source - 110 KB
+Download example - 40 KB
+History
+03.2001
+
+ - when the central directory was not located, the library throws
+ CZipException::cdirNotFound,
+ which allows distinguish from other exceptions (useful when we want to keep
+ prompting
+ the user to insert the last disk in a multi-disk spanning archive).
+
+
+
+
+
+02.2001
+
+ - Features added:
+
-
+
+ - ability to reuse the archive after an exception thrown during
+ extraction
+
- added progress control possibilities to CZipArchive::AddNewFile,
+ CZipArchive::ExtractFile, CZipArchive::TestFile
+
+
+
+
+ - Changes:
+
-
+
+ - CZipArchive::FindFile operation boosted ( thanks to Darin Warling for
+ the idea)
+
- library name changed to ZipArchive
+
+
+
+
+ - Bugs fixed:
+
-
+
+ - removed bug during extracting an encrypted file with 0 size
+
- fixed bug when extracting a file with an extra field in a local file
+ header (CZipFileHeader::ReadLocal)
+
+
+
+01.2001
+
+ - Disk numbering in a disk spanning archive begins now from PKBACK# 001 not
+ PKBACK# 000
+
- Adding and extracting without a full path possible in
+ CZipArchive::AddNewFile and CZipArchive::ExtractFile.
+
- Several minor changes and enhancements
+
- Changed names for several classes.
+
+11.2000
+
+ - Added support for password encryption and decryption. The encryption used
+ in PKZIP was generously supplied by Roger Schlafly.
+
- Testing the archive made easier
+
- Unicode support added
+
+08.2000
+
+06.2000
+the code has been completely rewritten since the very beginning; the main
+improvements are:
+
+ - multi-disk archive support
+
- creation of the disk spanning archives with the user-defined volume size
+
- ability to modify existing archives (add, delete files)
+
- modification self-extracting archives
+
- write buffer used for faster disk write operations
+
- one class for zip and unzip functions
+
- fast adding, deleting and extracting files with a single function call
+
+03.2000
+
+ - international characters in filenames inside archive are now converted in
+ a compatible way with other archiving programs (they are stored converted to
+ OEM inside archive).
+
+01.2000
+first version; it is just modified code from zip.c and unzip.c files written
+by Gilles Vollant and distributed with zlib library; the modifications are as
+follows:
+
+ - added class' wrappers
+
- several bugs fixed
+
- several enhancements added
+
- MFC support added
+
- memory leaks eliminated when write error occurred
+
- automatically free used memory on destruction or exception
+
- modern error notification using exceptions
+
+
+
diff --git a/stepmania/src/smpackage/ZipArchive/StdAfx.cpp b/stepmania/src/smpackage/ZipArchive/StdAfx.cpp
new file mode 100644
index 0000000000..35efe037ed
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/StdAfx.cpp
@@ -0,0 +1,6 @@
+// stdafx.cpp : source file that includes just the standard includes
+// Zip.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/stepmania/src/smpackage/ZipArchive/StdAfx.h b/stepmania/src/smpackage/ZipArchive/StdAfx.h
new file mode 100644
index 0000000000..fef7146336
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/StdAfx.h
@@ -0,0 +1,23 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__926F70F4_1B34_49AA_9532_498E8D2F3495__INCLUDED_)
+#define AFX_STDAFX_H__926F70F4_1B34_49AA_9532_498E8D2F3495__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include
+#include
+
+// TODO: reference additional headers your program requires here
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__926F70F4_1B34_49AA_9532_498E8D2F3495__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipArchive.cpp b/stepmania/src/smpackage/ZipArchive/ZipArchive.cpp
new file mode 100644
index 0000000000..ccff2a4545
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipArchive.cpp
@@ -0,0 +1,1381 @@
+// ZipArchive.cpp: implementation of the CZipArchive class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ZipArchive.h"
+#include
+#include // for qsort
+
+
+#ifndef DEF_MEM_LEVEL
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+#endif
+#define ENCR_HEADER_LEN 12
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+TCHAR CZipArchive::m_gszCopyright[] = {_T("Zip archive creation and modification Copyright 2000 Tadeusz Dracz")};
+CZipArchive::CZipArchive()
+{
+ m_bDetectZlibMemoryLeaks = true;
+ m_centralDir.m_pStorage= &m_storage;
+ m_info.m_stream.zalloc = (alloc_func)myalloc;
+ m_info.m_stream.zfree = (free_func)myfree;
+ m_iFileOpened = nothing;
+}
+
+
+CZipArchive::~CZipArchive()
+{
+ // Close(); // cannot be here: if an exception is thrown strange things can happen
+ EmptyPtrList();
+}
+
+void CZipArchive::Open(LPCTSTR szPathName, int iMode, int iVolumeSize)
+{
+ if (!IsClosed())
+ {
+ TRACE(_T("ZipArchive already opened.\n"));
+ return;
+ }
+ m_pszPassword.Release();
+ m_iFileOpened = nothing;
+ m_storage.Open(szPathName, iMode, iVolumeSize);
+ m_centralDir.Init();
+ if ((iMode == open) ||(iMode == openReadOnly))
+ m_centralDir.Read();
+}
+
+void CZipArchive::Open(CMemFile& mf, int iMode)
+{
+ if (!IsClosed())
+ {
+ TRACE(_T("ZipArchive already opened.\n"));
+ return;
+ }
+ if (iMode != open && iMode != openReadOnly && iMode != create)
+ {
+ TRACE(_T("Mode not supported.\n"));
+ return;
+ }
+ m_pszPassword.Release();
+ m_iFileOpened = nothing;
+ m_storage.Open(mf, iMode);
+ m_centralDir.Init();
+ if ((iMode == open) ||(iMode == openReadOnly))
+ m_centralDir.Read();
+}
+
+
+bool CZipArchive::IsClosed(bool bArchive)
+{
+ return bArchive ?(m_storage.GetCurrentDisk() == -1):(!m_storage.m_pFile || m_storage.m_pFile->m_hFile == CFile::hFileNull);
+}
+
+
+void CZipArchive::ThrowError(int err)
+{
+ AfxThrowZipException(err, IsClosed() ? _T("") : m_storage.m_pFile->GetFilePath());
+}
+
+bool CZipArchive::DeleteFile(WORD uIndex)
+{
+ if (m_storage.IsSpanMode())
+ {
+ TRACE(_T("You cannot delete files from the disk spannig archive.\n"));
+ return false;
+ }
+
+ if (m_iFileOpened)
+ {
+ TRACE(_T("You cannot delete files if there is a file opened.\n"));
+ return false;
+ }
+
+ if (!m_centralDir.IsValidIndex(uIndex))
+ return false;
+
+ m_info.Init();
+ m_centralDir.RemoveFromDisk();
+ DeleteInternal(uIndex);
+ m_info.m_pBuffer.Release();
+ return true;
+}
+
+int CZipArchive::GetNoEntries()
+{
+ return m_centralDir.m_headers.GetSize();
+}
+
+
+bool CZipArchive::GetFileInfo(CZipFileHeader & fhInfo, WORD uIndex)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return false;
+ }
+
+ if (!m_centralDir.IsValidIndex(uIndex))
+ return false;
+
+ fhInfo = *(m_centralDir.m_headers[uIndex]);
+ m_centralDir.ConvertFileName(true, false, &fhInfo);
+ return true;
+}
+
+int CZipArchive::FindFile(CString szFileName, bool bCaseSensitive)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return (int)-1;
+ }
+ // this is required for fast finding and is done only once
+ if (!m_centralDir.m_bConvertAfterOpen)
+ {
+ TRACE(_T("Converting all filenames."));
+ m_centralDir.ConvertAll();
+ }
+ if (!m_centralDir.m_bFindFastEnabled)
+ EnableFindFast();
+ int iResult = m_centralDir.FindFileNameIndex(szFileName, bCaseSensitive);
+ return iResult == -1 ? -1 : m_centralDir.m_findarray[iResult].m_uIndex;
+}
+
+bool CZipArchive::OpenFile(WORD uIndex)
+{
+ if (!m_centralDir.IsValidIndex(uIndex))
+ return false;
+
+ if (m_storage.IsSpanMode() == 1)
+ {
+ TRACE(_T("You cannot extract from the span in creation.\n"));
+ return false;
+ }
+
+
+ if (m_iFileOpened)
+ {
+ TRACE(_T("A file already opened.\n"));
+ return false;
+ }
+
+ m_info.Init();
+ m_centralDir.OpenFile(uIndex);
+ if (CurrentFile()->IsEncrypted())
+ {
+
+ if (m_pszPassword.GetSize() == 0)
+ {
+ TRACE(_T("Password not set for the encrypted file.\n"));
+ return false;
+ }
+ CryptInitKeys();
+ if (!CryptCheck())
+ ThrowError(ZIP_BADPASSWORD); // invalid password
+
+ }
+ else if (m_pszPassword.GetSize() != 0)
+ {
+ TRACE(_T("Password set for a not encrypted file. Ignoring password.\n"));
+ }
+
+ WORD uMethod = CurrentFile()->m_uMethod;
+ if ((uMethod != 0) &&(uMethod != Z_DEFLATED))
+ ThrowError(ZIP_BADZIPFILE);
+
+ if (uMethod == Z_DEFLATED)
+ {
+ m_info.m_stream.opaque = m_bDetectZlibMemoryLeaks ? &m_list : 0;
+ int err = inflateInit2(&m_info.m_stream, -MAX_WBITS);
+ // * windowBits is passed < 0 to tell that there is no zlib header.
+ // * Note that in this case inflate *requires* an extra "dummy" byte
+ // * after the compressed stream in order to complete decompression and
+ // * return Z_STREAM_END.
+ CheckForError(err);
+ }
+ m_info.m_uComprLeft = CurrentFile()->m_uComprSize;
+ if (CurrentFile()->IsEncrypted())
+ m_info.m_uComprLeft -= ENCR_HEADER_LEN;
+ m_info.m_uUncomprLeft = CurrentFile()->m_uUncomprSize;
+ m_info.m_uCrc32 = 0;
+ m_info.m_stream.total_out = 0;
+ m_info.m_stream.avail_in = 0;
+
+ m_iFileOpened = extract;
+ return true;
+}
+
+
+int CZipArchive::GetLocalExtraField(char *pBuf, int iSize)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return -1;
+ }
+
+ if (m_iFileOpened != extract)
+ {
+ TRACE(_T("A file must be opened to get the local extra field.\n"));
+ return -1;
+ }
+
+ int size = m_centralDir.m_pLocalExtraField.GetSize();
+ if (!pBuf|| !size)
+ return size;
+
+ if (iSize < size)
+ size = iSize;
+
+ memcpy(pBuf, m_centralDir.m_pLocalExtraField, size);
+ return size;
+}
+
+void* CZipArchive::myalloc(void* opaque, UINT items, UINT size)
+{
+ void* p = new char[size * items];
+ if (opaque)
+ {
+ CPtrList* list = (CPtrList*) opaque;
+ list->AddTail(p);
+ }
+ return p;
+}
+
+void CZipArchive::myfree(void* opaque, void* address)
+{
+ if (opaque)
+ {
+ CPtrList* list = (CPtrList*) opaque;
+ POSITION pos = list->Find(address);
+ if (pos)
+ list->RemoveAt(pos);
+ }
+ delete[] address;
+}
+
+void CZipArchive::CheckForError(int iErr)
+{
+ if ((iErr == Z_OK) ||(iErr == Z_NEED_DICT))
+ return;
+
+ ThrowError(iErr);
+}
+
+CZipFileHeader* CZipArchive::CurrentFile()
+{
+ ASSERT(m_centralDir.m_pOpenedFile);
+ return m_centralDir.m_pOpenedFile;
+}
+
+DWORD CZipArchive::ReadFile(void *pBuf, DWORD iSize)
+{
+ if (m_iFileOpened != extract)
+ {
+ TRACE(_T("Current file must be opened.\n"));
+ return 0;
+ }
+
+ if (!pBuf || !iSize)
+ return 0;
+
+ m_info.m_stream.next_out = (Bytef*)pBuf;
+ m_info.m_stream.avail_out = iSize > m_info.m_uUncomprLeft
+ ? m_info.m_uUncomprLeft : iSize;
+
+
+ DWORD iRead = 0;
+
+ // may happen when the file is 0 sized
+ bool bForce = m_info.m_stream.avail_out == 0 && m_info.m_uComprLeft > 0;
+ while (m_info.m_stream.avail_out > 0 || (bForce && m_info.m_uComprLeft > 0))
+ {
+ if ((m_info.m_stream.avail_in == 0) &&
+ (m_info.m_uComprLeft > 0))
+ {
+ DWORD uToRead = m_info.m_pBuffer.GetSize();
+ if (m_info.m_uComprLeft < uToRead)
+ uToRead = m_info.m_uComprLeft;
+
+ if (uToRead == 0)
+ return 0;
+
+ m_storage.Read(m_info.m_pBuffer, uToRead, false);
+ CryptDecodeBuffer(uToRead);
+ m_info.m_uComprLeft -= uToRead;
+
+ m_info.m_stream.next_in = (unsigned char*)(char*)m_info.m_pBuffer;
+ m_info.m_stream.avail_in = uToRead;
+ }
+
+ if (CurrentFile()->m_uMethod == 0)
+ {
+ DWORD uToCopy = m_info.m_stream.avail_out < m_info.m_stream.avail_in
+ ? m_info.m_stream.avail_out : m_info.m_stream.avail_in;
+
+ memcpy(m_info.m_stream.next_out, m_info.m_stream.next_in, uToCopy);
+
+ m_info.m_uCrc32 = crc32(m_info.m_uCrc32, m_info.m_stream.next_out, uToCopy);
+
+ m_info.m_uUncomprLeft -= uToCopy;
+ m_info.m_stream.avail_in -= uToCopy;
+ m_info.m_stream.avail_out -= uToCopy;
+ m_info.m_stream.next_out += uToCopy;
+ m_info.m_stream.next_in += uToCopy;
+ m_info.m_stream.total_out += uToCopy;
+ iRead += uToCopy;
+ }
+ else
+ {
+ DWORD uTotal = m_info.m_stream.total_out;
+ Bytef* pOldBuf = m_info.m_stream.next_out;
+ int err = inflate(&m_info.m_stream, Z_SYNC_FLUSH);
+ DWORD uToCopy = m_info.m_stream.total_out - uTotal;
+
+ m_info.m_uCrc32 = crc32(m_info.m_uCrc32, pOldBuf, uToCopy);
+
+ m_info.m_uUncomprLeft -= uToCopy;
+ iRead += uToCopy;
+
+ if (err == Z_STREAM_END)
+ return iRead;
+
+ CheckForError(err);
+ }
+ }
+
+ return iRead;
+}
+
+void CZipArchive::Close(bool bAfterException)
+{
+ // if after an exception - the archive may be closed, but the file may be opened
+ if (IsClosed() && (!bAfterException || IsClosed(false)))
+ {
+ TRACE(_T("ZipArchive is already closed.\n"));
+ return;
+ }
+
+ if (!bAfterException)
+ {
+ if (m_iFileOpened == extract)
+ CloseFile(NULL);
+
+ if (m_iFileOpened == compress)
+ CloseNewFile();
+
+ // write central directory
+ m_centralDir.Write();
+ }
+ else
+ {
+ m_info.m_pBuffer.Release();
+ m_iFileOpened = nothing;
+ EmptyPtrList();
+ }
+
+ m_centralDir.Clear();
+ m_storage.Close(bAfterException);
+}
+
+void CZipArchive::SetSpanCallback(ZIPCALLBACKFUN pFunc, void* pData)
+{
+ m_storage.m_pZIPCALLBACKFUN = pFunc;
+ m_storage.m_pCallbackData = pData;
+}
+
+void CZipArchive::SetAdvanced(int iWriteBuffer, int iExtractBuffer, int iSearchBuffer)
+{
+ if (!IsClosed())
+ {
+ TRACE(_T("Set this options before opening the archive.\n"));
+ return;
+ }
+
+ m_storage.m_iWriteBufferSize = iWriteBuffer < 1024 ? 1024 : iWriteBuffer;
+ m_centralDir.m_iBufferSize = iSearchBuffer < 1024 ? 1024 : iSearchBuffer;
+ m_info.m_iBufferSize = iExtractBuffer < 1024 ? 1024 : iExtractBuffer;
+}
+
+int CZipArchive::CloseFile(CFile &file)
+{
+ CString temp = file.GetFilePath();
+ file.Close();
+ return CloseFile(temp);
+}
+
+int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException)
+{
+ if (m_iFileOpened != extract)
+ {
+ TRACE(_T("No opened file.\n"));
+ return false;
+ }
+
+ int iRet = 1;
+ if (!bAfterException)
+ {
+ if (m_info.m_uUncomprLeft == 0)
+ {
+ if (m_info.m_uCrc32 != CurrentFile()->m_uCrc32)
+ ThrowError(ZIP_BADCRC);
+ }
+ else
+ iRet = -1;
+
+
+ if (CurrentFile()->m_uMethod == Z_DEFLATED)
+ inflateEnd(&m_info.m_stream);
+
+
+ if (lpszFilePath)
+ {
+ try
+ {
+ CFileStatus fs;
+ fs.m_ctime = fs.m_atime = CTime::GetCurrentTime();
+ fs.m_attribute = 0;
+ fs.m_mtime = CurrentFile()->GetTime();
+ CFile::SetStatus(lpszFilePath, fs);
+ if (SetFileAttributes(lpszFilePath, CurrentFile()->m_uExternalAttr) == 0)
+ iRet = -2;
+ }
+ catch (CException* e)
+ {
+ e->Delete();
+ return false;
+ }
+ }
+ }
+ m_centralDir.CloseFile();
+ m_iFileOpened = nothing;
+ m_info.m_pBuffer.Release();
+ EmptyPtrList();
+ return iRet;
+}
+
+bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpszFilePath)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return false;
+ }
+
+ if (m_iFileOpened)
+ {
+ TRACE(_T("A file already opened.\n"));
+ return false;
+ }
+
+ if (m_storage.IsSpanMode() == -1)
+ {
+ TRACE(_T("You cannot add the files to the existing disk spannig archive.\n"));
+ return false;
+ }
+
+ if (GetNoEntries() ==(WORD)USHRT_MAX)
+ {
+ TRACE(_T("Maximum file count inside archive reached.\n"));
+ return false;
+ }
+
+
+ if (lpszFilePath)
+ {
+ bool bRet = true;
+ CFileStatus fs;
+ if (!CFile::GetStatus(lpszFilePath, fs))
+ bRet = false;
+ else
+ {
+ header.SetTime(fs.m_mtime);
+ header.m_uExternalAttr = ::GetFileAttributes(lpszFilePath); // mfc bug: m_attribute is 1-byte
+ if (header.m_uExternalAttr == -1)
+ bRet = false;
+ }
+
+ if (!bRet)
+ // do not continue - if the file was a directory then not recognizing it will cause
+ // serious errors
+ return false;
+ }
+
+ m_info.Init();
+ m_centralDir.AddNewFile(header);
+
+ CString szFileName = CurrentFile()->GetFileName();
+
+ if (szFileName.IsEmpty())
+ {
+ szFileName.Format(_T("file%i"), GetNoEntries());;
+ CurrentFile()->SetFileName(szFileName);
+ }
+ // this ensures the conversion will take place anyway (must take because we are going
+ // to write the local header in a moment
+ m_centralDir.ConvertFileName(false, m_centralDir.m_bConvertAfterOpen);
+
+
+ bool bIsDirectory = IsDirectory(CurrentFile()->m_uExternalAttr);
+ bool bEncrypted = m_pszPassword.GetSize() != 0;
+#ifdef _DEBUG
+ if (bIsDirectory && bEncrypted)
+ TRACE(_T("Warning! Encrypting a directory. Possible but pointless.\n\
+ Clear the password before adding a directory.\n"));
+#endif
+
+
+ if (!CurrentFile()->PrepareData(iLevel, m_storage.IsSpanMode() == 1, bEncrypted))
+ ThrowError(ZIP_TOOLONGFILENAME);
+
+ CurrentFile()->WriteLocal(m_storage);
+ // we have written the local header, but if we keep filenames not converted
+ // in memory , we have to restore the non-converted value
+ if (m_centralDir.m_bConvertAfterOpen)
+ CurrentFile()->SetFileName(szFileName);
+ if (bEncrypted)
+ {
+ CZipAutoBuffer buf(ENCR_HEADER_LEN);
+ // use pseudo-crc since we don't know it yet
+ CryptCryptHeader((long)header.m_uModTime << 16, buf);
+ m_storage.Write(buf, ENCR_HEADER_LEN, false);
+ }
+
+
+ m_info.m_uComprLeft = 0;
+ m_info.m_stream.avail_in = (uInt)0;
+ m_info.m_stream.avail_out = (uInt)m_info.m_pBuffer.GetSize();
+ m_info.m_stream.next_out = (unsigned char*)(char*)m_info.m_pBuffer;
+ m_info.m_stream.total_in = 0;
+ m_info.m_stream.total_out = 0;
+
+ if (bIsDirectory && (CurrentFile()->m_uMethod != 0))
+ CurrentFile()->m_uMethod = 0;
+
+ if (CurrentFile()->m_uMethod == Z_DEFLATED)
+ {
+ m_info.m_stream.opaque = m_bDetectZlibMemoryLeaks ? &m_list : 0;
+
+ int err = deflateInit2(&m_info.m_stream, iLevel,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ CheckForError(err);
+ }
+ m_iFileOpened = compress;
+ return true;
+}
+
+CString CZipArchive::GetFilePath(LPCTSTR lpszFilePath)
+{
+ TCHAR szDir[_MAX_DIR];
+ TCHAR szDrive[_MAX_DRIVE];
+ _tsplitpath(lpszFilePath, szDrive, szDir, NULL, NULL);
+ return CString(szDrive) + CString(szDir);
+}
+
+CString CZipArchive::GetFileExt(LPCTSTR lpszFilePath)
+{
+ TCHAR szExt[_MAX_EXT];
+ _tsplitpath(lpszFilePath, NULL, NULL, NULL, szExt);
+ return CString(szExt);
+}
+
+CString CZipArchive::GetFileTitle(LPCTSTR lpszFilePath)
+{
+ TCHAR szFname[_MAX_FNAME];
+ _tsplitpath(lpszFilePath, NULL, NULL, szFname, NULL);
+ return CString(szFname);
+}
+
+CString CZipArchive::GetFileDirAndName(LPCTSTR lpszFilePath)
+{
+ TCHAR szDir[_MAX_DIR];
+ TCHAR szFname[_MAX_FNAME];
+ TCHAR szExt[_MAX_EXT];
+ _tsplitpath(lpszFilePath, NULL , szDir, szFname, szExt);
+ CString Dir = szDir;
+ Dir.TrimLeft(_T("\\"));
+ return Dir + szFname + szExt;
+}
+
+
+CString CZipArchive::GetFileName(LPCTSTR lpszFilePath)
+{
+ TCHAR szExt[_MAX_EXT];
+ TCHAR szName[_MAX_FNAME];
+ _tsplitpath(lpszFilePath, NULL, NULL, szName, szExt);
+ return CString(szName) + CString(szExt);
+}
+
+bool CZipArchive::ForceDirectory(LPCTSTR lpDirectory)
+{
+ ASSERT(lpDirectory);
+ CString szDirectory = lpDirectory;
+ szDirectory.TrimRight(_T("\\"));
+ if ((GetFilePath(szDirectory) == szDirectory) ||
+ (FileExists(szDirectory) == -1))
+ return true;
+ if (!ForceDirectory(GetFilePath(szDirectory)))
+ return false;
+ if (!CreateDirectory(szDirectory, NULL))
+ return false;
+ return true;
+}
+
+int CZipArchive::FileExists(LPCTSTR lpszName)
+{
+ CFileFind fileFind;
+ if (!fileFind.FindFile(lpszName))
+ {
+ if (DirectoryExists(lpszName)) // if root ex. "C:\"
+ return -1;
+ return 0;
+ }
+ fileFind.FindNextFile();
+ return fileFind.IsDirectory() ? -1 : 1;
+}
+
+bool CZipArchive::DirectoryExists(LPCTSTR lpszDir)
+{
+ TCHAR curPath[_MAX_PATH]; /* Get the current working directory: */
+ if (!_tgetcwd(curPath, _MAX_PATH))
+ return false;
+ if (_tchdir(lpszDir)) // retruns 0 if error
+ return false;
+ _tchdir(curPath);
+ return true;
+}
+
+bool CZipArchive::IsFileDirectory(WORD uIndex)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return false;
+ }
+
+ if (!m_centralDir.IsValidIndex(uIndex))
+ return false;
+
+ return IsDirectory(m_centralDir.m_headers[uIndex]->m_uExternalAttr);
+}
+bool CZipArchive::ExtractFile(WORD uIndex,
+ LPCTSTR lpszPath,
+ bool bFullPath,
+ LPCTSTR lpszNewName,
+ ZIPCALLBACKFUN pCallback,
+ void* pUserData,
+ DWORD nBufSize)
+{
+ if (!nBufSize && !lpszPath)
+ return false;
+
+ CZipFileHeader header;
+ GetFileInfo(header, uIndex); // to ensure that slash and oem conversions take place
+ CString szFile = lpszPath, szFileName = lpszNewName ? lpszNewName : header.GetFileName();
+ szFile.TrimRight(_T("\\"));
+ szFile += _T("\\") + (bFullPath ? GetFileDirAndName(szFileName)
+ : GetFileName(szFileName)); // just in case in the archive there are file names with drives
+
+ if (IsFileDirectory(uIndex))
+ {
+ ForceDirectory(szFile);
+ SetFileAttributes(szFile, header.m_uExternalAttr);
+ return true;
+ }
+ else
+ {
+ if (!OpenFile(uIndex))
+ return false;
+
+ ForceDirectory(GetFilePath(szFile));
+ CFile f(szFile, CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite);
+ DWORD iRead, iFileLength = pCallback ? header.GetSize() : 0, iSoFar = 0;
+ CZipAutoBuffer buf(nBufSize);
+ do
+ {
+ iRead = ReadFile(buf, buf.GetSize());
+ if (iRead)
+ {
+ f.Write(buf, iRead);
+ iSoFar += iRead;
+ if (pCallback)
+ if (!pCallback(iFileLength, iSoFar, pUserData))
+ break;
+ }
+ }
+ while (iRead == buf.GetSize());
+ return CloseFile(f) == 1;
+ }
+}
+
+void CZipArchive::SetExtraField(char *pBuf, WORD iSize)
+{
+ if (m_iFileOpened != compress)
+ {
+ TRACE(_T("A new file must be opened.\n"));
+ return;
+ }
+ if (!pBuf || !iSize)
+ return;
+
+ CurrentFile()->m_pExtraField.Allocate(iSize);
+ memcpy(CurrentFile()->m_pExtraField, pBuf, iSize);
+}
+
+bool CZipArchive::WriteNewFile(void *pBuf, DWORD iSize)
+{
+ if (m_iFileOpened != compress)
+ {
+ TRACE(_T("A new file must be opened.\n"));
+ return false;
+ }
+
+
+ m_info.m_stream.next_in = (unsigned char*)pBuf;
+ m_info.m_stream.avail_in = iSize;
+ CurrentFile()->m_uCrc32 = crc32(CurrentFile()->m_uCrc32, (unsigned char*)pBuf, iSize);
+
+
+ while (m_info.m_stream.avail_in > 0)
+ {
+ if (m_info.m_stream.avail_out == 0)
+ {
+ CryptEncodeBuffer();
+ m_storage.Write(m_info.m_pBuffer, m_info.m_uComprLeft, false);
+ m_info.m_uComprLeft = 0;
+ m_info.m_stream.avail_out = m_info.m_pBuffer.GetSize();
+ m_info.m_stream.next_out = (unsigned char*)(char*)m_info.m_pBuffer;
+ }
+
+ if (CurrentFile()->m_uMethod == Z_DEFLATED)
+ {
+ DWORD uTotal = m_info.m_stream.total_out;
+ int err = deflate(&m_info.m_stream, Z_NO_FLUSH);
+ CheckForError(err);
+ m_info.m_uComprLeft += m_info.m_stream.total_out - uTotal;
+ }
+ else
+ {
+ DWORD uToCopy = (m_info.m_stream.avail_in < m_info.m_stream.avail_out)
+ ? m_info.m_stream.avail_in : m_info.m_stream.avail_out;
+
+ memcpy(m_info.m_stream.next_out, m_info.m_stream.next_in, uToCopy);
+
+ m_info.m_stream.avail_in -= uToCopy;
+ m_info.m_stream.avail_out -= uToCopy;
+ m_info.m_stream.next_in += uToCopy;
+ m_info.m_stream.next_out += uToCopy;
+ m_info.m_stream.total_in += uToCopy;
+ m_info.m_stream.total_out += uToCopy;
+ m_info.m_uComprLeft += uToCopy;
+ }
+ }
+
+ return true;
+}
+
+bool CZipArchive::CloseNewFile()
+{
+ if (m_iFileOpened != compress)
+ {
+ TRACE(_T("A new file must be opened.\n"));
+ return false;
+ }
+
+ m_info.m_stream.avail_in = 0;
+
+ int err = Z_OK;
+ if (CurrentFile()->m_uMethod == Z_DEFLATED)
+ while (err == Z_OK)
+ {
+ if (m_info.m_stream.avail_out == 0)
+ {
+ CryptEncodeBuffer();
+ m_storage.Write(m_info.m_pBuffer, m_info.m_uComprLeft, false);
+ m_info.m_uComprLeft = 0;
+ m_info.m_stream.avail_out = m_info.m_pBuffer.GetSize();
+ m_info.m_stream.next_out = (unsigned char*)(char*)m_info.m_pBuffer;
+ }
+ DWORD uTotal = m_info.m_stream.total_out;
+ err = deflate(&m_info.m_stream, Z_FINISH);
+ m_info.m_uComprLeft += m_info.m_stream.total_out - uTotal;
+ }
+
+ if (err == Z_STREAM_END)
+ err = Z_OK;
+ CheckForError(err);
+
+ if (m_info.m_uComprLeft > 0)
+ {
+ CryptEncodeBuffer();
+ m_storage.Write(m_info.m_pBuffer, m_info.m_uComprLeft, false);
+ }
+
+ if (CurrentFile()->m_uMethod == Z_DEFLATED)
+ {
+ err = deflateEnd(&m_info.m_stream);
+ CheckForError(err);
+ }
+
+
+ // it may be increased by the encrypted header size
+ CurrentFile()->m_uComprSize += m_info.m_stream.total_out;
+ CurrentFile()->m_uUncomprSize = m_info.m_stream.total_in;
+
+ m_centralDir.CloseNewFile();
+ m_iFileOpened = nothing;
+ m_info.m_pBuffer.Release();
+ return true;
+}
+
+void CZipArchive::DeleteFiles(CStringArray &aNames, bool bCaseSensitive)
+{
+ CWordArray indexes;
+
+ for (WORD i = 0; i < GetNoEntries(); i++)
+ {
+ CZipFileHeader fh;
+ GetFileInfo(fh, i);
+ CString szFileName = fh.GetFileName();
+ for (int j = 0; j < aNames.GetSize(); j++)
+ {
+ bool bEqual = (bCaseSensitive ? aNames[j].Collate(szFileName)
+ : aNames[j].CollateNoCase(szFileName)) == 0;
+ if (bEqual)
+ {
+ indexes.Add(i);
+ break;
+ }
+ }
+ }
+
+ DeleteFiles(indexes);
+}
+
+
+void CZipArchive::DeleteFiles(CWordArray &aIndexes)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return;
+ }
+
+ if (m_storage.IsSpanMode())
+ {
+ TRACE(_T("You cannot delete files from the disk spannig archive.\n"));
+ return;
+ }
+
+ if (m_iFileOpened)
+ {
+ TRACE(_T("You cannot delete files if there is a file opened.\n"));
+ return;
+ }
+
+ // sorting the index table using qsort
+ int uSize = aIndexes.GetSize();
+ if (!uSize)
+ return;
+ qsort((void*)&aIndexes[0], uSize, sizeof(WORD), CompareWords);
+
+ m_centralDir.RemoveFromDisk();
+
+ m_info.Init();
+ // remove in a reverse order
+ for (int i = uSize - 1; i >= 0; i--)
+ DeleteInternal(aIndexes[i]);
+ m_info.m_pBuffer.Release();
+}
+
+DWORD CZipArchive::RemovePackedFile(DWORD uStartOffset, DWORD uEndOffset)
+{
+ uStartOffset += m_centralDir.m_uBytesBeforeZip;
+ uEndOffset += m_centralDir.m_uBytesBeforeZip;
+ DWORD BytesToCopy = m_storage.m_pFile->GetLength() - uEndOffset;
+ DWORD uTotalToWrite = BytesToCopy;
+
+ char* buf = (char*)m_info.m_pBuffer;
+ if (BytesToCopy > m_info.m_pBuffer.GetSize())
+ BytesToCopy = m_info.m_pBuffer.GetSize();
+
+
+
+ DWORD TotalWritten = 0;
+ DWORD size_read;
+
+ do
+ {
+ m_storage.m_pFile->Seek(uEndOffset + TotalWritten, CFile::begin);
+ size_read = m_storage.m_pFile->Read(buf, BytesToCopy);
+ if (size_read > 0)
+ {
+ m_storage.m_pFile->Seek(uStartOffset + TotalWritten, CFile::begin);
+ m_storage.m_pFile->Write(buf, size_read);
+ }
+ TotalWritten += size_read;
+ }
+ while (size_read == BytesToCopy);
+ if (uTotalToWrite != TotalWritten)
+ ThrowError(CZipException::generic);
+ DWORD uRemoved = (uEndOffset - uStartOffset);
+ m_storage.m_pFile->SetLength(m_storage.m_pFile->GetLength() - uRemoved);
+ return uRemoved;
+}
+
+
+void CZipArchive::DeleteInternal(WORD uIndex)
+{
+ CZipFileHeader* pfh = m_centralDir.m_headers[uIndex];
+ DWORD uOtherOffsetChanged = 0;
+
+ if (uIndex == GetNoEntries() - 1) // last entry or the only one entry
+ m_storage.m_pFile->SetLength(pfh->m_uOffset + m_centralDir.m_uBytesBeforeZip);
+ else
+ uOtherOffsetChanged = RemovePackedFile(pfh->m_uOffset, m_centralDir.m_headers[uIndex + 1]->m_uOffset);
+
+
+ m_centralDir.RemoveFile(uIndex);
+
+ // teraz uaktualnij offsety w pozosta³ych pozycjach central dir
+ // (update offsets in file headers in the central dir)
+ if (uOtherOffsetChanged)
+ for (int i = uIndex; i < GetNoEntries(); i++)
+ m_centralDir.m_headers[i]->m_uOffset -= uOtherOffsetChanged;
+}
+
+bool CZipArchive::IsDriveRemovable(LPCTSTR lpszFilePath)
+{
+ return GetDriveType(GetDrive(lpszFilePath)) == DRIVE_REMOVABLE;
+}
+
+CString CZipArchive::GetDrive(LPCTSTR lpszFilePath)
+{
+ TCHAR szDrive[_MAX_DRIVE];
+ _tsplitpath(lpszFilePath, szDrive, NULL, NULL, NULL);
+ return szDrive;
+}
+
+bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
+ int iLevel,
+ bool bFullPath,
+ ZIPCALLBACKFUN pCallback,
+ void* pUserData,
+ unsigned long nBufSize)
+{
+ if (!nBufSize)
+ return false;
+
+ CZipFileHeader header;
+ header.SetFileName(bFullPath ? GetFileDirAndName(lpszFilePath) : GetFileName(lpszFilePath));
+ if (header.GetFileNameSize() == 0)
+ return false;
+ if (!OpenNewFile(header, iLevel, lpszFilePath))
+ return false;
+
+ if (!IsDirectory(header.m_uExternalAttr))
+ {
+ CFile f;
+ CFileException* e = new CFileException;
+ BOOL bRet = f.Open(lpszFilePath, CFile::modeRead | CFile::shareDenyWrite, e);
+ e->Delete();
+ if (!bRet)
+ return false;
+
+ DWORD iRead, iFileLength = pCallback ? f.GetLength() : 0, iSoFar = 0;
+ CZipAutoBuffer buf(nBufSize);
+ do
+ {
+ iRead = f.Read(buf, nBufSize);
+ if (iRead)
+ {
+ WriteNewFile(buf, iRead);
+ iSoFar += iRead;
+ if (pCallback)
+ if (!pCallback(iFileLength, iSoFar, pUserData))
+ break;
+ }
+ }
+ while (iRead == buf.GetSize());
+ }
+ CloseNewFile();
+ return true;
+}
+
+int CZipArchive::GetSpanMode()
+{
+ return m_storage.m_iSpanMode * m_storage.IsSpanMode();
+}
+
+CString CZipArchive::GetArchivePath()
+{
+ return m_storage.m_pFile->GetFilePath();
+}
+
+CString CZipArchive::GetGlobalComment()
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return _T("");
+ }
+ CString temp;
+ if (SingleToWide(m_centralDir.m_pszComment, temp) != -1)
+ return temp;
+ else
+ return _T("");
+}
+
+bool CZipArchive::SetGlobalComment(const CString &szComment)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return false;
+ }
+ if (m_storage.IsSpanMode() == -1)
+ {
+ TRACE(_T("You cannot modify the global comment of the existing disk spanning archive.\n"));
+ return false;
+ }
+
+ WideToSingle(szComment, m_centralDir.m_pszComment);
+ m_centralDir.RemoveFromDisk();
+ return true;
+}
+
+bool CZipArchive::IsDirectory(DWORD uAttr)
+{
+ return (uAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+int CZipArchive::GetCurrentDisk()
+{
+ return m_storage.GetCurrentDisk() + 1;
+}
+
+bool CZipArchive::SetFileComment(WORD uIndex, CString szComment)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("ZipArchive is closed.\n"));
+ return false;
+ }
+ if (m_storage.IsSpanMode() == -1)
+ {
+ TRACE(_T("You cannot modify the file comment in the existing disk spanning archive.\n"));
+ return false;
+ }
+
+ if (!m_centralDir.IsValidIndex(uIndex))
+ return false;
+ m_centralDir.m_headers[uIndex]->SetComment(szComment);
+ m_centralDir.RemoveFromDisk();
+ return true;
+}
+
+int CZipArchive::CompareWords(const void *pArg1, const void *pArg2)
+{
+ WORD w1 = *(WORD*)pArg1;
+ WORD w2 = *(WORD*)pArg2;
+ return w1 == w2 ? 0 :(w1 < w2 ? - 1 : 1);
+}
+
+void CZipArchive::CryptInitKeys()
+{
+ ASSERT(m_pszPassword.GetSize());
+ m_keys[0] = 305419896L;
+ m_keys[1] = 591751049L;
+ m_keys[2] = 878082192L;
+ for (DWORD i = 0; i < m_pszPassword.GetSize(); i++)
+ CryptUpdateKeys(m_pszPassword[i]);
+}
+
+void CZipArchive::CryptUpdateKeys(char c)
+{
+
+ m_keys[0] = CryptCRC32(m_keys[0], c);
+ m_keys[1] += m_keys[0] & 0xff;
+ m_keys[1] = m_keys[1] * 134775813L + 1;
+ c = char(m_keys[1] >> 24);
+ m_keys[2] = CryptCRC32(m_keys[2], c);
+}
+
+bool CZipArchive::CryptCheck()
+{
+ CZipAutoBuffer buf(ENCR_HEADER_LEN);
+ m_storage.Read(buf, ENCR_HEADER_LEN, false);
+ BYTE b = 0;
+ for (int i = 0; i < ENCR_HEADER_LEN; i++)
+ {
+ b = buf[i]; // only temporary
+ CryptDecode((char&)b);
+ }
+ // check the last byte
+ if (CurrentFile()->IsDataDescr()) // Data descriptor present
+ return BYTE(CurrentFile()->m_uModTime >> 8) == b;
+ else
+ return BYTE(CurrentFile()->m_uCrc32 >> 24) == b;
+}
+
+char CZipArchive::CryptDecryptByte()
+{
+ int temp = (m_keys[2] & 0xffff) | 2;
+ return (char)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+void CZipArchive::CryptDecode(char &c)
+{
+ c ^= CryptDecryptByte();
+ CryptUpdateKeys(c);
+}
+
+bool CZipArchive::SetPassword(LPCTSTR lpszPassword)
+{
+ if (m_iFileOpened != nothing)
+ {
+ TRACE(_T("You cannot change the password when the file is opened\n"));
+ return false; // it's important not to change the password when the file inside archive is opened
+ }
+ if (IsClosed())
+ {
+ TRACE(_T("Setting the password for a closed archive has no effect.\n"));
+ }
+ if (lpszPassword)
+ {
+ int iLen = WideToSingle(lpszPassword, m_pszPassword);
+ if (iLen == -1)
+ return false;
+ for (size_t i = 0; (int)i < iLen; i++)
+ if (m_pszPassword[i] > 127)
+ {
+ m_pszPassword.Release();
+ TRACE(_T("The password contains forbidden characters. Password cleared.\n"));
+ return false;
+ }
+ }
+ else
+ m_pszPassword.Release();
+ return true;
+}
+
+DWORD CZipArchive::CryptCRC32(DWORD l, char c)
+{
+ const DWORD *CRC_TABLE = get_crc_table();
+ return CRC_TABLE[(l ^ c) & 0xff] ^ (l >> 8);
+}
+
+void CZipArchive::CryptCryptHeader(long iCrc, CZipAutoBuffer &buf)
+{
+ CryptInitKeys();
+ srand(UINT(GetTickCount()*time(NULL)));
+ // genereate pseudo-random sequence
+ char c;
+ for (int i = 0; i < ENCR_HEADER_LEN - 2; i++)
+ {
+ int t1 = rand();
+ c = (char)(t1 >> 6);
+ if (!c)
+ c = (char)t1;
+ CryptEncode(c);
+ buf[i] = c;
+
+ }
+ c = (char)((iCrc >> 16) & 0xff);
+ CryptEncode(c);
+ buf[ENCR_HEADER_LEN - 2] = c;
+ c = (char)((iCrc >> 24) & 0xff);
+ CryptEncode(c);
+ buf[ENCR_HEADER_LEN - 1] = c;
+}
+
+void CZipArchive::CryptEncode(char &c)
+{
+ char t = CryptDecryptByte();
+ CryptUpdateKeys(c);
+ c ^= t;
+}
+
+void CZipArchive::CryptEncodeBuffer()
+{
+ if (CurrentFile()->IsEncrypted())
+ for (DWORD i = 0; i < m_info.m_uComprLeft; i++)
+ CryptEncode(m_info.m_pBuffer[i]);
+}
+
+void CZipArchive::CloseFileAfterTestFailed()
+{
+ if (m_iFileOpened != extract)
+ {
+ TRACE(_T("No file opened.\n"));
+ return;
+ }
+ m_info.m_pBuffer.Release();
+ m_centralDir.Clear(false);
+ m_iFileOpened = nothing;
+}
+
+bool CZipArchive::TestFile(WORD uIndex, ZIPCALLBACKFUN pCallback, void* pUserData, DWORD uBufSize)
+{
+ if (!uBufSize)
+ return false;
+ CZipFileHeader* pHeader = m_centralDir.m_headers[uIndex];
+ if (IsFileDirectory(uIndex))
+ {
+
+ // we do not test whether the password for the encrypted directory
+ // is correct, since it seems to be senseless (anyway password
+ // encrypted directories should be avoided - it adds 12 bytes)
+ DWORD iSize = pHeader->m_uComprSize;
+ if ((iSize != 0 || iSize != pHeader->m_uUncomprSize)
+ // different treating compressed directories
+ && !(pHeader->IsEncrypted() && iSize == 12 && !pHeader->m_uUncomprSize))
+ ThrowError(CZipException::dirWithSize);
+ return true;
+ }
+ else
+ {
+ try
+ {
+ if (!OpenFile(uIndex))
+ return false;
+ CZipAutoBuffer buf(uBufSize);
+ DWORD iRead, iSoFar = 0;
+ do
+ {
+ iRead = ReadFile(buf, buf.GetSize());
+ iSoFar += iRead;
+ if (pCallback)
+ if (!pCallback(pHeader->m_uUncomprSize, iSoFar, pUserData))
+ break;
+ }
+ while (iRead == buf.GetSize());
+ CloseFile();
+ }
+ catch(CException*)
+ {
+ CloseFileAfterTestFailed();
+ throw;
+ }
+ }
+ return true;
+
+}
+
+int CZipArchive::WideToSingle(LPCTSTR lpWide, CZipAutoBuffer &szSingle)
+{
+ size_t wideLen = _tcslen(lpWide);
+ if (wideLen == 0)
+ {
+ szSingle.Release();
+ return 0;
+ }
+
+#ifdef _UNICODE
+ // iLen does not include terminating character
+ int iLen = WideCharToMultiByte(CP_ACP,0, lpWide, wideLen, szSingle,
+ 0, NULL, NULL);
+ if (iLen > 0)
+ {
+ szSingle.Allocate(iLen, true);
+ iLen = WideCharToMultiByte(CP_ACP,0, lpWide , wideLen, szSingle,
+ iLen, NULL, NULL);
+ ASSERT(iLen != 0);
+ }
+ else // here it means error
+ {
+ szSingle.Release();
+ iLen --;
+ }
+ return iLen;
+
+#else // if not UNICODE just copy
+ // iLen does not include the NULL character
+ szSingle.Allocate(wideLen);
+ memcpy(szSingle, lpWide, wideLen);
+ return wideLen;
+#endif
+
+}
+
+int CZipArchive::SingleToWide(CZipAutoBuffer &szSingle, CString& szWide)
+{
+ int singleLen = szSingle.GetSize();
+#ifdef _UNICODE
+ // iLen doesn't include terminating character
+ int iLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szSingle, singleLen, NULL, 0);
+ if (iLen > 0)
+ {
+ iLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szSingle, singleLen,
+ szWide.GetBuffer(iLen) , iLen);
+ szWide.ReleaseBuffer(iLen);
+ ASSERT(iLen != 0);
+ }
+ else
+ {
+ szWide.Empty();
+ iLen --;
+ }
+ return iLen;
+
+#else // if not UNICODE just copy
+ // iLen does not include the NULL character
+ memcpy(szWide.GetBuffer(singleLen), szSingle, singleLen);
+ szWide.ReleaseBuffer(singleLen);
+ return singleLen;
+#endif
+}
+
+const DWORD* CZipArchive::GetCRCTable()
+{
+ return get_crc_table();
+}
+
+void CZipArchive::CryptDecodeBuffer(DWORD uCount)
+{
+ if (CurrentFile()->IsEncrypted())
+ for (DWORD i = 0; i < uCount; i++)
+ CryptDecode(m_info.m_pBuffer[i]);
+}
+
+void CZipArchive::EmptyPtrList()
+{
+ if (m_list.GetCount())
+ {
+ // if some memory hasn't been freed due to an error in zlib, so free it now
+ POSITION pos = m_list.GetHeadPosition();
+ while (pos)
+ delete[] m_list.GetNext(pos);
+ }
+
+}
+
+
+
+void CZipArchive::EnableFindFast(bool bEnable)
+{
+ if (IsClosed())
+ {
+ TRACE(_T("Set it after opening the archive"));
+ return;
+ }
+
+ if (m_centralDir.m_bFindFastEnabled == bEnable)
+ return;
+ m_centralDir.m_bFindFastEnabled = bEnable;
+ if (bEnable)
+ m_centralDir.BuildFindFastArray();
+ else
+ m_centralDir.m_findarray.RemoveAll();
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipArchive.dsp b/stepmania/src/smpackage/ZipArchive/ZipArchive.dsp
new file mode 100644
index 0000000000..a2cfd40326
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipArchive.dsp
@@ -0,0 +1,283 @@
+# Microsoft Developer Studio Project File - Name="ZipArchive" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=ZipArchive - Win32 Unicode Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "ZipArchive.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "ZipArchive.mak" CFG="ZipArchive - Win32 Unicode Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "ZipArchive - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "ZipArchive - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "ZipArchive - Win32 Static Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "ZipArchive - Win32 Unicode Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "ZipArchive - Win32 Unicode Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "ZipArchive - Win32 Unicode Static Release" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "ZipArchive - Win32 Release"
+
+# PROP BASE Use_MFC 2
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 2
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x415 /d "NDEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x415 /d "NDEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "ZipArchive - Win32 Debug"
+
+# PROP BASE Use_MFC 2
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 2
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /MDd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /D "_AFXDLL" /Fr /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x415 /d "_DEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x415 /d "_DEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "ZipArchive - Win32 Static Release"
+
+# PROP BASE Use_MFC 2
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Zip___Win32_Static_Release"
+# PROP BASE Intermediate_Dir "Zip___Win32_Static_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 1
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Static_Release"
+# PROP Intermediate_Dir "Static_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x415 /d "NDEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x415 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "ZipArchive - Win32 Unicode Debug"
+
+# PROP BASE Use_MFC 2
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Zip___Win32_Unicode_Debug"
+# PROP BASE Intermediate_Dir "Zip___Win32_Unicode_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 2
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Unicode_Debug"
+# PROP Intermediate_Dir "Unicode_Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "ZLIB_DLL" /Fr /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /MDd /W4 /Gm /GX /ZI /Od /D "ZLIB_DLL" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /D "_UNICODE" /Fr /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x415 /d "_DEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x415 /d "_DEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "ZipArchive - Win32 Unicode Release"
+
+# PROP BASE Use_MFC 2
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Zip___Win32_Unicode_Release"
+# PROP BASE Intermediate_Dir "Zip___Win32_Unicode_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 2
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Unicode_Release"
+# PROP Intermediate_Dir "Unicode_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /D "ZLIB_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_AFXDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x415 /d "NDEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x415 /d "NDEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "ZipArchive - Win32 Unicode Static Release"
+
+# PROP BASE Use_MFC 1
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Zip___Win32_Unicode_Static_Release"
+# PROP BASE Intermediate_Dir "Zip___Win32_Unicode_Static_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 1
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Unicode_Static_Release"
+# PROP Intermediate_Dir "Unicode_Static_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "ZLIB_DLL" /D "_UNICODE" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x415 /d "NDEBUG"
+# ADD RSC /l 0x415 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "ZipArchive - Win32 Release"
+# Name "ZipArchive - Win32 Debug"
+# Name "ZipArchive - Win32 Static Release"
+# Name "ZipArchive - Win32 Unicode Debug"
+# Name "ZipArchive - Win32 Unicode Release"
+# Name "ZipArchive - Win32 Unicode Static Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipAutoBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipBigFile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipCentralDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipException.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipFileHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipInternalInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipStorage.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipAutoBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipBigFile.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipCentralDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipException.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipFileHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipInternalInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ZipStorage.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\Appnote.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\zlib.lib
+# End Source File
+# End Target
+# End Project
+# Section ZipArchive : {427B9281-D5E8-11D3-B7C7-E75054E13747}
+# 2:12:AutoBuffer.h:AutoBuffer.h
+# 2:18:CLASS: CAutoBuffer:CAutoBuffer
+# 2:19:Application Include:Zip.h
+# 2:14:AutoBuffer.cpp:AutoBuffer.cpp
+# End Section
diff --git a/stepmania/src/smpackage/ZipArchive/ZipArchive.dsw b/stepmania/src/smpackage/ZipArchive/ZipArchive.dsw
new file mode 100644
index 0000000000..b4d097172a
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipArchive.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "ZipArchive"=.\ZipArchive.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/stepmania/src/smpackage/ZipArchive/ZipArchive.h b/stepmania/src/smpackage/ZipArchive/ZipArchive.h
new file mode 100644
index 0000000000..9f9eef92de
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipArchive.h
@@ -0,0 +1,698 @@
+// ZipArchive.h: interface for the CZipArchive class.
+//
+//////////////////////////////////////////////////////////////////////
+// ZipArchive 1.5.1, March 2001
+//
+//
+// This library allows to crate ZIP files in the compatible way with
+// PKZIP version 2.6. Some important issues:
+// - multiple disk spanning is supported
+// - encyption is not supported
+// - allows to create disk spanning archive also on non removable devices
+// and with user-defined volume size
+// - this library uses the zlib library by Jean-loup Gailly and Mark Adler
+// to perform inflate, deflate operations
+//
+//
+//
+// Copyright (C) 2000 - 2001 Tadeusz Dracz
+//
+//
+// Permission is granted to anyone to use this software for any purpose
+// and to alter it and redistribute it freely, subject to the
+// following restrictions:
+//
+// 1. Using this software in commercial applications requires an author permission.
+// The permission will be granted to everyone excluding the cases when
+// someone simply tries to resell the code.
+//
+// 2. 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.
+//
+// 3. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+//
+// 4. This notice may not be removed or altered from any source distribution.
+//
+//
+// You can contact me at:
+// tdracz@artpol.com.pl
+//
+// For new versions check the site:
+// http://software.artpol.com.pl
+//
+// History:
+// 03.2001
+//
+// - when the central directory was not located, the library throws CZipException::cdirNotFound,
+// which allows distinguish from other exceptions (useful when we want to keep prompting
+// the user to insert the last disk in a multi-disk spanning archive).
+//
+//
+// 02.2001
+// Features added:
+// - ability to reuse the archive after an exception thrown during extraction
+// - added progress control possibilities to CZipArchive::AddNewFile, CZipArchive::ExtractFile, CZipArchive::TestFile
+// Changes:
+// - CZipArchive::FindFile operation boosted ( thanks to Darin Warling for the idea)
+// - library name changed to ZipArchive
+// Bugs fixed:
+// - removed bug during extracting an encrypted file with 0 size
+// - fixed bug when extracting a file with an extra field in a local file header (CZipFileHeader::ReadLocal)
+//
+// 01.2001
+// - Disk numbering in a disk spanning archive begins now from PKBACK# 001 not PKBACK# 000
+// - Adding and extracting without a full path possible in CZipArchive::AddNewFile and CZipArchive::ExtractFile.
+// - Several minor changes and enhancements
+// - Changed names for several classes.
+//
+// 11.2000
+// - Added support for password encryption and decryption.
+// The encryption used in PKZIP was generously supplied by Roger
+// Schlafly.
+// - Testing the archive made easier
+// - Unicode support added
+//
+// 08.2000
+// - Bugs fixed
+//
+// 06.2000
+//
+// the code has been completely rewritten since the very beginning;
+// the main improvements are:
+// - multi-disk archive support
+// - creation of the disk spanning archives with the user-defined volume size
+// - ability to modify existing archives (add, delete files)
+// - modification self-extracting archives
+// - write buffer used for faster disk write operations
+// - one class for zip and unzip functions
+// - fast adding, deleting and extracting files with a single function call
+//
+// 03.2000
+// - international characters in filenames inside archive are now
+// converted in a compatible way with other archiving programs (they are stored
+// converted to OEM inside archive).
+//
+// 01.2000
+//
+// first version; it is just modified code from zip.c and unzip.c files
+// written by Gilles Vollant and distributed with zlib library;
+// the modifications are as follows:
+// - added class' wrappers
+// - several bugs fixed
+// - several enhancements added
+// - MFC support added
+// - memory leaks eliminated when write error occurred
+// - automatically free used memory on destruction or exception
+// - modern error notification using exceptions
+//
+// for more info about .ZIP format, see
+// ftp://ftp.pkware.com/appnote.zip
+// the unpacked file (appnote.txt) from this archive is a part of this project
+//
+//
+// Note:
+// if a file added to the archive is bigger after compressing
+// (e.g. it is an other archive) it should be delted from the archive and
+// added once again with store method (it may be done only on the files
+// not divided between volumes)
+
+#if !defined(AFX_ZIPARCHIVE_H__A7F528A6_1872_4071_BE66_D56CC2DDE0E6__INCLUDED_)
+#define AFX_ZIPARCHIVE_H__A7F528A6_1872_4071_BE66_D56CC2DDE0E6__INCLUDED_
+
+#include "ZipStorage.h" // Added by ClassView
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "ZipException.h"
+#include "ZipCentralDir.h" // Added by ClassView
+#include "ZipInternalInfo.h" // Added by ClassView
+
+
+//////////////////////////////////////////////////////////////////////////
+///////////////////// CZipArchive /////////////////////////////////////
+
+class CZipArchive
+{
+public:
+ static int SingleToWide(CZipAutoBuffer &szSingle, CString& szWide);
+ static int WideToSingle(LPCTSTR lpWide, CZipAutoBuffer &szSingle);
+
+// Function name : TestFile
+// Description : Test the file with the given index
+// the function throws CException*, but performs all the necessary cleanup
+// before, so that the next file can be tested after catchig the exception
+// and examining it for the reason of error.
+// Return type : bool
+// return false if the incorrect action has been taken by
+// the user or the programmer (it is when OpenFile(WORD nIndex) or
+// GetFileInfo(CZipFileHeader & fhInfo, WORD uIndex) return false or uBufSize
+// is 0
+// Argument : WORD uIndex
+// index of the file to test
+// Argument : ZIPCALLBACKFUN pCallback = NULL
+// See the description at AddNewFile
+// Argument : void* pUserData = NULL
+// Argument : DWORD uBufSize = 65535
+// the size of the buffer used during extraction
+ bool TestFile(WORD uIndex, ZIPCALLBACKFUN pCallback = NULL, void* pUserData = NULL, DWORD uBufSize = 65535);
+
+// Function name : CloseFileAfterTestFailed
+// Description : Perform the necessary cleanup after the exception
+// while testing the archive so that next files in the archive can be tested
+// Return type : void
+ void CloseFileAfterTestFailed();
+
+
+// Function name : SetPassword
+// Description : set the password for the file that is going to be opened or created
+// use this function BEFORE opening or adding a file
+// Return type : bool
+// return false if the password contains ASCII characters
+// with values 128 or higher or the file inside archive is
+// opened
+// Argument : LPCTSTR lpszPassword = NULL
+// set it to NULL to clear password
+ bool SetPassword(LPCTSTR lpszPassword = NULL);
+
+// Function name : SetAdvanced
+// Description : set advanced options
+// Return type : void
+// Argument : int iWriteBuffer = 65535
+// buffer used during write operation to the disk, the bigger, the better;
+// it is pointless, however, to set it bigger than the size of the volume;
+// the optimal size is the size of the volume
+// Argument : int iExtractBuffer = 16384
+// set the size of the buffer used in extracting and compressing files
+// default 16384, must not be < 1024
+// set it before opening the archive
+// Argument : int iSearchBuffer = 32768
+// set the size of the buffer used in searching for the central dir
+// useful with big archives, default 32768, must not be < 1024
+ void SetAdvanced(int iWriteBuffer = 65535, int iExtractBuffer = 16384, int iSearchBuffer = 32768);
+
+// Function name : SetSpanCallback
+// Description : set callback function used during operations on a
+// pkzip compatible disk spanning archive to change disks;
+// set it usualy before opening the archive for reading
+// Return type : void
+// Argument : ZIPCALLBACKFUN pFunc
+// for the description of callback function see CZipStorage.h
+// Argument : void* pData
+// user data to be passed to the callback function as the last parameter
+ void SetSpanCallback(ZIPCALLBACKFUN pFunc, void* pData = NULL);
+
+// archive open modes
+ enum {open, openReadOnly, create, createSpan};
+
+// Disk spanning archive modes:
+// pkzip compatible mode (pkSpan):
+// - only on removeble devices
+// - autodetect the size of the volume
+// - write a label to the disk
+// - there is a need to set the span callback function
+// TD mode (tdSpan):
+// - may be created on non removable devices
+// - uses user-defined volume size
+// - no need to set the span callback function
+
+// Function name : Open
+// Description : Open a zip archive
+// Return type : void
+// Argument : LPCTSTR szPathName
+// Path to the archive
+// Argument : int iMode= CZipArchive::open;
+// open mode flags:
+// open open an existing archive
+// openReadOnly open an existing archive as read only file
+// (this mode is intended to use in self extract code)
+// if you try to add or delete a file in this mode, an exception will be thrown
+// create create a new archive
+// createSpan create a disk spanning archive
+// Argument : int iVolumeSize = 0
+// if iMode == createSpan and iVolumeSize <= 0 then create disk spanning
+// archive in pkzip mode
+// if iMode == createSpan and iVolumeSize > 0 then create disk spanning
+// archive in TD mode
+// if iMode == open and the exisitng archive is a spanned archive
+// the pkSpan mode is assumed if the archive is on a removable device
+// or tdSpan otherwise;
+// if you want to open tdSpan archive on a removable device, set iVolumeSize
+// to a value different from 0
+// if iMode == create this argument doesn't matter
+ void Open(LPCTSTR szPathName, int iMode = open, int iVolumeSize = 0);
+
+// Function name : Open
+// Description : Open or create an archive in CMemFile
+// Return type : void
+// Argument : CMemFile& mf
+// Argument : int iMode = open
+// the following modes are valid: open, openReadOnly, create
+ void Open(CMemFile& mf, int iMode = open);
+
+
+// Function name : AddNewFile
+// Description : add quickly a new file to the archive
+// Return type : bool
+// Argument : LPCTSTR lpszFilePath
+// file to be added
+// Argument : int iLevel = Z_DEFAULT_COMPRESSION
+// the compression level (see OpenNewFile() for detailed desciption)
+// Argument : bool bFullPath
+// if true, include full path of the file inside the archive
+// Argument : ZIPCALLBACKFUN pCallback = NULL
+// callback function (may be NULL)
+// To set the callback function for this operation pass its pointer as the
+// argument (do not use SetSpanCallback for it - its for different purposes).
+// The callback function, if set, is called after reading and writing one portion of data.
+// - the first argument (DWORD):
+// total number of bytes to read (the size of the file)
+// - the second one (int) :
+// total number bytes already read
+// - the third argument (void*):
+// pUserData argument passed to #AddNewFile
+// Argument : void* pUserData = NULL
+// user - defined data passed on to the callback function
+// (doesn't matter if there is no callback function defined)
+// Argument : DWORD nBufSize = 65535
+// the size of the buffer used during compression
+
+/*
+*/
+ bool AddNewFile(LPCTSTR lpszFilePath, int iLevel = -1, bool bFullPath = true, ZIPCALLBACKFUN pCallback = NULL, void* pUserData = NULL, unsigned long nBufSize = 65535);
+
+// Function name : OpenNewFile
+// Description : add a new file to the zip archive
+// Return type : bool
+// return false in the following cases:
+// - the lpszFilePath is not NULL and the file attributes and data was not correctly retreived
+// - a file is already opened for extraction or compression
+// - archive is an existing disk span archive
+// - maximum file count inside archive reached (65535)
+// Argument : CZipFileHeader & header
+// structure that have addtional information; the following fields are valid:
+// - m_uMethod - file compression method; can be 0 (storing) or Z_DEFLATE (deflating)
+// otherwise Z_DEFLATE is assumed
+// - m_uModDate, m_uModTime - use SetTime method of CFileHeadeer to set them
+// if lpszFilePath is not NULL this fields are updated automaticaly
+// - m_uExternalAttr - attributes of the file
+// if lpszFilePath is not NULL this field is updated automaticaly
+// - m_szFileName - file name (may be with path) to be stored inside archive
+// to represent this file
+// - m_szComment - file comment
+// - m_pExtraField - LOCAL extra field, use SetExtraField() after opening
+// a new file, but before closing it to set the extra field
+// in the header in the central directory
+// other fields are ignored - they are updated automaticaly
+// Argument : int iLevel = Z_DEFAULT_COMPRESSION
+// the level of compression (-1, 0 - 9); named values:
+// Z_DEFAULT_COMPRESSION : -1
+// Z_NO_COMPRESSION : 0
+// Z_BEST_SPEED : 1
+// Z_BEST_COMPRESSION : 9
+// Argument : LPCTSTR lpszFilePath = NULL
+// the path to the file to retreive date and attributes from
+ bool OpenNewFile(CZipFileHeader & header, int iLevel = Z_DEFAULT_COMPRESSION, LPCTSTR lpszFilePath = NULL);
+
+// Function name : WriteNewFile
+// Description : compress the contents of the buffer and write it to a new file
+// Return type : bool
+// return false if the new file hasn't been opened
+// Argument : void *pBuf
+// buffer containing the data to be compressed and written
+// Argument : DWORD iSize
+// the size of the buffer
+ bool WriteNewFile(void *pBuf, DWORD iSize);
+
+// Function name : SetExtraField
+// Description : set the extra field in the file header in the central directory
+// must be used after opening a new file in the archive, but before closing it
+// Return type : void
+// Argument : char *pBuf
+// bufer with the data to be copied
+// Argument : DWORD iSize
+// size of the buffer
+ void SetExtraField(char *pBuf, WORD iSize);
+
+// Function name : CloseNewFile
+// Description : close the new file in the archive
+// Return type : bool
+// return false if no new file is opened
+// Argument : bool bAfterException = false
+// set it to true if you want to reuse CZipArchive after is has thrown an exception
+ bool CloseNewFile();
+
+// Function name : ExtractFile
+// Description : fast extracting
+// Return type : bool
+// Argument : WORD uIndex
+// the index of the file
+// Argument : LPCTSTR lpszPath
+// PATH only to extract the file to
+// Argument : bool bFullPath = true
+// extract the file with full path (if there is a path stored with the filename)
+// or just with the filename alone
+// (it means that the resulting file path is lpszPath + one of the above)
+// Argument : LPCTSTR lpszNewName = NULL
+// if NULL the default file name is taken (from the archive)
+// Argument : ZIPCALLBACKFUN pCallback = NULL
+// See the description at AddNewFile
+// Argument : void* pUserData = NULL
+// Argument : DWORD nBufSize = 65535
+// the size of the buffer used during extraction
+ bool ExtractFile(WORD uIndex, LPCTSTR lpszPath, bool bFullPath = true, LPCTSTR lpszNewName = NULL, ZIPCALLBACKFUN pCallback = NULL, void* pUserData = NULL, DWORD nBufSize = 65535);
+
+// Function name : OpenFile
+// Description : open the file with the given index in the archive for extracting
+// Argument : WORD uIndex
+// Return type : bool
+ bool OpenFile(WORD uIndex);
+
+// Function name : ReadFile
+// Description : decompress currently opened file to the bufor
+// Return type : DWORD
+// number of bytes read
+// Argument : void *pBuf
+// buffer to receive data
+// Argument : DWORD iSize
+// the size of the buffer
+ DWORD ReadFile(void *pBuf, DWORD iSize);
+
+// Function name : GetLocalExtraField
+// Description : get the local extra filed of the currently opened
+// for extraction file in the archive
+// Return type : int
+// if pBuf == NULL return the size of the local extra field
+// Argument : char* pBuf
+// the buffer to receive the data
+// Argument : int iSize
+// the size of the buffer
+ int GetLocalExtraField(char* pBuf, int iSize);
+
+// Function name : CloseFile
+// Description : close current file and update
+// date and attribute information of CFile, closes CFile
+// Return type : int
+// see below
+// Argument : CFile & file
+// OPENED CFile structure of the extracted file
+ int CloseFile(CFile &file);
+
+
+/**
+ Close the file opened for extraction in the archive and copy its date and
+ attributes to the file pointed by \e lpszFilePath
+ \param lpszFilePath
+ Points to the path of the file to have the date and attributes information updated.
+ \param bAfterException
+ Set to \c true to close the file inside archive after an exception has been
+ thrown, to allow futher operations on the archive.
+ \warning Close the file pointed by \e lpszFilePath before using this method,
+ because the system may not be able to retrieve information from it.
+ \return
+ - "1" = ok
+ - "-1" = some bytes left to uncompress - probably due to a bad password
+ - "-2" = setting extracted file date and attributes was not successful
+ \note Throws exceptions.
+*/
+ int CloseFile(LPCTSTR lpszFilePath = NULL, bool bAfterException = false);
+
+// Function name : DeleteFile
+// Description : delete the file with the given index
+// Return type : bool
+// Argument : WORD uIndex
+// index of the file to be deleted
+ bool DeleteFile(WORD uIndex);
+
+/* delete files from the archive opened in the Delete mode specified by aIndexes
+ or aNames
+
+ aIndexes is a array of indexes of the files inside the archive;
+ the index no. 0 is the first file in the archive
+
+ aNames is a array of file names inside the archive; they must be the
+ same as they apppear in the archive (the name and the path (if persists)
+ is required, lower and upper case are not distinguished)
+
+*/
+ void DeleteFiles(CWordArray &aIndexes);
+ void DeleteFiles(CStringArray &aNames, bool bCaseSensitive = false);
+
+
+// Function name : SetGlobalComment
+// Description : set the global comment in the archive
+// Return type : bool
+// return false if the archive is closed or if it is an existing disk spanning archive
+// Argument : const CString& szComment
+ bool SetGlobalComment(const CString& szComment);
+
+// Function name : GetGlobalComment
+// Description : get the global commment
+// Return type : CString
+// return an empty string if the archive is closed
+ CString GetGlobalComment();
+
+
+// Function name : SetFileComment
+// Description : set the comment of the file with the given index
+// Return type : bool
+// return false if the comment change is imposible
+// Argument : WORD uIndex
+// index of the file
+// Argument : CString szComment
+// comment to add
+ bool SetFileComment(WORD uIndex, CString szComment);
+
+// Function name : GetArchivePath
+// Description : return the path of the currently opended archive volume
+// Return type : CString
+ CString GetArchivePath();
+
+// Function name : GetCurrentDisk
+// Description : return the zero-base number of the current disk
+// Return type : int
+// return -1 if there is no current disk (archive is closed)
+ int GetCurrentDisk();
+
+// Function name : GetSpanMode
+// Description : return the disk spanning mode of the cuurrent archive
+// Return type : int
+// CZipStorage::tdSpan == - 2 - exisitng TD compatible disk spanning
+// CZipStorage::pkzipSpan == - 1 - exisitng pkzip compatible disk spanning
+// CZipStorage::noSpan == 0 - no disk spanning
+// CZipStorage::pkzipSpan == 1 - pkzip compatible disk spanning in creation
+// CZipStorage::tdSpan == 2 - TD compatible disk spanning in creation
+ int GetSpanMode();
+
+// Function name : IsFileDirectory
+// Description : check if the file with the given index is a directory
+// Argument : WORD uIndex
+// index of the file
+// Return type : bool
+// return true if the file is a directory
+// return false if the file is not a directory or if there is no file
+// with the given index
+ bool IsFileDirectory(WORD uIndex);
+
+// Function name : FindFile
+// Description : find the file in the archive
+// This function requires CZipCentralDir::m_bFindFastEnabled set to true
+// Use EnableFindFast()
+// Return type : int
+// the index of the file found or -1 if no file was found
+// Argument : CString szFileName
+// the name of the file to be found
+// Argument : bool bCaseSensitive = false
+// if true - perform case sensitive search
+ int FindFile(CString szFileName, bool bCaseSensitive = false);
+
+
+/*
+ Function name : EnableFindFast
+ Description :
+ Enable fast finding by the file name of the files inside the archive.
+ Set CZipCentralDir::m_bFindFastEnabled to true, which is required by FindFile.
+ Do not enable it, if you don't plan to use FindFile function
+
+ Return type : void
+ Argument : bool bEnable = true
+*/
+ void EnableFindFast(bool bEnable = true);
+
+
+/*
+ Function name : SetConvertAfterOpen
+ Description : Set CZipCentralDir::m_bConvertAfterOpen value. Use before opening the archive
+ see CZipCentralDir::m_bConvertAfterOpen
+ Return type : void
+ Argument : bool bConvertAfterOpen
+*/
+ void SetConvertAfterOpen (bool bConvertAfterOpen)
+ {
+ if (!IsClosed())
+ {
+ TRACE(_T("Set it before opening the archive"));
+ return;
+ }
+ m_centralDir.m_bConvertAfterOpen = bConvertAfterOpen;
+
+ }
+
+
+// Function name : GetFileInfo
+// Description : get the info of the file with the given index
+// Return type : bool
+// true if successful
+// Argument : CZipFileHeader & fhInfo
+// structure to receive info
+// Argument : WORD uIndex
+// zero-based index of the file
+ bool GetFileInfo(CZipFileHeader & fhInfo, WORD uIndex);
+
+
+// Function name : GetNoEntries
+// Description : get number of files in the archive
+// Return type : int
+ int GetNoEntries();
+
+// Function name : Close
+// Description : close archive
+// Return type : void
+// Argument : bool bAfterException = false
+// set it to true if you want to close and reuse CZipArchive after is has thrown an exception
+// ( it doesn't write any data to the file but only makes some cleaning then)
+ void Close(bool bAfterException = false);
+
+
+
+// Function name : IsClosed
+// Description : test if the archive or the current volume file is closed
+// Return type : bool
+// Argument : bool bArchive = true
+// if true test for the whole archive, if false - for the volume file only
+ bool IsClosed(bool bArchive = true);
+
+// specify whether to control memory allocation and freeing by zlib library
+// strongly suggested to set it to true (default)
+// set it before opening a file (new or current) in the archive
+ bool m_bDetectZlibMemoryLeaks;
+
+
+ CZipArchive();
+ virtual ~CZipArchive();
+
+////////////////////////////////////////////////////////////////////////
+////////////////////// static helper functions ///////////////////////
+////////////////////////////////////////////////////////////////////////
+
+// Function name : GetFileTitle
+// Description : get the title of the file
+// Return type : CString
+// Argument : LPCTSTR lpszFilePath
+ static CString GetFileTitle(LPCTSTR lpszFilePath);
+
+// Function name : GetFileDirAndName
+// Description : get the directory and the file name from the file path
+// Return type : static CString
+// Argument : LPCTSTR lpszFilePath
+ static CString GetFileDirAndName(LPCTSTR lpszFilePath);
+
+// Function name : GetDrive
+// Description : return the (drive:) part from the path
+// Return type : static CString
+// Argument : LPCTSTR lpszFilePath
+ static CString GetDrive(LPCTSTR lpszFilePath);
+
+// Function name : IsDriveRemovable
+// Description : return true if the file, path or (disk:) specified by the
+// argument is (on) a removable drive
+// Return type : static bool
+// Argument : LPCTSTR lpszFilePath
+ static bool IsDriveRemovable(LPCTSTR lpszFilePath);
+
+// Function name : DirectoryExists
+// Description : check if the given directory exists
+// Return type : static bool
+// Argument : LPCTSTR lpszDir
+ static bool DirectoryExists(LPCTSTR lpszDir);
+
+
+// Function name : FileExists
+// Description : check if the given file or directory exists
+// Return type : static int
+// return -1 if the given file is a directory, 1 if is a file
+// or 0 if there is no such a file
+// Argument : LPCTSTR lpszName
+ static int FileExists(LPCTSTR lpszName);
+
+// Function name : ForceDirectory
+// Description : create nested directories with a single command
+// Return type : static bool
+// Argument : LPCTSTR lpDirectory
+ static bool ForceDirectory(LPCTSTR lpDirectory);
+
+// Function name : GetFilePath
+// Description : get the path of the given file
+// Return type : static CString
+// Argument : LPCTSTR strFilePath
+ static CString GetFilePath(LPCTSTR lpszFilePath);
+
+
+// Function name : GetFileExt
+// Description : return the file extension
+// Return type : static CString
+// Argument : LPCTSTR lpszFilePath
+ static CString GetFileExt(LPCTSTR lpszFilePath);
+
+
+// Function name : GetFileName
+// Description : return the name of the file (title + extension)
+// Return type : static CString
+// Argument : LPCTSTR lpszFilePath
+ static CString GetFileName(LPCTSTR lpszFilePath);
+
+ // just a helper for a various purposes
+ static const DWORD* GetCRCTable();
+ // function for a VERY advanced use - you normally never need that
+ CZipStorage* GetStorage(){return &m_storage;}
+
+protected:
+ void EmptyPtrList();
+ void CryptDecodeBuffer(DWORD uCount);
+ void CryptEncodeBuffer();
+ void CryptEncode(char &c);
+ void CryptCryptHeader(long iCrc, CZipAutoBuffer& buf);
+ DWORD CryptCRC32(DWORD l, char c);
+ void CryptDecode(char &c);
+ char CryptDecryptByte();
+ bool CryptCheck();
+ void CryptUpdateKeys(char c);
+ void CryptInitKeys();
+ CZipAutoBuffer m_pszPassword;
+ DWORD m_keys[3];
+
+ static int CompareWords(const void *pArg1, const void *pArg2);
+ bool IsDirectory(DWORD uAttr);
+ void DeleteInternal(WORD uIndex);
+ DWORD RemovePackedFile(DWORD uStartOffset, DWORD uEndOffset);
+ CZipFileHeader* CurrentFile();
+ void CheckForError(int iErr);
+ CZipInternalInfo m_info;
+ CZipStorage m_storage;
+ CPtrList m_list;
+ static void* myalloc(void* opaque, UINT items, UINT size);
+ static void myfree(void* opaque, void* address);
+ enum {extract = -1, nothing, compress};
+ // 0 - no file inside archive opened
+ // -1 - current opened for extract
+ // 1 - new opened for compression
+ char m_iFileOpened;
+ void ThrowError(int err);
+ CZipCentralDir m_centralDir;
+ static TCHAR m_gszCopyright[];
+};
+
+#endif // !defined(AFX_ZIPARCHIVE_H__A7F528A6_1872_4071_BE66_D56CC2DDE0E6__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipArchive.opt b/stepmania/src/smpackage/ZipArchive/ZipArchive.opt
new file mode 100644
index 0000000000000000000000000000000000000000..fe0f7099462c190196c3db63663cf2d71a766375
GIT binary patch
literal 48640
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
literal 0
HcmV?d00001
diff --git a/stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.cpp b/stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.cpp
new file mode 100644
index 0000000000..1197be39c1
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.cpp
@@ -0,0 +1,104 @@
+// ZipAutoBuffer.cpp: implementation of the CZipAutoBuffer class.
+// Part of the ZipArchive library
+//
+// Copyright (C) 2000 - 2001 Tadeusz Dracz.
+// This program 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.
+//
+// For the licensing details see the file License.txt
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include "stdafx.h"
+#include "ZipAutoBuffer.h"
+#include
+
+// #ifdef _DEBUG
+// #undef THIS_FILE
+// static char THIS_FILE[]=__FILE__;
+// #define new DEBUG_NEW
+// #endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CZipAutoBuffer::CZipAutoBuffer()
+{
+ m_iSize = 0;
+ m_pBuffer = NULL;
+}
+
+CZipAutoBuffer::CZipAutoBuffer(DWORD iSize, bool bZeroMemory)
+{
+ m_iSize = 0;
+ m_pBuffer = NULL;
+ Allocate(iSize, bZeroMemory);
+}
+
+CZipAutoBuffer::~CZipAutoBuffer()
+{
+ Release();
+}
+
+
+void CZipAutoBuffer::Release()
+{
+ if (m_pBuffer)
+ {
+ delete [] m_pBuffer;
+ m_iSize = 0;
+ m_pBuffer = NULL;
+ }
+}
+
+char* CZipAutoBuffer::Allocate(DWORD iSize, bool bZeroMemory)
+{
+ if (iSize != m_iSize)
+ Release();
+ else
+ {
+ if (bZeroMemory)
+ memset(m_pBuffer, 0, iSize); // zerowanie bufora
+ return m_pBuffer;
+ }
+
+ if (iSize > 0)
+ {
+ m_pBuffer = new char [iSize];
+ if (bZeroMemory)
+ memset(m_pBuffer, 0, iSize); // zerowanie bufora
+ m_iSize = iSize;
+ }
+ else
+ m_pBuffer = NULL;
+
+ return m_pBuffer;
+}
+
+
+CZipAutoBuffer::CZipAutoBuffer(const CZipAutoBuffer& buffer)
+{
+ m_pBuffer = NULL;
+ m_iSize = 0;
+
+ if (buffer.m_pBuffer)
+ {
+ Allocate(buffer.m_iSize);
+ memcpy(m_pBuffer, buffer.m_pBuffer, buffer.m_iSize);
+ }
+}
+CZipAutoBuffer& CZipAutoBuffer::operator=(const CZipAutoBuffer& buffer)
+{
+ if (this == &buffer)
+ return *this;
+ Release();
+ if (buffer.m_pBuffer)
+ {
+ Allocate(buffer.m_iSize);
+ memcpy(m_pBuffer, buffer.m_pBuffer, buffer.m_iSize);
+ }
+ return *this;
+}
\ No newline at end of file
diff --git a/stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.h b/stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.h
new file mode 100644
index 0000000000..404e6fb765
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipAutoBuffer.h
@@ -0,0 +1,63 @@
+/**
+* \file ZipAutoBuffer.h
+* Interface for the CZipAutoBuffer class.
+*
+* \author Tadeusz Dracz
+*/
+// Part of the ZipArchive library
+//
+// Copyright (C) 2000 - 2001 Tadeusz Dracz.
+// This program 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.
+//
+// For the licensing details see the file License.txt
+////////////////////////////////////////////////////////////////////////////////
+
+
+#if !defined(AFX_ZIPAUTOBUFFER_H__DEC28C20_83FE_11D3_B7C3_EDEC47A8A86C__INCLUDED_)
+#define AFX_ZIPAUTOBUFFER_H__DEC28C20_83FE_11D3_B7C3_EDEC47A8A86C__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+/**
+ A smart buffer freeing its contents on destruction.
+*/
+class CZipAutoBuffer
+{
+public:
+ operator char*()
+ {
+ return m_pBuffer;
+ }
+
+ // may produce ambiguity on some compilers
+// operator const char*() const
+// {
+// return m_pBuffer;
+// }
+ const char* GetBuffer() const {return m_pBuffer;}
+ char* Allocate(DWORD iSize, bool bZeroMemory = false);
+ void Release();
+ DWORD GetSize() const
+ {
+ return m_iSize;
+ }
+ bool IsAllocated() const
+ {
+ return (m_pBuffer != NULL);
+ }
+ CZipAutoBuffer(DWORD iSize, bool bZeroMemory = false);
+ CZipAutoBuffer();
+ CZipAutoBuffer(const CZipAutoBuffer& buffer);
+ virtual ~CZipAutoBuffer();
+ CZipAutoBuffer& operator=(const CZipAutoBuffer& buffer);
+protected:
+ char* m_pBuffer;
+ DWORD m_iSize;
+};
+
+#endif // !defined(AFX_ZIPAUTOBUFFER_H__DEC28C20_83FE_11D3_B7C3_EDEC47A8A86C__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipBigFile.cpp b/stepmania/src/smpackage/ZipArchive/ZipBigFile.cpp
new file mode 100644
index 0000000000..1239e8e355
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipBigFile.cpp
@@ -0,0 +1,41 @@
+// ZipBigFile.cpp: implementation of the CZipBigFile class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ZipBigFile.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+IMPLEMENT_DYNAMIC(CZipBigFile, CFile)
+
+CZipBigFile::CZipBigFile()
+{
+
+}
+
+CZipBigFile::~CZipBigFile()
+{
+
+}
+
+_int64 CZipBigFile::Seek(_int64 dOff, UINT nFrom)
+{
+ ASSERT_VALID(this);
+ ASSERT(m_hFile != (UINT)hFileNull);
+ ASSERT(nFrom == begin || nFrom == end || nFrom == current);
+ ASSERT(begin == FILE_BEGIN && end == FILE_END && current == FILE_CURRENT);
+ LARGE_INTEGER li;
+ li.QuadPart = dOff;
+
+ li.LowPart = ::SetFilePointer((HANDLE)m_hFile, li.LowPart, &li.HighPart, (DWORD)nFrom);
+ DWORD dw = GetLastError();
+ if ((li.LowPart == (DWORD)-1) && (dw != NO_ERROR))
+ {
+ CFileException::ThrowOsError((LONG)dw);
+ }
+
+ return li.QuadPart;
+
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipBigFile.h b/stepmania/src/smpackage/ZipArchive/ZipBigFile.h
new file mode 100644
index 0000000000..3790dd3c56
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipBigFile.h
@@ -0,0 +1,22 @@
+// ZipBigFile.h: interface for the CZipBigFile class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_ZipBigFile_H__79E0E6BD_25D6_4B82_85C5_AB397D9EC368__INCLUDED_)
+#define AFX_ZipBigFile_H__79E0E6BD_25D6_4B82_85C5_AB397D9EC368__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+class CZipBigFile : public CFile
+{
+ DECLARE_DYNAMIC(CZipBigFile)
+public:
+ _int64 Seek(_int64 dOff, UINT nFrom);
+ CZipBigFile();
+ virtual ~CZipBigFile();
+
+};
+
+#endif // !defined(AFX_ZipBigFile_H__79E0E6BD_25D6_4B82_85C5_AB397D9EC368__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipCentralDir.cpp b/stepmania/src/smpackage/ZipArchive/ZipCentralDir.cpp
new file mode 100644
index 0000000000..012c21ab79
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipCentralDir.cpp
@@ -0,0 +1,677 @@
+// ZipCentralDir.cpp: implementation of the CZipCentralDir class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include "stdafx.h"
+#include "ZipCentralDir.h"
+#include "ZipArchive.h"
+
+struct CZipAutoHandle
+{
+ HANDLE m_hFileMap;
+ LPVOID m_pFileMap;
+ CZipAutoHandle()
+ {
+ m_hFileMap = NULL;
+ m_pFileMap = NULL;
+ }
+ bool CreateMapping(HANDLE hFile)
+ {
+ m_hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,
+ 0, 0, _T("ZipArchive Mapping File"));
+ if (!m_hFileMap)
+ return false;
+ // Get pointer to memory representing file
+ m_pFileMap = MapViewOfFile(m_hFileMap, FILE_MAP_WRITE, 0, 0, 0);
+ return (m_pFileMap != NULL);
+ }
+ void RemoveMapping()
+ {
+ if (m_pFileMap)
+ {
+ UnmapViewOfFile(m_pFileMap);
+ m_pFileMap = NULL;
+ }
+ if (m_hFileMap)
+ {
+ CloseHandle(m_hFileMap);
+ m_hFileMap = NULL;
+ }
+
+ }
+ ~CZipAutoHandle()
+ {
+ RemoveMapping();
+ }
+};
+
+#define ZIPCENTRALDIRSIZE 22
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+char CZipCentralDir::m_gszSignature[] = {0x50, 0x4b, 0x05, 0x06};
+CZipCentralDir::CZipCentralDir()
+{
+ m_bConvertAfterOpen = true;
+ m_bFindFastEnabled = false;
+ m_pStorage = NULL;
+ m_pOpenedFile = NULL;
+ m_iBufferSize = 32768;
+
+}
+
+void CZipCentralDir::Init()
+{
+ m_bOnDisk = false;
+ m_uBytesBeforeZip = m_uCentrDirPos = 0;
+ m_pOpenedFile = NULL;
+ m_pszComment.Release();
+}
+
+CZipCentralDir::~CZipCentralDir()
+{
+ Clear();
+}
+
+void CZipCentralDir::Read()
+{
+ ASSERT(m_pStorage);
+ WORD uCommentSize;
+ m_uCentrDirPos = Locate();
+ m_pStorage->m_pFile->Seek(m_uCentrDirPos, CFile::begin);
+ CZipAutoBuffer buf(ZIPCENTRALDIRSIZE);
+ DWORD uRead = m_pStorage->m_pFile->Read(buf, ZIPCENTRALDIRSIZE );
+ if (uRead != ZIPCENTRALDIRSIZE)
+ ThrowError(ZIP_BADZIPFILE);
+ memcpy(&m_szSignature, buf, 4);
+ memcpy(&m_uThisDisk, buf + 4, 2);
+ memcpy(&m_uDiskWithCD, buf + 6, 2);
+ memcpy(&m_uDiskEntriesNo, buf + 8, 2);
+ memcpy(&m_uEntriesNumber, buf + 10, 2);
+ memcpy(&m_uSize, buf + 12, 4);
+ memcpy(&m_uOffset, buf + 16, 4);
+ memcpy(&uCommentSize, buf + 20, 2);
+ buf.Release();
+
+
+ m_pStorage->UpdateSpanMode(m_uThisDisk);
+ // if m_uThisDisk is not zero, it is enough to say that it is multi archive
+ ASSERT((!m_uThisDisk && (m_uEntriesNumber == m_uDiskEntriesNo) && !m_uDiskWithCD) || m_uThisDisk);
+
+
+
+ if (!m_pStorage->IsSpanMode() && ((DWORD)m_uCentrDirPos < m_uOffset + m_uSize))
+ ThrowError(ZIP_BADZIPFILE);
+
+ if (uCommentSize)
+ {
+ m_pszComment.Allocate(uCommentSize);
+ uRead = m_pStorage->m_pFile->Read(m_pszComment, uCommentSize);
+ if (uRead != uCommentSize)
+ ThrowError(ZIP_BADZIPFILE);
+ }
+
+ m_uBytesBeforeZip = m_pStorage->IsSpanMode() ? 0 : m_uCentrDirPos - m_uSize - m_uOffset;
+
+ if ((!m_uSize && m_uEntriesNumber) || (!m_uEntriesNumber && m_uSize))
+ ThrowError(ZIP_BADZIPFILE);
+
+ m_bOnDisk = true;
+ m_pStorage->ChangeDisk(m_uDiskWithCD);
+
+ if (!m_uSize)
+ return;
+
+ ReadHeaders();
+}
+
+// return the location of the beginning of the "end" record in the file
+DWORD CZipCentralDir::Locate()
+{
+
+ // maximum size of end of central dir record
+ long uMaxRecordSize = 0xffff + ZIPCENTRALDIRSIZE;
+ DWORD uFileSize = m_pStorage->m_pFile->GetLength();
+
+ if ((DWORD)uMaxRecordSize > uFileSize)
+ uMaxRecordSize = uFileSize;
+
+ CZipAutoBuffer buf(m_iBufferSize);
+
+ long uPosInFile = 0;
+ int uRead = 0;
+ // backward reading
+ while (uPosInFile < uMaxRecordSize)
+ {
+ uPosInFile = uRead + m_iBufferSize;
+ if (uPosInFile > uMaxRecordSize)
+ uPosInFile = uMaxRecordSize;
+
+ int iToRead = uPosInFile - uRead;
+
+ m_pStorage->m_pFile->Seek(-uPosInFile, CFile::end);
+ int iActuallyRead = m_pStorage->m_pFile->Read(buf, iToRead);
+ if (iActuallyRead != iToRead)
+ ThrowError(ZIP_BADZIPFILE);
+ // search from the very last bytes to prevent an error if inside archive
+ // there are packed other arhives
+ for (int i = iToRead - 4; i >=0 ; i--)
+ if (!memcmp((char*)buf + i, m_gszSignature, 4))
+ return uFileSize - (uPosInFile - i);
+
+ uRead += iToRead - 3;
+
+ }
+
+ ThrowError(ZIP_CDIR_NOTFOUND);
+ return 0;
+}
+
+void CZipCentralDir::ThrowError(int err)
+{
+ AfxThrowZipException(err, m_pStorage->m_pFile->GetFilePath());
+}
+
+
+void CZipCentralDir::ReadHeaders()
+{
+ m_pStorage->m_pFile->Seek(m_uOffset + m_uBytesBeforeZip, CFile::begin);
+ RemoveHeaders();
+ for (int i = 0; i < m_uEntriesNumber; i++)
+ {
+ CZipFileHeader* pHeader = new CZipFileHeader;
+ m_headers.Add(pHeader); // bezpoœrednio nastêpuje w razie wyj¹tku
+
+ if (!pHeader->Read(m_pStorage))
+ ThrowError(ZIP_BADZIPFILE);
+ ConvertFileName(true, true, pHeader);
+ }
+ if (m_bFindFastEnabled)
+ BuildFindFastArray();
+
+}
+
+// remove all headers from the central dir
+void CZipCentralDir::Clear(bool bEverything)
+{
+ m_pOpenedFile = NULL;
+ m_pLocalExtraField.Release();
+
+ if (bEverything)
+ {
+ RemoveHeaders();
+ m_findarray.RemoveAll();
+ m_pszComment.Release();
+
+ }
+}
+
+
+bool CZipCentralDir::IsValidIndex(WORD uIndex)
+{
+
+ bool ret = uIndex < m_headers.GetSize();
+#ifdef _DEBUG
+ if (!ret)
+ TRACE(_T("Not a valid index.\n"));
+#endif
+ return ret;
+}
+
+// open the file for extracting
+void CZipCentralDir::OpenFile(WORD uIndex)
+{
+ WORD uLocalExtraFieldSize;
+ m_pOpenedFile = m_headers[uIndex];
+ m_pStorage->ChangeDisk(m_pOpenedFile->m_uDiskStart);
+ m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + m_uBytesBeforeZip, CFile::begin);
+ if (!m_pOpenedFile->ReadLocal(m_pStorage, uLocalExtraFieldSize))
+ ThrowError(ZIP_BADZIPFILE);
+
+
+ m_pLocalExtraField.Release(); // just in case
+ if (uLocalExtraFieldSize)
+ {
+ int iCurrDsk = m_pStorage->GetCurrentDisk();
+ m_pLocalExtraField.Allocate(uLocalExtraFieldSize);
+ m_pStorage->Read(m_pLocalExtraField, uLocalExtraFieldSize, true);
+ if (m_pStorage->GetCurrentDisk() != iCurrDsk)
+ ThrowError(ZIP_BADZIPFILE);
+ }
+
+}
+
+void CZipCentralDir::CloseFile()
+{
+ if (!m_pOpenedFile)
+ return;
+ m_pLocalExtraField.Release();
+ if (m_pOpenedFile->IsDataDescr())
+ {
+ CZipAutoBuffer buf(12);
+ m_pStorage->Read(buf, 4, false);
+ // in span mode, files that are divided between disks have bit 3 of flag set
+ // which tell about the presence of the data descriptor after the compressed data
+ // This signature may be in the disk spanning archive that is one volume only
+ // (it is detected as a non disk spanning archive)
+ if (memcmp(buf, CZipStorage::m_gszExtHeaderSignat, 4) != 0) // there is no signature
+ m_pStorage->m_pFile->Seek(-4, CFile::current);
+
+
+ m_pStorage->Read(buf, 12, false);
+ if (!m_pOpenedFile->CheckCrcAndSizes(buf))
+ ThrowError(ZIP_BADZIPFILE);
+ }
+ m_pOpenedFile = NULL;
+}
+
+// add new header using the argument as a template
+void CZipCentralDir::AddNewFile(CZipFileHeader & header)
+{
+ CZipFileHeader* pHeader = new CZipFileHeader(header);
+ m_pOpenedFile = pHeader;
+ m_headers.Add(pHeader);
+ if (m_bFindFastEnabled)
+ InsertFindFastElement(pHeader, WORD(m_headers.GetSize() - 1)); // GetSize IS > 0, 'cos we've just added a header
+ RemoveFromDisk();
+ m_pStorage->m_pFile->SeekToEnd();
+}
+
+// called during adding or deleting files; remove the central dir from the disk
+void CZipCentralDir::RemoveFromDisk()
+{
+ if (m_bOnDisk)
+ {
+ ASSERT(!m_pStorage->IsSpanMode()); // you can't add files to the existing disk span archive or to delete them from it
+ m_pStorage->m_pFile->SetLength(m_uBytesBeforeZip + m_uOffset);
+ m_bOnDisk = false;
+ }
+}
+
+
+void CZipCentralDir::CloseNewFile()
+{
+ CZipAutoBuffer buf(12 + 4);
+ short iToWrite = 0;
+ bool bIsSpan = m_pStorage->IsSpanMode() != 0;
+ bool bEncrypted = m_pOpenedFile->IsEncrypted();
+ if (m_pOpenedFile->IsDataDescr())
+ {
+ if (bIsSpan || bEncrypted)
+ {
+ memcpy(buf, m_pStorage->m_gszExtHeaderSignat, 4);
+ iToWrite += 4;
+ }
+ }
+ else /*if (!IsSpan)*/
+ {
+ ASSERT(!bIsSpan && !bEncrypted);
+ m_pStorage->Flush();
+ m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + 14, CFile::begin);
+ // we don't have to restore the pointer, because before adding a new file,
+ // the pointer is moved to the end
+ }
+
+ m_pOpenedFile->GetCrcAndSizes(buf + iToWrite);
+ iToWrite += 12;
+
+ // offset set during writting the local header
+ m_pOpenedFile->m_uOffset -= m_uBytesBeforeZip;
+
+ // write the data descriptor and a disk spanning signature at once
+ m_pStorage->Write(buf, iToWrite, true);
+ if (!bIsSpan && bEncrypted)
+ {
+ // write the information to the local header too
+ m_pStorage->Flush();
+ m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + 14, CFile::begin);
+ m_pStorage->Write(buf + 4, 12, true);
+ }
+
+ if (!bIsSpan)
+ m_pStorage->Flush();
+
+ m_pOpenedFile = NULL;
+
+}
+
+void CZipCentralDir::Write()
+{
+ if (m_bOnDisk)
+ return;
+ if (!m_pStorage->IsSpanMode())
+ {
+ m_pStorage->Flush();
+ m_pStorage->m_pFile->SeekToEnd();
+ }
+ m_uEntriesNumber = (WORD)m_headers.GetSize();
+ m_uSize = 0;
+ bool bDontAllowDiskChange = false;
+ // if there is a disk spanning archive in creation and it is only one-volume,
+ // (current disk is 0 so far, no bytes has been written so we know they are
+ // all in the buffer) make sure that it will be after writting central dir
+ // and make it a non disk spanning archive
+ if (m_pStorage->IsSpanMode() && m_pStorage->GetCurrentDisk() == 0)
+ {
+ DWORD uVolumeFree = m_pStorage->VolumeLeft();
+ // calculate the size of data descriptors already in the buffer or on the disk
+ // (they will be removed in the non disk spanning archive):
+ // multi span signature at the beginnig (4 bytes) + the size of the data
+ // descr. for each file (multi span signature + 12 bytes data)
+ // the count of bytes to add: central dir size - total to remove;
+ DWORD uToGrow = GetSize(true) - (4 + m_uEntriesNumber * (4 + 12));
+ if (uVolumeFree >= uToGrow)
+ // lets make sure it will be one-disk archive
+ {
+ // can the operation be done only in the buffer?
+ if (!m_pStorage->m_iBytesWritten && // no bytes on the disk yet
+ (m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough?
+ {
+ RemoveDataDescr(true);
+ bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
+ }
+ else
+ {
+ m_pStorage->Flush();
+ m_pStorage->m_pFile->Flush();
+ if (RemoveDataDescr(false))
+ bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
+ }
+ }
+ }
+
+ WriteHeaders();
+ m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
+ DWORD uSize = WriteCentralEnd();
+ if (bDontAllowDiskChange && (m_pStorage->GetCurrentDisk() != 0))
+ ThrowError(ZIP_BADZIPFILE);
+ // if after adding a central directory there is a disk change,
+ // update the information and write it again
+ if (m_uThisDisk != m_pStorage->GetCurrentDisk())
+ {
+ m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
+ if (m_uEntriesNumber)
+ {
+ m_uDiskEntriesNo = 0;
+ }
+ else
+ {
+ m_uDiskWithCD = m_uThisDisk;
+ m_uOffset = 0;
+ }
+
+ if (m_pStorage->m_uBytesInWriteBuffer >= uSize)
+ // if the data is still in the buffer, simply remove it
+ m_pStorage->m_uBytesInWriteBuffer -= uSize;
+ else
+ {
+ m_pStorage->Flush();
+ m_pStorage->m_iBytesWritten -= uSize;
+ m_pStorage->m_pFile->SeekToBegin();
+ }
+
+ WriteCentralEnd();
+ }
+
+}
+
+void CZipCentralDir::WriteHeaders()
+{
+ m_uDiskEntriesNo = 0;
+ m_uDiskWithCD = (WORD)m_pStorage->GetCurrentDisk();
+ m_uOffset = m_pStorage->GetPosition() - m_uBytesBeforeZip;
+ if (!m_uEntriesNumber)
+ return;
+
+ WORD iDisk = m_uDiskWithCD;
+ for (int i = 0; i < m_uEntriesNumber; i++)
+ {
+ CZipFileHeader* pHeader = m_headers[i];
+ ConvertFileName(false, true, pHeader);
+ m_uSize += pHeader->Write(m_pStorage);
+ if (m_pStorage->GetCurrentDisk() != iDisk)
+ {
+ m_uDiskEntriesNo = 1;
+ iDisk = (WORD)m_pStorage->GetCurrentDisk();
+ // update the information about the offset and starting disk if the
+ // first header was written on the new disk
+ if (i == 0)
+ {
+ m_uOffset = 0;
+ m_uDiskWithCD = iDisk;
+ }
+ }
+ else
+ m_uDiskEntriesNo++;
+ }
+}
+
+DWORD CZipCentralDir::WriteCentralEnd()
+{
+ DWORD uSize = GetSize();
+ CZipAutoBuffer buf(uSize);
+ WORD uCommentSize = (WORD)m_pszComment.GetSize();
+ memcpy(buf, m_gszSignature, 4);
+ memcpy(buf + 4, &m_uThisDisk, 2);
+ memcpy(buf + 6, &m_uDiskWithCD, 2);
+ memcpy(buf + 8, &m_uDiskEntriesNo, 2);
+ memcpy(buf + 10, &m_uEntriesNumber, 2);
+ memcpy(buf + 12, &m_uSize, 4);
+ memcpy(buf + 16, &m_uOffset, 4);
+ memcpy(buf + 20, &uCommentSize, 2);
+ memcpy(buf + 22, m_pszComment, uCommentSize);
+ m_pStorage->Write(buf, uSize, true);
+ return uSize;
+}
+
+
+void CZipCentralDir::RemoveFile(WORD uIndex)
+{
+ CZipFileHeader* pHeader = m_headers[uIndex];
+ if (m_bFindFastEnabled)
+ {
+ int i = FindFileNameIndex(pHeader->GetFileName(), true);
+ ASSERT(i != -1);
+ int uIndex = m_findarray[i].m_uIndex;
+ m_findarray.RemoveAt(i);
+ // shift down the indexes
+ for (int j = 0; j < m_findarray.GetSize(); j++)
+ {
+ if (m_findarray[j].m_uIndex > uIndex)
+ m_findarray[j].m_uIndex--;
+ }
+ }
+ delete pHeader;
+ m_headers.RemoveAt(uIndex);
+}
+
+
+DWORD CZipCentralDir::GetSize(bool bWhole)
+{
+ DWORD uHeaders = 0;
+ if (bWhole)
+ {
+ for (int i = 0; i < m_headers.GetSize(); i++)
+ uHeaders += m_headers[i]->GetSize();
+ }
+ return ZIPCENTRALDIRSIZE + m_pszComment.GetSize() + uHeaders;
+}
+
+// remove data descriptors from the write buffer in the disk spanning volume
+// that is one-disk only (do not remove from password encrypted files)
+bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
+{
+ CZipAutoHandle ah;
+ char* pFile = NULL;
+ DWORD uSize;
+ if (bFromBuffer)
+ {
+ uSize = m_pStorage->m_uBytesInWriteBuffer;
+ pFile = m_pStorage->m_pWriteBuffer;
+ }
+ else
+ {
+ uSize = m_pStorage->m_pFile->GetLength();
+ if (!ah.CreateMapping((HANDLE)m_pStorage->m_pFile->m_hFile))
+ return false;
+ pFile = (char*)ah.m_pFileMap;
+ }
+
+ DWORD uOffsetToChange = 4;
+ DWORD uToCopy = 0;
+ DWORD uPosInBuffer = 0;
+ DWORD uExtraHeaderLen;
+ // this will work providing the order in the m_headers is the same as
+ // in the archive
+ for (int i = 0; i < m_headers.GetSize(); i++)
+ {
+ // update the flag value in the local and central header
+// int uDataDescr = (m_headers[i]->m_uFlag & 8) ? (4 + 12) : 0;
+
+ CZipFileHeader* pHeader = m_headers[i];
+
+
+ char* pSour = pFile + pHeader->m_uOffset;
+
+ if (!pHeader->IsEncrypted())
+ {
+ // removing data descriptor
+ pHeader->m_uFlag &= ~8;
+ // update local header:
+ // write modified flag in the local header
+ memcpy(pSour + 6, &pHeader->m_uFlag, 2);
+ uExtraHeaderLen = 4/*ext. header signature*/ + 12/*data descriptor*/;
+ }
+ else
+ // do not remove data descriptors from encrypted files
+ uExtraHeaderLen = 0;
+
+ // update crc32 and sizes' values
+ pHeader->GetCrcAndSizes(pSour+ 14);
+
+ uToCopy = (i == (m_headers.GetSize() - 1) ? uSize : m_headers[i + 1]->m_uOffset)
+ - pHeader->m_uOffset - uExtraHeaderLen;
+
+ memmove(pFile + uPosInBuffer, pSour, uToCopy);
+
+ uPosInBuffer += uToCopy;
+ pHeader->m_uOffset -= uOffsetToChange;
+ uOffsetToChange += uExtraHeaderLen;
+ }
+
+ if (bFromBuffer)
+ m_pStorage->m_uBytesInWriteBuffer = uPosInBuffer;
+ else
+ {
+ m_pStorage->m_iBytesWritten = uPosInBuffer;
+ ah.RemoveMapping();
+ m_pStorage->m_pFile->SetLength(uPosInBuffer);
+ }
+ return true;
+}
+
+void CZipCentralDir::RemoveHeaders()
+{
+ for (int i = 0; i < m_headers.GetSize(); i++)
+ delete m_headers[i];
+ m_headers.RemoveAll();
+}
+
+void CZipCentralDir::ConvertAll()
+{
+ ASSERT(!m_bConvertAfterOpen);
+ for (int i = 0; i < m_headers.GetSize(); i++)
+ ConvertFileName(true, false, m_headers[i]);
+ m_bConvertAfterOpen = true;
+}
+
+
+void CZipCentralDir::BuildFindFastArray()
+{
+ m_findarray.RemoveAll();// just in case
+ for (int i = 0; i < m_headers.GetSize(); i++)
+ InsertFindFastElement(m_headers[i], (WORD)i);
+}
+
+void CZipCentralDir::InsertFindFastElement(CZipFileHeader* pHeader, WORD uIndex)
+{
+ CString fileName = pHeader->GetFileName();
+
+
+ int iSize = m_findarray.GetSize();
+
+ // Our initial binary search range encompasses the entire array of filenames:
+ int start = 0;
+ int end = iSize;
+
+ // Keep halving our search range until we find the right place
+ // to insert the new element:
+ while ( start < end )
+ {
+ // Find the midpoint of the search range:
+ int midpoint = ( start + end ) / 2;
+
+ // Compare the filename with the filename at the midpoint of the current search range:
+ int result = CompareElement(fileName, (WORD)midpoint, true);
+
+ // If our filename is larger, it must fall in the first half of the search range:
+ if ( result > 0 )
+ {
+ end = midpoint;
+ }
+
+ // If it's smaller, it must fall in the last half:
+ else if ( result < 0 )
+ {
+ start = midpoint + 1;
+ }
+
+ // If they're equal, we can go ahead and insert here:
+ else
+ {
+ start = midpoint; break;
+ }
+ }
+ m_findarray.InsertAt(start, CZipFindFast(pHeader, WORD(uIndex == -1 ? iSize : uIndex /* just in case */)));
+}
+
+int CZipCentralDir::FindFileNameIndex(LPCTSTR lpszFileName, bool bCaseSensitive)
+{
+ int start = 0;
+ int end = m_findarray.GetUpperBound();
+
+ // Keep halving our search range until we find the given element:
+ while ( start <= end )
+ {
+ // Find the midpoint of the search range:
+ int midpoint = ( start + end ) / 2;
+
+ // Compare the given filename with the filename at the midpoint of the search range:
+ int result = CompareElement(lpszFileName, (WORD)midpoint, bCaseSensitive);
+
+ // If our filename is smaller, it must fall in the first half of the search range:
+ if ( result > 0 )
+ {
+ end = midpoint - 1;
+ }
+
+ // If it's larger, it must fall in the last half:
+ else if ( result < 0 )
+ {
+ start = midpoint + 1;
+ }
+
+ // If they're equal, return the result:
+ else
+ {
+ return midpoint;
+ }
+ }
+
+ // Signal failure:
+ return -1;
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipCentralDir.h b/stepmania/src/smpackage/ZipArchive/ZipCentralDir.h
new file mode 100644
index 0000000000..25170ee5d0
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipCentralDir.h
@@ -0,0 +1,156 @@
+// ZipCentralDir.h: interface for the CZipCentralDir class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_ZipCentralDir_H__859029E8_8927_4717_9D4B_E26E5DA12BAE__INCLUDED_)
+#define AFX_ZipCentralDir_H__859029E8_8927_4717_9D4B_E26E5DA12BAE__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+#include "ZipException.h"
+#include
+#include "ZipFileHeader.h"
+#include "ZipAutoBuffer.h"
+
+/**
+ Used in fast finding files by the filename.
+ \see CZipCentralDir::m_findarray
+ \see CZipArchive::FindFile
+*/
+struct CZipFindFast
+{
+ CZipFindFast()
+ {
+ m_uIndex = 0;
+ m_pHeader= NULL;
+ }
+ CZipFindFast(CZipFileHeader* pHeader, WORD uIndex):m_pHeader(pHeader), m_uIndex(uIndex){}
+ /**
+ We extract a name from it.
+ */
+ CZipFileHeader* m_pHeader;
+
+ /**
+ The index in the central directory of the \e m_pHeader.
+ */
+ WORD m_uIndex;
+};
+
+
+class CZipCentralDir
+{
+
+public:
+
+// end of central dir signature 4 bytes (0x06054b50)
+ char m_szSignature[4];
+// number of this disk 2 bytes
+ WORD m_uThisDisk;
+// number of the disk with the
+// start of the central directory 2 bytes
+ WORD m_uDiskWithCD;
+// total number of entries in
+// the central dir on this disk 2 bytes
+ WORD m_uDiskEntriesNo;
+// total number of entries in
+// the central dir 2 bytes
+ WORD m_uEntriesNumber;
+// size of the central directory 4 bytes
+ DWORD m_uSize;
+// offset of start of central
+// directory with respect to
+// the starting disk number 4 bytes
+ DWORD m_uOffset;
+// zipfile comment length 2 bytes
+// WORD m_uCommentSize;
+// zipfile comment (variable size)
+ CZipAutoBuffer m_pszComment;
+ bool m_bFindFastEnabled;
+ CZipFileHeader* m_pOpenedFile;
+ void RemoveFile(WORD uIndex);
+ void Clear(bool bEverything = true);
+ CZipStorage* m_pStorage;
+ DWORD m_uCentrDirPos;
+ DWORD m_uBytesBeforeZip;
+ CZipCentralDir();
+ virtual ~CZipCentralDir();
+ void CloseFile();
+ void OpenFile(WORD uIndex);
+ bool IsValidIndex(WORD uIndex);
+ void Read();
+ void Init();
+ void CloseNewFile();
+ void Write();
+ int m_iBufferSize;
+ bool m_bOnDisk;
+ static char m_gszSignature[];
+ CTypedPtrArray m_headers;
+ CZipAutoBuffer m_pLocalExtraField;
+ void AddNewFile(CZipFileHeader & header);
+ void RemoveFromDisk();
+ DWORD GetSize(bool bWhole = false);
+ CArray m_findarray;
+ int FindFileNameIndex(LPCTSTR lpszFileName, bool bCaseSensitive);
+ void BuildFindFastArray();
+ /**
+ - If \c true, the conversion of the filenames takes
+ place after opening the archive (after reading the central directory
+ from the file), and before writing the central directory back to
+ the archive.
+ - If \c false, the conversion takes place on each call to CZipArchive::GetFileInfo
+
+ Set it to \c true when you plan to use CZipArchive::FindFile or get the stored files information.
+ Set it to \c false when you plan mostly to only modify the archive.
+
+ \b Default: \c true
+ \note Set it before opening the archive.
+ \see ConvertFileName
+ */
+ bool m_bConvertAfterOpen;
+
+/**
+ Convert the filename of the CZipFileHeader.
+ \param bFromZip
+ if \c true, convert from archive format
+ \param bAfterOpen
+ if \c true, called after opening the archive or before closing
+ \param pHeader
+ the header to have filename converted; if \c NULL convert the currently
+ opened file
+ \see m_bConvertAfterOpen
+*/
+ void ConvertFileName(bool bFromZip, bool bAfterOpen, CZipFileHeader* pHeader = NULL)
+ {
+ if (bAfterOpen != m_bConvertAfterOpen)
+ return;
+ if (!pHeader)
+ {
+ pHeader = m_pOpenedFile;
+ ASSERT(pHeader);
+ }
+ pHeader->AnsiOem(!bFromZip);
+ pHeader->SlashChange(bFromZip);
+ }
+ void ConvertAll();
+protected:
+ void InsertFindFastElement(CZipFileHeader* pHeader, WORD uIndex);
+ void RemoveHeaders();
+ bool RemoveDataDescr(bool bFromBuffer);
+ DWORD WriteCentralEnd();
+ void WriteHeaders();
+ void ReadHeaders();
+ void ThrowError(int err);
+ DWORD Locate();
+ int CompareElement(LPCTSTR lpszFileName, WORD uIndex, bool bCaseSensitive)
+ {
+ return bCaseSensitive ? m_findarray[uIndex].m_pHeader->GetFileName().Collate(lpszFileName)
+ : m_findarray[uIndex].m_pHeader->GetFileName().CollateNoCase(lpszFileName);
+ }
+
+};
+
+#endif // !defined(AFX_ZipCentralDir_H__859029E8_8927_4717_9D4B_E26E5DA12BAE__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipException.cpp b/stepmania/src/smpackage/ZipArchive/ZipException.cpp
new file mode 100644
index 0000000000..e9e43fe6a6
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipException.cpp
@@ -0,0 +1,78 @@
+// ZipException.cpp: implementation of the CZipException class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ZipException.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+IMPLEMENT_DYNAMIC( CZipException, CException)
+
+CZipException::CZipException(int iCause, LPCTSTR lpszZipName):CException(TRUE)
+{
+ m_iCause = iCause;
+
+ if (lpszZipName)
+ m_szFileName = lpszZipName;
+}
+
+CZipException::~CZipException()
+{
+
+}
+
+void AfxThrowZipException(int iZipError, LPCTSTR lpszZipName)
+{
+ throw new CZipException(CZipException::ZipErrToCause(iZipError), lpszZipName);
+}
+
+int CZipException::ZipErrToCause(int iZipError)
+{
+ switch (iZipError)
+ {
+ case 2://Z_NEED_DICT:
+ return CZipException::needDict;
+ case 1://Z_STREAM_END:
+ return CZipException::streamEnd;
+ case -1://Z_ERRNO:
+ return CZipException::errNo;
+ case -2://Z_STREAM_ERROR:
+ return CZipException::streamError;
+ case -3://Z_DATA_ERROR:
+ return CZipException::dataError;
+ case -4://Z_MEM_ERROR:
+ return CZipException::memError;
+ case -5://Z_BUF_ERROR:
+ return CZipException::bufError;
+ case -6://Z_VERSION_ERROR:
+ return CZipException::versionError;
+ case ZIP_BADZIPFILE:
+ return CZipException::badZipFile;
+ case ZIP_BADCRC:
+ return CZipException::badCrc;
+ case ZIP_ABORTED:
+ return CZipException::aborted;
+ case ZIP_NOCALLBACK:
+ return CZipException::noCallback;
+ case ZIP_NONREMOVABLE:
+ return CZipException::nonRemovable;
+ case ZIP_TOOMANYVOLUMES:
+ return CZipException::tooManyVolumes;
+ case ZIP_TOOLONGFILENAME:
+ return CZipException::tooLongFileName;
+ case ZIP_BADPASSWORD:
+ return CZipException::badPassword;
+ case ZIP_CDIR_NOTFOUND:
+ return CZipException::cdirNotFound;
+
+
+ default:
+ return CZipException::generic;
+ }
+
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipException.h b/stepmania/src/smpackage/ZipArchive/ZipException.h
new file mode 100644
index 0000000000..93640ca030
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipException.h
@@ -0,0 +1,71 @@
+// ZipException.h: interface for the CZipException class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_ZIPEXCEPTION_H__E3546921_D728_11D3_B7C7_E77339672847__INCLUDED_)
+#define AFX_ZIPEXCEPTION_H__E3546921_D728_11D3_B7C7_E77339672847__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+typedef unsigned short uShort;
+// errors number definitions
+#define ZIP_BADZIPFILE (-101)
+#define ZIP_BADCRC (-102)
+#define ZIP_NOCALLBACK (-103)
+#define ZIP_ABORTED (-104)
+#define ZIP_NONREMOVABLE (-105)
+#define ZIP_TOOMANYVOLUMES (-106)
+#define ZIP_TOOLONGFILENAME (-107)
+#define ZIP_BADPASSWORD (-108)
+#define ZIP_CDIR_NOTFOUND (-109)
+
+class CZipException : public CException
+{
+public:
+ DECLARE_DYNAMIC(CZipException)
+ // convert zlib library and internal error code to a ZipException code
+ static int ZipErrToCause(int iZipError);
+ // name of the zip file where the error occured
+ CString m_szFileName;
+
+ enum
+ {
+ noError, // no error
+ generic, // unknown error
+ streamEnd, // zlib library errors
+ needDict, //
+ errNo, //
+ streamError, //
+ dataError, //
+ memError, //
+ bufError, //
+ versionError, //
+ badZipFile, // damaged or not a zip file
+ badCrc, // crc mismatched
+ noCallback, // no callback function set
+ aborted, // disk change callback function returned false
+ nonRemovable, // the disk selected for pkSpan archive is non removable
+ tooManyVolumes, // limit of the maximum volumes reached (999)
+ tooLongFileName, // the file name of the file added to the archive is too long
+ badPassword, // incorrect password set for the file being decrypted
+ cdirNotFound, ///< the central directory was not found in the archive
+ dirWithSize // during testing: found the directory with the size greater than 0
+ };
+ // cause - takes one of the codes above
+ int m_iCause;
+ CZipException(int iCause = generic, LPCTSTR lpszZipName = NULL);
+ virtual ~CZipException();
+
+};
+
+// throw zip exception
+// Parameters:
+// iZipError - zlib or internal error code
+// lpszZipName - name of the file where the error occured
+void AfxThrowZipException(int iZipError = 1000, LPCTSTR lpszZipName = NULL);
+
+#endif // !defined(AFX_ZIPEXCEPTION_H__E3546921_D728_11D3_B7C7_E77339672847__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipFileHeader.cpp b/stepmania/src/smpackage/ZipArchive/ZipFileHeader.cpp
new file mode 100644
index 0000000000..5487e02d44
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipFileHeader.cpp
@@ -0,0 +1,329 @@
+// ZipFileHeader.cpp: implementation of the CZipFileHeader class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ZipFileHeader.h"
+#include "zlib.h"
+#include "ZipAutoBuffer.h"
+#include "ZipArchive.h"
+
+#define ZipFileHeaderSIZE 46
+#define LOCALZipFileHeaderSIZE 30
+#define VERSIONMADEBY 20
+#define ENCR_HEADER_LEN 12
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+char CZipFileHeader::m_gszSignature[] = {0x50, 0x4b, 0x01, 0x02};
+char CZipFileHeader::m_gszLocalSignature[] = {0x50, 0x4b, 0x03, 0x04};
+CZipFileHeader::CZipFileHeader()
+{
+ m_uExternalAttr = FILE_ATTRIBUTE_ARCHIVE;
+ m_uModDate = m_uModTime = m_uInternalAttr = 0;
+ m_uMethod = Z_DEFLATED;
+}
+
+CZipFileHeader::~CZipFileHeader()
+{
+
+}
+
+// read the header from the central dir
+bool CZipFileHeader::Read(CZipStorage *pStorage)
+{
+// // just in case
+// m_pszComment.Release();
+// m_pszFileName.Release();
+ WORD uFileNameSize, uCommentSize, uExtraFieldSize;
+ CZipAutoBuffer buf(ZipFileHeaderSIZE);
+ pStorage->Read(buf, ZipFileHeaderSIZE, true);
+ memcpy(&m_szSignature, buf, 4);
+ memcpy(&m_uVersionMadeBy, buf + 4, 2);
+ memcpy(&m_uVersionNeeded, buf + 6, 2);
+ memcpy(&m_uFlag, buf + 8, 2);
+ memcpy(&m_uMethod, buf + 10, 2);
+ memcpy(&m_uModTime, buf + 12, 2);
+ memcpy(&m_uModDate, buf + 14, 2);
+ memcpy(&m_uCrc32, buf + 16, 4);
+ memcpy(&m_uComprSize, buf + 20, 4);
+ memcpy(&m_uUncomprSize, buf + 24, 4);
+ memcpy(&uFileNameSize, buf + 28, 2);
+ memcpy(&uExtraFieldSize, buf + 30, 2);
+ memcpy(&uCommentSize, buf + 32, 2);
+ memcpy(&m_uDiskStart, buf + 34, 2);
+ memcpy(&m_uInternalAttr, buf + 36, 2);
+ memcpy(&m_uExternalAttr, buf + 38, 4);
+ memcpy(&m_uOffset, buf + 42, 4);
+ buf.Release();
+
+ if (memcmp(m_szSignature, m_gszSignature, 4) != 0)
+ return false;
+
+ int iCurDsk = pStorage->GetCurrentDisk();
+ m_pszFileName.Allocate(uFileNameSize); // don't add NULL at the end
+ pStorage->m_pFile->Read(m_pszFileName, uFileNameSize);
+ if (uExtraFieldSize)
+ {
+ ASSERT(!m_pExtraField.IsAllocated());
+ m_pExtraField.Allocate(uExtraFieldSize);
+ pStorage->m_pFile->Read(m_pExtraField, uExtraFieldSize);
+ }
+ if (uCommentSize)
+ {
+ m_pszComment.Allocate(uCommentSize);
+ pStorage->m_pFile->Read(m_pszComment, uCommentSize);
+ }
+
+ return pStorage->GetCurrentDisk() == iCurDsk; // check that the while header is on the one disk
+}
+
+// return CTime representation of m_uModDate, m_uModTime
+CTime CZipFileHeader::GetTime()
+{
+ return CTime(m_uModDate, m_uModTime);
+}
+
+// write the header to the central dir
+DWORD CZipFileHeader::Write(CZipStorage *pStorage)
+{
+ WORD uFileNameSize = GetFileNameSize(), uCommentSize = GetCommentSize(),
+ uExtraFieldSize = GetExtraFieldSize();
+ DWORD iSize = GetSize();
+ CZipAutoBuffer buf(iSize);
+ memcpy(buf, &m_szSignature, 4);
+ memcpy(buf + 4, &m_uVersionMadeBy, 2);
+ memcpy(buf + 6, &m_uVersionNeeded, 2);
+ memcpy(buf + 8, &m_uFlag, 2);
+ memcpy(buf + 10, &m_uMethod, 2);
+ memcpy(buf + 12, &m_uModTime, 2);
+ memcpy(buf + 14, &m_uModDate, 2);
+ memcpy(buf + 16, &m_uCrc32, 4);
+ memcpy(buf + 20, &m_uComprSize, 4);
+ memcpy(buf + 24, &m_uUncomprSize, 4);
+ memcpy(buf + 28, &uFileNameSize, 2);
+ memcpy(buf + 30, &uExtraFieldSize, 2);
+ memcpy(buf + 32, &uCommentSize, 2);
+ memcpy(buf + 34, &m_uDiskStart, 2);
+ memcpy(buf + 36, &m_uInternalAttr, 2);
+ memcpy(buf + 38, &m_uExternalAttr, 4);
+ memcpy(buf + 42, &m_uOffset, 4);
+
+ memcpy(buf + 46, m_pszFileName, uFileNameSize);
+
+ if (uExtraFieldSize)
+ memcpy(buf + 46 + uFileNameSize, m_pExtraField, uExtraFieldSize);
+
+ if (uCommentSize)
+ memcpy(buf + 46 + uFileNameSize + uExtraFieldSize, m_pszComment, uCommentSize);
+
+ pStorage->Write(buf, iSize, true);
+ return iSize;
+}
+
+// read local header
+bool CZipFileHeader::ReadLocal(CZipStorage *pStorage, WORD& iLocExtrFieldSize)
+{
+ char buf[LOCALZipFileHeaderSIZE];
+ pStorage->Read(buf, LOCALZipFileHeaderSIZE, true);
+ if (memcmp(buf, m_gszLocalSignature, 4) != 0)
+ return false;
+
+ bool bIsDataDescr = (((WORD)*(buf + 6)) & 8) != 0;
+
+ WORD uFileNameSize = GetFileNameSize();
+ if ((memcmp(buf + 6, &m_uFlag, 2) != 0)
+ ||(memcmp(buf + 8, &m_uMethod, 2) != 0)
+ || (m_uMethod && (m_uMethod != Z_DEFLATED))
+ || (memcmp(buf + 26, &uFileNameSize, 2) != 0))
+ return false;
+
+// jeszcze mo¿naby porównaæ nazwy plików
+
+ if (!bIsDataDescr/* || !pStorage->IsSpanMode()*/)
+ if (!CheckCrcAndSizes(buf + 14))
+ return false;
+
+ memcpy(&iLocExtrFieldSize, buf + 28, 2);
+ pStorage->m_pFile->Seek(uFileNameSize, CFile::current);
+
+ return true;
+}
+
+// set the m_uModDate, m_uModTime values using CTime object
+void CZipFileHeader::SetTime(const CTime &time)
+{
+ WORD year = (WORD)time.GetYear();
+ if (year <= 1980)
+ year = 0;
+ else
+ year -= 1980;
+ m_uModDate = (WORD) (time.GetDay() + (time.GetMonth() << 5) + (year << 9));
+ m_uModTime = (WORD) ((time.GetSecond() >> 1) + (time.GetMinute() << 5) +
+ (time.GetHour() << 11));
+}
+// the buffer contains crc32, compressed and uncompressed sizes to be compared
+// with the actual values
+bool CZipFileHeader::CheckCrcAndSizes(char *pBuf)
+{
+ return (memcmp(pBuf, &m_uCrc32, 4) == 0) && (memcmp(pBuf + 4, &m_uComprSize, 4) == 0)
+ && (memcmp(pBuf + 8, &m_uUncomprSize, 4) == 0);
+}
+
+// write the local header
+void CZipFileHeader::WriteLocal(CZipStorage& storage)
+{
+ // extra field is local by now
+ WORD uFileNameSize = GetFileNameSize(), uExtraFieldSize = GetExtraFieldSize();
+ DWORD iLocalSize = LOCALZipFileHeaderSIZE + uExtraFieldSize + uFileNameSize;
+ CZipAutoBuffer buf(iLocalSize);
+ memcpy(buf, m_gszLocalSignature, 4);
+ memcpy(buf + 4, &m_uVersionNeeded, 2);
+ memcpy(buf + 6, &m_uFlag, 2);
+ memcpy(buf + 8, &m_uMethod, 2);
+ memcpy(buf + 10, &m_uModTime, 2);
+ memcpy(buf + 12, &m_uModDate, 2);
+ memcpy(buf + 14, &m_uCrc32, 4);
+ memcpy(buf + 18, &m_uComprSize, 4);
+ memcpy(buf + 22, &m_uUncomprSize, 4);
+ memcpy(buf + 26, &uFileNameSize, 2);
+ memcpy(buf + 28, &uExtraFieldSize, 2);
+ memcpy(buf + 30, m_pszFileName, uFileNameSize);
+ memcpy(buf + 30 + uFileNameSize, m_pExtraField, uExtraFieldSize);
+
+ // possible disk change before writting to the file in the disk spanning mode
+ // so write the local header first
+ storage.Write(buf, iLocalSize, true);
+ // it was only local information, use CZipArchive::SetExtraField to set the file extra field in the central directory
+ m_pExtraField.Release();
+
+ m_uDiskStart = (WORD)storage.GetCurrentDisk();
+ m_uOffset = storage.GetPosition() - iLocalSize;
+}
+
+// prepare the data before adding a new file
+bool CZipFileHeader::PrepareData(int iLevel, bool bExtraHeader, bool bEncrypted)
+{
+ memcpy(m_szSignature, m_gszSignature, 4);
+ m_uInternalAttr = 0;
+ m_uVersionMadeBy = VERSIONMADEBY;
+ m_uVersionNeeded = 20;
+
+ m_uCrc32 = 0;
+ m_uComprSize = 0;
+ m_uUncomprSize = 0;
+ if (iLevel == 0)
+ m_uMethod = 0;
+
+ if ((m_uMethod != Z_DEFLATED) && (m_uMethod != 0))
+ m_uMethod = Z_DEFLATED;
+
+ m_uFlag = 0;
+ if (m_uMethod == Z_DEFLATED)
+ switch (iLevel)
+ {
+ case 1:
+ m_uFlag |= 6;
+ break;
+ case 2:
+ m_uFlag |= 4;
+ break;
+ case 8:
+ case 9:
+ m_uFlag |= 2;
+ break;
+ }
+
+ if (bExtraHeader)
+ m_uFlag |= 8; // data descriptor present
+
+ if (bEncrypted)
+ {
+ m_uComprSize = ENCR_HEADER_LEN; // encrypted header
+ m_uFlag |= 9; // encrypted file
+ }
+
+ return !(m_pszComment.GetSize() > USHRT_MAX || m_pszFileName.GetSize() > USHRT_MAX
+ || m_pExtraField.GetSize() > USHRT_MAX);
+}
+
+// fill the buffer with the current values
+void CZipFileHeader::GetCrcAndSizes(char * pBuffer)
+{
+ memcpy(pBuffer, &m_uCrc32, 4);
+ memcpy(pBuffer + 4, &m_uComprSize, 4);
+ memcpy(pBuffer + 8, &m_uUncomprSize, 4);
+}
+
+DWORD CZipFileHeader::GetSize()
+{
+ return ZipFileHeaderSIZE + GetExtraFieldSize() + GetFileNameSize() + GetCommentSize();
+}
+
+
+bool CZipFileHeader::IsEncrypted()
+{
+ return (m_uFlag & (WORD) 1) != 0;
+}
+
+bool CZipFileHeader::IsDataDescr()
+{
+ return (m_uFlag & (WORD) 8) != 0;
+}
+
+bool CZipFileHeader::SetComment(LPCTSTR lpszComment)
+{
+ return CZipArchive::WideToSingle(lpszComment, m_pszComment) != -1;
+}
+
+CString CZipFileHeader::GetComment()
+{
+ CString temp;
+ CZipArchive::SingleToWide(m_pszComment, temp);
+ return temp;
+
+}
+
+bool CZipFileHeader::SetFileName(LPCTSTR lpszFileName)
+{
+ return CZipArchive::WideToSingle(lpszFileName, m_pszFileName) != -1;
+}
+
+CString CZipFileHeader::GetFileName()
+{
+ CString temp;
+ CZipArchive::SingleToWide(m_pszFileName, temp);
+ return temp;
+}
+
+
+void CZipFileHeader::SlashChange(bool bWindowsStyle)
+{
+ char t1 = '\\', t2 = '/', c1, c2;
+ if (bWindowsStyle)
+ {
+ c1 = t1;
+ c2 = t2;
+ }
+ else
+ {
+ c1 = t2;
+ c2 = t1;
+ }
+ for (DWORD i = 0; i < m_pszFileName.GetSize(); i++)
+ {
+ if (m_pszFileName[i] == c2)
+ m_pszFileName[i] = c1;
+ }
+}
+
+void CZipFileHeader::AnsiOem(bool bAnsiToOem)
+{
+ if (bAnsiToOem)
+ CharToOemBuffA(m_pszFileName, m_pszFileName, m_pszFileName.GetSize());
+ else
+ OemToCharBuffA(m_pszFileName, m_pszFileName, m_pszFileName.GetSize());
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipFileHeader.h b/stepmania/src/smpackage/ZipArchive/ZipFileHeader.h
new file mode 100644
index 0000000000..b582345c38
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipFileHeader.h
@@ -0,0 +1,106 @@
+// ZipFileHeader.h: interface for the CZipFileHeader class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_ZipFileHeader_H__0081FC65_C9C9_4D48_AF72_DBF37DF5E0CF__INCLUDED_)
+#define AFX_ZipFileHeader_H__0081FC65_C9C9_4D48_AF72_DBF37DF5E0CF__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "ZipException.h"
+#include "ZipStorage.h"
+#include "ZipAutoBuffer.h"
+
+class CZipFileHeader
+{
+public:
+// convert characters in the filename from oem to ansi or vice-versa
+ void AnsiOem(bool bAnsiToOem);
+// change slash to backslash or vice-versa
+ void SlashChange(bool bWindowsStyle);
+// return the filename size in characters (without NULL);
+ WORD GetFileNameSize(){return (WORD)m_pszFileName.GetSize();}
+// return the comment size in characters (without NULL);
+ WORD GetCommentSize(){return (WORD)m_pszComment.GetSize();}
+// return the extra field size in characters (without NULL);
+ WORD GetExtraFieldSize(){return (WORD)m_pExtraField.GetSize();}
+
+ CString GetFileName();
+// return true if confersion from unicode to single byte was successful
+ bool SetFileName(LPCTSTR lpszFileName);
+ CString GetComment();
+// return true if confersion from unicode to single byte was successful
+ bool SetComment(LPCTSTR lpszComment);
+// return true if the data descriptor is present
+ bool IsDataDescr();
+// return true if the file is encrypted
+ bool IsEncrypted();
+// central file header signature 4 bytes (0x02014b50)
+ char m_szSignature[4];
+// version made by 2 bytes
+ WORD m_uVersionMadeBy;
+// version needed to extract 2 bytes
+ WORD m_uVersionNeeded;
+// general purpose bit flag 2 bytes
+ WORD m_uFlag;
+// compression method 2 bytes
+ WORD m_uMethod;
+// last mod file time 2 bytes
+ WORD m_uModTime;
+// last mod file date 2 bytes
+ WORD m_uModDate;
+// crc-32 4 bytes
+ DWORD m_uCrc32;
+// compressed size 4 bytes
+ DWORD m_uComprSize;
+// uncompressed size 4 bytes
+ DWORD m_uUncomprSize;
+// filename length 2 bytes
+// WORD m_uFileNameSize;
+// extra field length 2 bytes
+// WORD m_uExtraFieldSize;
+// file comment length 2 bytes
+// WORD m_uCommentSize;
+// disk number start 2 bytes
+ WORD m_uDiskStart;
+// internal file attributes 2 bytes
+ WORD m_uInternalAttr;
+// external file attributes 4 bytes
+ DWORD m_uExternalAttr;
+// relative offset of local header 4 bytes
+ DWORD m_uOffset;
+// extra field (variable size)
+ CZipAutoBuffer m_pExtraField;
+
+ CZipFileHeader();
+ virtual ~CZipFileHeader();
+ CTime GetTime();
+ void SetTime(const CTime& time);
+ static char m_gszSignature[];
+ static char m_gszLocalSignature[];
+// return the total size of the structure as stored in the central directory
+ DWORD GetSize();
+protected:
+// filename (variable size)
+ CZipAutoBuffer m_pszFileName;
+// file comment (variable size)
+ CZipAutoBuffer m_pszComment;
+
+ void GetCrcAndSizes(char * pBuffer);
+ bool PrepareData(int iLevel, bool bExtraHeader, bool bEncrypted);
+ void WriteLocal(CZipStorage& storage);
+ bool CheckCrcAndSizes(char* pBuf);
+ friend class CZipCentralDir;
+ friend class CZipArchive;
+ bool Read(CZipStorage *pStorage);
+ bool ReadLocal(CZipStorage *pStorage, WORD& iLocExtrFieldSize);
+ DWORD Write(CZipStorage *pStorage);
+
+};
+
+#endif // !defined(AFX_ZipFileHeader_H__0081FC65_C9C9_4D48_AF72_DBF37DF5E0CF__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipInternalInfo.cpp b/stepmania/src/smpackage/ZipArchive/ZipInternalInfo.cpp
new file mode 100644
index 0000000000..653310dce0
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipInternalInfo.cpp
@@ -0,0 +1,28 @@
+// ZipInternalInfo.cpp: implementation of the CZipInternalInfo class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ZipInternalInfo.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CZipInternalInfo::CZipInternalInfo()
+{
+ m_iBufferSize = 16384;
+}
+
+CZipInternalInfo::~CZipInternalInfo()
+{
+
+}
+
+void CZipInternalInfo::Init()
+{
+ m_pBuffer.Allocate(m_iBufferSize);
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipInternalInfo.h b/stepmania/src/smpackage/ZipArchive/ZipInternalInfo.h
new file mode 100644
index 0000000000..86792fc989
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipInternalInfo.h
@@ -0,0 +1,32 @@
+// ZipInternalInfo.h: interface for the CZipInternalInfo class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_ZIPINTERNALINFO_H__C6749101_590C_4F74_8121_B82E3BE9FA44__INCLUDED_)
+#define AFX_ZIPINTERNALINFO_H__C6749101_590C_4F74_8121_B82E3BE9FA44__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+#include "ZipAutoBuffer.h"
+#include "zlib.h"
+
+class CZipInternalInfo
+{
+public:
+ DWORD m_iBufferSize;
+ z_stream m_stream;
+ DWORD m_uUncomprLeft;
+ DWORD m_uComprLeft;
+ DWORD m_uCrc32;
+ void Init();
+ CZipAutoBuffer m_pBuffer;
+ CZipInternalInfo();
+ virtual ~CZipInternalInfo();
+
+};
+
+#endif // !defined(AFX_ZIPINTERNALINFO_H__C6749101_590C_4F74_8121_B82E3BE9FA44__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/ZipStorage.cpp b/stepmania/src/smpackage/ZipArchive/ZipStorage.cpp
new file mode 100644
index 0000000000..0a295d8612
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipStorage.cpp
@@ -0,0 +1,428 @@
+// ZipStorage.cpp: implementation of the CZipStorage class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "ZipStorage.h"
+#include "ZipArchive.h"
+
+//////////////////////////////////////////////////////////////////////
+// disk spanning objectives:
+// - sinature at the first disk at the beginning
+// - headers and central dir records not divided between disks
+// - each file has a data descriptor preceded by the signature
+// (bit 3 set in flag);
+
+
+char CZipStorage::m_gszExtHeaderSignat[] = {0x50, 0x4b, 0x07, 0x08};
+CZipStorage::CZipStorage()
+{
+ m_pCallbackData = m_pZIPCALLBACKFUN = NULL;
+ m_iWriteBufferSize = 65535;
+ m_iCurrentDisk = -1;
+ m_pFile = NULL;
+}
+
+CZipStorage::~CZipStorage()
+{
+
+}
+
+DWORD CZipStorage::Read(void *pBuf, DWORD iSize, bool bAtOnce)
+{
+ if (iSize == 0)
+ return 0;
+ DWORD iRead = 0;
+ while (!iRead)
+ {
+ iRead = m_pFile->Read(pBuf, iSize);
+ if (!iRead)
+ if (IsSpanMode())
+ ChangeDisk(m_iCurrentDisk + 1);
+ else
+ ThrowError(ZIP_BADZIPFILE);
+ }
+
+ if (iRead == iSize)
+ return iRead;
+ else if (bAtOnce || !IsSpanMode())
+ ThrowError(ZIP_BADZIPFILE);
+
+ while (iRead < iSize)
+ {
+ ChangeDisk(m_iCurrentDisk + 1);
+ UINT iNewRead = m_pFile->Read((char*)pBuf + iRead, iSize - iRead);
+ if (!iNewRead && iRead < iSize)
+ ThrowError(ZIP_BADZIPFILE);
+ iRead += iNewRead;
+ }
+
+ return iRead;
+}
+
+void CZipStorage::Open(LPCTSTR szPathName, int iMode, int iVolumeSize)
+{
+ m_pWriteBuffer.Allocate(m_iWriteBufferSize);
+ m_uBytesInWriteBuffer = 0;
+ m_bNewSpan = false;
+ m_pFile = &m_internalfile;
+
+ if ((iMode == CZipArchive::create) ||(iMode == CZipArchive::createSpan)) // create new archive
+ {
+ m_iCurrentDisk = 0;
+ if (iMode == CZipArchive::create)
+ {
+ m_iSpanMode = noSpan;
+ OpenFile(szPathName, CFile::modeCreate | CFile::modeReadWrite);
+ }
+ else // create disk spanning archive
+ {
+ m_bNewSpan = true;
+ m_iBytesWritten = 0;
+ if (iVolumeSize <= 0) // pkzip span
+ {
+ if (!m_pZIPCALLBACKFUN)
+ ThrowError(ZIP_NOCALLBACK);
+ if (!CZipArchive::IsDriveRemovable(szPathName))
+ ThrowError(ZIP_NONREMOVABLE);
+ m_iSpanMode = pkzipSpan;
+ }
+ else
+ {
+ m_iTdSpanData = iVolumeSize;
+ m_iSpanMode = tdSpan;
+ }
+
+ NextDisk(4, szPathName);
+ Write(m_gszExtHeaderSignat, 4, true);
+ }
+ }
+ else // open existing
+ {
+ OpenFile(szPathName, CFile::modeNoTruncate | ((iMode == CZipArchive::openReadOnly) ? CFile::modeRead : CFile::modeReadWrite));
+ // m_uData, m_bAllowModif i m_iSpanMode ustalane automatycznie podczas odczytu central dir
+ m_iSpanMode = iVolumeSize == 0 ? suggestedAuto : suggestedTd;
+ }
+
+}
+
+
+void CZipStorage::Open(CMemFile& mf, int iMode)
+{
+ m_pWriteBuffer.Allocate(m_iWriteBufferSize);
+ m_uBytesInWriteBuffer = 0;
+ m_bNewSpan = false;
+ m_pFile = &mf;
+
+ if (iMode == CZipArchive::create)
+ {
+ m_iCurrentDisk = 0;
+ m_iSpanMode = noSpan;
+ mf.SetLength(0);
+ }
+ else // open existing
+ {
+ mf.SeekToBegin();
+ m_iSpanMode = suggestedAuto;
+ }
+}
+
+
+int CZipStorage::IsSpanMode()
+{
+ return m_iSpanMode == noSpan ? 0 : (m_bNewSpan ? 1 : -1);
+}
+
+void CZipStorage::ChangeDisk(int iNumber)
+{
+ if (iNumber == m_iCurrentDisk)
+ return;
+
+ ASSERT(m_iSpanMode != noSpan);
+ m_iCurrentDisk = iNumber;
+ OpenFile(m_iSpanMode == pkzipSpan ? ChangePkzipRead() : ChangeTdRead(),
+ CFile::modeNoTruncate | CFile::modeRead);
+}
+
+void CZipStorage::ThrowError(int err)
+{
+ AfxThrowZipException(err, m_pFile->GetFilePath());
+}
+
+bool CZipStorage::OpenFile(LPCTSTR lpszName, UINT uFlags, bool bThrow)
+{
+ CFileException* e = new CFileException;
+ BOOL bRet = m_pFile->Open(lpszName, uFlags | CFile::shareDenyWrite, e);
+ if (!bRet && bThrow)
+ throw e;
+ e->Delete();
+ return bRet != 0;
+}
+
+// zapobiega konstrukcji ChangeDisk(++m_iCurrentDisk)
+void CZipStorage::SetCurrentDisk(int iNumber)
+{
+ m_iCurrentDisk = iNumber;
+}
+
+int CZipStorage::GetCurrentDisk()
+{
+ return m_iCurrentDisk;
+}
+
+CString CZipStorage::ChangePkzipRead()
+{
+ CString szTemp = m_pFile->GetFilePath();
+ m_pFile->Close();
+ CallCallback(-1 , szTemp);
+ return szTemp;
+}
+
+CString CZipStorage::ChangeTdRead()
+{
+ CString szTemp = GetTdVolumeName(m_iCurrentDisk == m_iTdSpanData);
+ m_pFile->Close();
+ return szTemp;
+}
+
+void CZipStorage::Close(bool bAfterException)
+{
+ if (!bAfterException)
+ {
+ Flush();
+ if ((m_iSpanMode == tdSpan) && (m_bNewSpan))
+ {
+ // give to the last volume the zip extension
+ CString szFileName = m_pFile->GetFilePath();
+ CString szNewFileName = GetTdVolumeName(true);
+ m_pFile->Close();
+ if (CZipArchive::FileExists(szNewFileName))
+ CFile::Remove(szNewFileName);
+ CFile::Rename(szFileName, szNewFileName);
+ }
+ else
+#ifdef _DEBUG // to prevent assertion if the file is already closed
+ if (m_pFile->m_hFile != (UINT)CFile::hFileNull)
+#endif
+ m_pFile->Close();
+ }
+ else
+#ifdef _DEBUG // to prevent assertion if the file is already closed
+ if (m_pFile->m_hFile != (UINT)CFile::hFileNull)
+#endif
+ m_pFile->Close();
+
+
+ m_pWriteBuffer.Release();
+ m_iCurrentDisk = -1;
+ m_iSpanMode = noSpan;
+ m_pFile = NULL;
+}
+
+CString CZipStorage::GetTdVolumeName(bool bLast, LPCTSTR lpszZipName)
+{
+ CString szFilePath = lpszZipName ? lpszZipName : m_pFile->GetFilePath();
+ CString szPath = CZipArchive::GetFilePath(szFilePath);
+ CString szName = CZipArchive::GetFileTitle(szFilePath);
+ CString szExt;
+ if (bLast)
+ szExt = _T("zip");
+ else
+ szExt.Format(_T("%.3d"), m_iCurrentDisk);
+ return szPath + szName + _T(".") + szExt;
+}
+
+void CZipStorage::NextDisk(int iNeeded, LPCTSTR lpszFileName)
+{
+ Flush();
+ ASSERT(m_iSpanMode != noSpan);
+ if (m_iBytesWritten)
+ {
+ m_iBytesWritten = 0;
+ m_iCurrentDisk++;
+ if (m_iCurrentDisk >= 999)
+ ThrowError(ZIP_TOOMANYVOLUMES);
+ }
+ CString szFileName;
+ bool bPkSpan = (m_iSpanMode == pkzipSpan);
+ if (bPkSpan)
+ szFileName = lpszFileName ? lpszFileName : m_pFile->GetFilePath();
+ else
+ szFileName = GetTdVolumeName(false, lpszFileName);
+
+#ifdef _DEBUG // to prevent assertion if the file is already closed
+ if (m_pFile->m_hFile != (UINT)CFile::hFileNull)
+#endif
+ m_pFile->Close(); // if it is closed, so it will not close
+
+ if (bPkSpan)
+ {
+ int iCode = iNeeded;
+ while (true)
+ {
+ CallCallback(iCode, szFileName);
+ if (CZipArchive::FileExists(szFileName))
+ iCode = -2;
+ else
+ {
+ CString label;
+ label.Format(_T("pkback# %.3d"), m_iCurrentDisk + 1);
+ if (!SetVolumeLabel(CZipArchive::GetDrive(szFileName), label)) /*not write label*/
+ iCode = -3;
+ else if (!OpenFile(szFileName, CFile::modeCreate | CFile::modeReadWrite, false))
+ iCode = -4;
+ else
+ break;
+ }
+
+ }
+ m_uCurrentVolSize = GetFreeVolumeSpace();
+ }
+ else
+ {
+ m_uCurrentVolSize = m_iTdSpanData;
+ OpenFile(szFileName, CFile::modeCreate | CFile::modeReadWrite);
+ }
+}
+
+void CZipStorage::CallCallback(int iCode, CString szTemp)
+{
+ ASSERT(m_pZIPCALLBACKFUN);
+ if (!(*m_pZIPCALLBACKFUN)(m_iCurrentDisk + 1, iCode, m_pCallbackData))
+ throw new CZipException(CZipException::aborted, szTemp);
+}
+
+DWORD CZipStorage::GetFreeVolumeSpace()
+{
+ ASSERT (m_iSpanMode == pkzipSpan);
+ DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
+ if (!GetDiskFreeSpace(
+ CZipArchive::GetDrive(m_pFile->GetFilePath()),
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &NumberOfFreeClusters,
+ &TotalNumberOfClusters))
+ return 0;
+ _int64 total = SectorsPerCluster * BytesPerSector * NumberOfFreeClusters;
+ return (DWORD)total;
+}
+
+
+void CZipStorage::UpdateSpanMode(WORD uLastDisk)
+{
+ m_iCurrentDisk = uLastDisk;
+ if (uLastDisk)
+ {
+ // disk spanning detected
+
+ if (m_iSpanMode == suggestedAuto)
+ m_iSpanMode = CZipArchive::IsDriveRemovable(m_pFile->GetFilePath()) ?
+ pkzipSpan : tdSpan;
+ else
+ m_iSpanMode = tdSpan;
+
+ if (m_iSpanMode == pkzipSpan)
+ {
+ if (!m_pZIPCALLBACKFUN)
+ ThrowError(ZIP_NOCALLBACK);
+ }
+ else /*if (m_iSpanMode == tdSpan)*/
+ m_iTdSpanData = uLastDisk; // disk with .zip extension ( the last one)
+
+ m_pWriteBuffer.Release(); // no need for this in this case
+ }
+ else
+ m_iSpanMode = noSpan;
+
+}
+
+void CZipStorage::Write(void *pBuf, DWORD iSize, bool bAtOnce)
+{
+ if (!IsSpanMode())
+ WriteInternalBuffer((char*)pBuf, iSize);
+ else
+ {
+ // if not at once, one byte is enough free space
+ DWORD iNeeded = bAtOnce ? iSize : 1;
+ DWORD uTotal = 0;
+
+ while (uTotal < iSize)
+ {
+ DWORD uFree;
+ while ((uFree = VolumeLeft()) < iNeeded)
+ {
+ if ((m_iSpanMode == tdSpan) && !m_iBytesWritten && !m_uBytesInWriteBuffer)
+ // in the tdSpan mode, if the size of the archive is less
+ // than the size of the packet to be written at once,
+ // increase once the size of the volume
+ m_uCurrentVolSize = iNeeded;
+ else
+ NextDisk(iNeeded);
+ }
+
+ DWORD uLeftToWrite = iSize - uTotal;
+ DWORD uToWrite = uFree < uLeftToWrite ? uFree : uLeftToWrite;
+ WriteInternalBuffer((char*)pBuf + uTotal, uToWrite);
+ if (bAtOnce)
+ return;
+ else
+ uTotal += uToWrite;
+ }
+
+ }
+}
+
+
+void CZipStorage::WriteInternalBuffer(char *pBuf, DWORD uSize)
+{
+ DWORD uWritten = 0;
+ while (uWritten < uSize)
+ {
+ DWORD uFreeInBuffer = GetFreeInBuffer();
+ if (uFreeInBuffer == 0)
+ {
+ Flush();
+ uFreeInBuffer = m_pWriteBuffer.GetSize();
+ }
+ DWORD uLeftToWrite = uSize - uWritten;
+ DWORD uToCopy = uLeftToWrite < uFreeInBuffer ? uLeftToWrite : uFreeInBuffer;
+ memcpy(m_pWriteBuffer + m_uBytesInWriteBuffer, pBuf + uWritten, uToCopy);
+ uWritten += uToCopy;
+ m_uBytesInWriteBuffer += uToCopy;
+ }
+}
+
+DWORD CZipStorage::VolumeLeft()
+{
+ // for pkzip span m_uCurrentVolSize is updated after each flush()
+ return m_uCurrentVolSize - m_uBytesInWriteBuffer - ((m_iSpanMode == pkzipSpan) ? 0 : m_iBytesWritten);
+}
+
+void CZipStorage::Flush()
+{
+ m_iBytesWritten += m_uBytesInWriteBuffer;
+ if (m_uBytesInWriteBuffer)
+ {
+ m_pFile->Write(m_pWriteBuffer, m_uBytesInWriteBuffer);
+ m_uBytesInWriteBuffer = 0;
+ }
+ if (m_iSpanMode == pkzipSpan)
+ // after writting it is difficult to predict the free space due to
+ // not completly written clusters, write operation may start from
+ // the new cluster
+ m_uCurrentVolSize = GetFreeVolumeSpace();
+}
+
+DWORD CZipStorage::GetPosition()
+{
+ return m_pFile->GetPosition() + m_uBytesInWriteBuffer;
+}
+
+
+DWORD CZipStorage::GetFreeInBuffer()
+{
+ return m_pWriteBuffer.GetSize() - m_uBytesInWriteBuffer;
+}
diff --git a/stepmania/src/smpackage/ZipArchive/ZipStorage.h b/stepmania/src/smpackage/ZipArchive/ZipStorage.h
new file mode 100644
index 0000000000..9d203ae32e
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/ZipStorage.h
@@ -0,0 +1,134 @@
+// ZipStorage.h: interface for the CZipStorage class.
+//
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2000 Tadeusz Dracz.
+// For conditions of distribution and use, see copyright notice in ZipArchive.h
+////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_ZIPSTORAGE_H__941824FE_3320_4794_BDE3_BE334ED8984B__INCLUDED_)
+#define AFX_ZIPSTORAGE_H__941824FE_3320_4794_BDE3_BE334ED8984B__INCLUDED_
+
+#include "ZipBigFile.h" // Added by ClassView
+#include "ZipAutoBuffer.h" // Added by ClassView
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+// callback function called when there is a need for a disk change
+// calling CZipArchive functions, apart from the static ones, may have unexpected results
+// iNumber - disk number needed
+// iCode :
+// -1 - disk needed for reading
+// other codes occurs during writting
+// >=0 : number of bytes needed
+// -2 - the file with the archive name already exists on the disk
+// -3 - the disk is probably write - protected
+// -4 - couldn't create a file
+// pData - user defined data
+// return false to abort operation: the proper exception will be thrown
+typedef bool (*ZIPCALLBACKFUN )(int iNumber, int iCode, void* pData);
+
+class CZipStorage
+{
+public:
+ void Open(CMemFile& mf, int iMode);
+// return the position in the file, taking into account the bytes in the write buffer
+ DWORD GetPosition();
+
+// flush the data from the read buffer to the disk
+ void Flush();
+
+// only called by CZipCentralDir when opening an existing archive
+ void UpdateSpanMode(WORD uLastDisk);
+// the preset size of the write buffer
+ int m_iWriteBufferSize;
+
+// user data to be passed to the callback function
+ void* m_pCallbackData;
+
+// function used to change disks during writing to the disk spanning archive
+ void NextDisk(int iNeeded, LPCTSTR lpszFileName = NULL);
+
+ void Close(bool bAfterException);
+
+// return the numer of the current disk
+ int GetCurrentDisk();
+
+ void SetCurrentDisk(int iNumber);
+
+// change the disk during extract operations
+ void ChangeDisk(int iNumber);
+
+// Function name : IsSpanMode
+// Description : detect span mode
+// Return type : int
+// -1 - existing span opened
+// 0 - no span
+// 1 - new span
+ int IsSpanMode();
+
+ void Open(LPCTSTR szPathName, int iMode, int iVolumeSize);
+ void Write(void *pBuf, DWORD iSize, bool bAtOnce);
+ DWORD Read(void* pBuf, DWORD iSize, bool bAtOnce);
+ CZipBigFile m_internalfile;
+ CFile* m_pFile;
+ CZipStorage();
+ virtual ~CZipStorage();
+ enum {noSpan, pkzipSpan, tdSpan, suggestedAuto, suggestedTd};
+ int m_iSpanMode;
+ ZIPCALLBACKFUN m_pZIPCALLBACKFUN;
+ static char m_gszExtHeaderSignat[];
+
+// open tdspan: last disk number, create tdspan: volume size
+// create pkspan: not used
+ int m_iTdSpanData;
+
+protected:
+// how many bytes left free in the write buffer
+ DWORD GetFreeInBuffer();
+ friend class CZipCentralDir;
+// numer of bytes available in the write buffer
+ DWORD m_uBytesInWriteBuffer;
+
+// tdSpan : the total size of the current volume, pkSpan : free space on the current volume
+ DWORD m_uCurrentVolSize;
+
+// return the number of bytes left on the current volume
+ DWORD VolumeLeft();
+
+// write data to the internal buffer
+ void WriteInternalBuffer(char *pBuf, DWORD uSize);
+
+// number of bytes left free in the write buffer
+ DWORD m_uVolumeFreeInBuffer;
+
+ CZipAutoBuffer m_pWriteBuffer;
+
+// return the number of free bytes on the current removable disk
+ DWORD GetFreeVolumeSpace();
+
+ void CallCallback(int iCode, CString szTemp);
+
+// only disk spanning creation: tells how many bytes have been written physically to the current volume
+ DWORD m_iBytesWritten;
+
+// construct the name of the volume in tdSpan mode
+ CString GetTdVolumeName(bool bLast, LPCTSTR lpszZipName = NULL);
+
+// change the disk in tdSpan mode
+ CString ChangeTdRead();
+
+// change the disk in pkSpan mode
+ CString ChangePkzipRead();
+
+// you can only add a new files to the new disk spanning archive and only extract
+// them from the existing one
+ bool m_bNewSpan;
+
+ int m_iCurrentDisk;
+ bool OpenFile(LPCTSTR lpszName, UINT uFlags, bool bThrow = true);
+ void ThrowError(int err);
+
+};
+
+#endif // !defined(AFX_ZIPSTORAGE_H__941824FE_3320_4794_BDE3_BE334ED8984B__INCLUDED_)
diff --git a/stepmania/src/smpackage/ZipArchive/zconf.h b/stepmania/src/smpackage/ZipArchive/zconf.h
new file mode 100644
index 0000000000..6d450fc793
--- /dev/null
+++ b/stepmania/src/smpackage/ZipArchive/zconf.h
@@ -0,0 +1,279 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define compress2 z_compress2
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+# ifndef STDC
+# define STDC
+# endif
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+# define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR _far
+# endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+# if defined(_WINDOWS) || defined(WINDOWS)
+# ifdef FAR
+# undef FAR
+# endif
+# include
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR _cdecl _export
+# endif
+# endif
+# if defined (__BORLANDC__)
+# if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+# include
+# define ZEXPORT __declspec(dllexport) WINAPI
+# define ZEXPORTRVA __declspec(dllexport) WINAPIV
+# else
+# if defined (_Windows) && defined (__DLL__)
+# define ZEXPORT _export
+# define ZEXPORTVA _export
+# endif
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# if defined (ZLIB_DLL)
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+#endif
+
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include /* for off_t */
+# include /* for SEEK_* and off_t */
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(inflate_blocks,"INBL")
+# pragma map(inflate_blocks_new,"INBLNE")
+# pragma map(inflate_blocks_free,"INBLFR")
+# pragma map(inflate_blocks_reset,"INBLRE")
+# pragma map(inflate_codes_free,"INCOFR")
+# pragma map(inflate_codes,"INCO")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_flush,"INFLU")
+# pragma map(inflate_mask,"INMA")
+# pragma map(inflate_set_dictionary,"INSEDI2")
+# pragma map(inflate_copyright,"INCOPY")
+# pragma map(inflate_trees_bits,"INTRBI")
+# pragma map(inflate_trees_dynamic,"INTRDY")
+# pragma map(inflate_trees_fixed,"INTRFI")
+# pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/stepmania/src/smpackage/install.bmp b/stepmania/src/smpackage/install.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..64107b2f2be90d74bc2b33d9db0a4791b043b875
GIT binary patch
literal 31578
zcmeI43sh5Ax`2NlZA6%&@>FVqJQUP4s0h-MHBFk{xghNVin>47FH5c?o6+
zkVNEhd6b7h5J4sZL=@yPfdqsI3I#+IypG<^fTMj}8SR}rqMgwDp9Bb~IE$|7or#>i
z7U%4R8H<&L3c-9=N1A51Z{w;inE}@bfpfLfA*Ygoq%2*#E0N(9+ZhtIZd~yL1cq
z$a@tO^XZ@na)>x1`$3qP=#-SA<3JN#C3)C*f-$p0WbIui4aN)J_9G4rO+7V
z0q4TEg1e&yi1+OP|Mz`BeCSj7EbRzf>Ft6q@7#vJ{Li;gbAS#fgVuvGY7^8)xIylo
z_0V)^BeWcT4O&I+a4vciG#_?{xm;eDFoUWeL4
zUf{8T3VV3(!tc(VhQ=5M)_)DEA{kJ9$Q`0W_CilvE&Oq?6Y7N(UxKz$#V@cKKysc_0Q>
z%gVtzS_G@GoLzD@xLg_nhl+Yw-**evwR8hDvk>eOQ@|!966|wMfCJvcE+!FHMF_#U
z>@3&__Q9sEA#g1}2WyU`!)k2PDJ2`$VLkUo4Q$4A=fh&~tX6{6TR($srB(3LhBkPs
zr3uwcY>qn$
z*4Y)XJWK?%@-|ps*$TfBiDAhbZ^L4$BfPwJBT%JFTR9ByY@$qrcYPE3d)-7miYJ!T2
z3OIJ`7#ulr1orOT3mgsywrtq~gx(9tFux@5XMjaym{$@IAoKb4kdvb&na{fYkFB
z4*G^I9=b7kT3J0b+wPNxP?c^K$)f9ft@hJWBQ217D`hER+#X{)0f)ttiT^Y7p1^C=W_Dm5fv
zr}qOty`7&iB9i$GaTx1`$2&XObky-v)RscwI97tq0(o*
zu#wD-kn)T!dzkDmE$#1>_x2XIE6Tg8yE>066BEP3qp#6?8C>t{EhChGnb1k*GX!Xa
z7bYX6rKK9VytufyFk4aH)z#IRC244gj2WbHSX{6DjZMQ8DsQ@`lgy0}^Yku1{CWV9
zYh=j0y)e6_sJpAIq*E1{q)IvO#AGvl0;6i8sOw)9dx$$wH)?-t@dpMbEWU|c6^!BvmoR)%&
z&XTgWyu7@W_^bAuwOp31xVEk?t`+C>-IMi5=97{z%JbN0A6j;qOrD;e-i*kF!i=nv
zwzfaCi4xS^ZY(yJV}G?aqCP@>l@j1TxeQA(H%iu%onCQAj;pPRytuhJEmN$pkqvkwE{TNB+M#*}j)0X??y{9m=wk
z-QHyG&UPKqfSHTT!8ypzn0nR!sDOh$ZJsjluWDpD#F8?usaJ8_uA
zJU$V)Ox7CO^^WM&gORDN6#6bt94^V+h?#o^$_~rZ3l-hfRaKRpSs9Xs*fctO=Ol04
znakz4+760Tv5}D(qvrG#By%GMj$QZM-c~#
zlsaikAt%-BPF
z3c9exHh8T1e(b&HO9e7*ko<
z*_qW)R?4$=@#Uh&Hl^hZ7T4GITwPR5Y)MI8XI6n!oHk-kGB;-6*mrk%L3d?URn_lP
zQx5YSd^wCM-ns~bxh*I%1>Jd-Dy#E&QBHEsb#pgQPg2i~8T*R9f}$>bPpin6^SoV|
z1{EieqslWKf>WcDR4PeEMp01#GCxi6Cz%^FaqRnDVZrgTiUS7<0~~yrTw*oG@T$i2
zVRL9#2{q5kP%3e4Hm5M{#*f4N;n>*2IZF~NjhW857Fpp-v9PG5LU9Mbqp{fx7OuK_
zd3zD7G8ni!Sx!7*lB%IWqErf7#My;~X?;Hq^H4rtJ7*Y=w0wT(oNJL4OfthINkcZy
zgnBcX9L^eA@Nkd|M{nd=-XY1+4Y$H2N}Ub8&Mk|3|UykNEtMAE2^U{4f&XoF!mA
zRFZt%mgS3T&Ezob-A1lO#Dx=Y>BQX5^ge$uQX;`mtiqO@|{hPPj7vm
zZP!_7y_pV0TaBhyD=-}=?C%)TBP5JTCISJGgb8E%gHG~z`B;F@z!*`|RDgOfz=p<6
z5vi7lq2|coF)b#I
z6E;D2&~;iL!-s(=89Ih)Y^HC>OlzfYatvEEWa=BlM8%B?m(#Q
zL(?$)g+Xlyp`!vc>W}d>MxL*wB?H8F*Kr{M>HMep$pH&ob9&5$E7XF1oF&G
z+!B4AZZSLa=>~hkOk0J9hK^xpX1LgBnDzErZ?uWN>SM%=pby$f^RK%kbRR9pq?boz
z>KmLWhWY%Exxeg9+-v@v%-!s1h#Uj@ZXts)b)tj>0(pWcLX@!{l;VYi);)
z=j0S3a@k>xra#yZB{Z9!>p{$*fxJUQk<}z!go8>s@jy&X^OF<)#KVA-!Gu46uD}#v
z!Y#yRCNd2ViOxsRyAAV)-VYn8pD%~Q^4ZS*qjg>^beuQiDu>wgen^*^PM+`&b2wN@{D>xyO#>s*!n}
z<`rlE>m`v{k$)PY;chr4hjzRC^39v4`b%$wpx6E!=BB8;v$#@7mvGz-0d?1kP+%)V
z(yX!Pv^#4ZGUJ&N@SJpnJ-$v+H>&Zs+7WtvRP5mCbGWrRqeyaV*oIi3bES>k3l19S
z?GLurwKJ;^_sqMHiT|1suo&rxYa}%Nq*{~`6O$4fiQm!^mCB-Fn;rP}&USHP*bZO0
z8>oLsNap{V6zABhts^CI3F_RFCv)>tQez_<@Pm1VvH-)7Eq+$#vN+B`H~Ry1mi;-l
zeU3LJi~n;aV7*8f*O;Gs^5Vs&6#RTDk)W0rv=kI5&fB^$*D_rm4BY&3a;hfv{GZF}
zA9r_mnYuAQ|K!CB9lCwZLLu&lRVd1PZj3sw^WJw=GlhJ1zx^NA8M3AS9|>6eu~RL&
zkbj}0tt3k+l;Xaa9EAcm!1q6}_rEdljpbA?NIjnth0#YmzaG4le*u}RaF>KsN+4HU
z>FK#ydUv2NZ1RUiaFir-qepERfT!6vnv#wSc_qh-T5@nJRAG-U-0Z)*ME4#)QIceC
z5ZQ|mv;1bDw>z&SODM%}=4tJPJy&k_-}!jbd()4QWd0(Mo-qc;Pw)0=ird?Zi+kn$
zeW$;9ylh4`Y1^L=#|v_~ipmQK#t_8g?S6Vlq@F)5lNUXOWd5QPetLY!{Lf^VXA%JT
EKU95#%m4rY
literal 0
HcmV?d00001
diff --git a/stepmania/src/smpackage/manage.bmp b/stepmania/src/smpackage/manage.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0024c614391d424b893fe1b3eadd4d3fe2634723
GIT binary patch
literal 31578
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
OZF
zlX6T4qpWw1*Kx}00Rtbyda&0_<+$s5R@NCe9o!nP*OII7dY)q3Y+83*d(`m0aO`-6
z?O+%ZUDvaEAKP&~za8&7Tf+N(b*SCC^TIRYE;Yo1(i#k}4}9=4`UB&}@pi?4$68`f
zSv-D#I)9_7HgRRbZ9*vAvhTsWS+3*vwwrxtSWeBtJ?)G8{29q^-@{jhze)IH@JB;B
z+HENn_wPf+=J^xDI&F|UV6m#~!@TuP;_ZMNXs^3m+tqdiZ7J)LOqQqrp>LE_6x!|b
zJ3df>Z_u|a^=3*IsQ%1RdcPqpl=GcOB0
z(kEH^8fx2i2vcjUM{7xzr!>R%3q%3tAp4kuJi{Dh4|9iB94syFjK%d?T!1<7${y^l
zDZgd-gFWRR{TvT-vd}BpuPpR8bew^@9>SE?zw@)+{vi;O
zpJ2bwM+t#S8zA&aM#}Uy`URT6-9@#9NS)nAH!N9wwnruLjHOFW;E0vo-p*z4HB(1I
zVI2%LBi7V6GM7tpKU>ztwqUolWGtQX{_?Yi;8S0F|7bM&kES^(zi;cW8j*S#b5K>J=j#EQKSVSc~8f@+KE_Wv=q)PVqY
z)P{lG`X{`%Z}HDfE>U9~`)6y%>hiC9t1)yBMYOitzwWL?jWIc9*n38of8CGyk&}_A
z^36|N<5$3CBRt;J*2@!ftabTbi5Z5Y&F5i0+q!`2gmaq3cJlj_dO<7$t?N_xd409?
z^YYJb=lH)8=`@ya`})%FhwjhizIFNa^k6+yLN>~OmGy7V$~yKSsMl!(8;=iW%0&IR
zu$L(GHUfve_5N~yz4tUw@2LkGzWR)$(;1?FV@EO)NPpsmx
SuOIr#4%=kgr!ZZoe)&I3EM-0b
literal 0
HcmV?d00001
diff --git a/stepmania/src/smpackage/smpackage.clw b/stepmania/src/smpackage/smpackage.clw
new file mode 100644
index 0000000000..899035d676
--- /dev/null
+++ b/stepmania/src/smpackage/smpackage.clw
@@ -0,0 +1,66 @@
+; CLW file contains information for the MFC ClassWizard
+
+[General Info]
+Version=1
+LastClass=CSMPackageInstallDlg
+LastTemplate=CDialog
+NewFileInclude1=#include "stdafx.h"
+NewFileInclude2=#include "smpackage.h"
+
+ClassCount=3
+Class1=CSmpackageApp
+Class2=CSmpackageDlg
+
+ResourceCount=3
+Resource1=IDR_MAINFRAME
+Resource2=IDD_MANAGER
+Class3=CSMPackageInstallDlg
+Resource3=IDD_INSTALL
+
+[CLS:CSmpackageApp]
+Type=0
+HeaderFile=smpackage.h
+ImplementationFile=smpackage.cpp
+Filter=N
+LastObject=CSmpackageApp
+
+[CLS:CSmpackageDlg]
+Type=0
+HeaderFile=smpackageDlg.h
+ImplementationFile=smpackageDlg.cpp
+Filter=D
+LastObject=CSmpackageDlg
+BaseClass=CDialog
+VirtualFilter=dWC
+
+
+
+[DLG:IDD_MANAGER]
+Type=1
+Class=CSmpackageDlg
+ControlCount=5
+Control1=IDOK,button,1342242817
+Control2=IDC_LIST_SONGS,listbox,1352728835
+Control3=IDC_BUTTON_PLAY,button,1342242816
+Control4=IDC_BUTTON_EXPORT,button,1476460544
+Control5=IDC_STATIC,static,1342177294
+
+[DLG:IDD_INSTALL]
+Type=1
+Class=CSMPackageInstallDlg
+ControlCount=5
+Control1=IDC_EDIT_MESSAGE,edit,1342179460
+Control2=IDOK,button,1342242817
+Control3=IDCANCEL,button,1342242816
+Control4=IDC_BUTTON_BACK,button,1476460544
+Control5=IDC_STATIC,static,1342177294
+
+[CLS:CSMPackageInstallDlg]
+Type=0
+HeaderFile=SMPackageInstallDlg.h
+ImplementationFile=SMPackageInstallDlg.cpp
+BaseClass=CDialog
+Filter=D
+LastObject=CSMPackageInstallDlg
+VirtualFilter=dWC
+
diff --git a/stepmania/src/smpackage/smpackage.cpp b/stepmania/src/smpackage/smpackage.cpp
new file mode 100644
index 0000000000..c6cb30c7d3
--- /dev/null
+++ b/stepmania/src/smpackage/smpackage.cpp
@@ -0,0 +1,120 @@
+// smpackage.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "smpackage.h"
+#include "smpackageDlg.h"
+#include "smpackageInstallDlg.h"
+#include "../RageUtil.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageApp
+
+BEGIN_MESSAGE_MAP(CSmpackageApp, CWinApp)
+ //{{AFX_MSG_MAP(CSmpackageApp)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ // DO NOT EDIT what you see in these blocks of generated code!
+ //}}AFX_MSG
+ ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageApp construction
+
+CSmpackageApp::CSmpackageApp()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CSmpackageApp object
+
+CSmpackageApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageApp initialization
+
+BOOL CSmpackageApp::InitInstance()
+{
+ // Standard initialization
+ // If you are not using these features and wish to reduce the size
+ // of your final executable, you should remove from the following
+ // the specific initialization routines you do not need.
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+
+
+ // Make sure the current directory is the root program directory
+ if( !DoesFileExist("Songs") )
+ {
+ // change dir to path of the execuctable
+ TCHAR szFullAppPath[MAX_PATH];
+ GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
+
+ // strip off executable name
+ LPSTR pLastBackslash = strrchr(szFullAppPath, '\\');
+ *pLastBackslash = '\0'; // terminate the string
+
+ SetCurrentDirectory(szFullAppPath);
+
+ if( !DoesFileExist("Songs") )
+ {
+ AfxMessageBox( "Your Songs folder could not be located. Be sure 'smpackage.exe' is in your Stepmania installation folder.", MB_ICONSTOP );
+ exit( 1 );
+ }
+
+ }
+
+ // check if there's a .smzip command line argument
+ CStringArray arrayCommandLineBits;
+ split( ::GetCommandLine(), "\"", arrayCommandLineBits );
+ for( int i=0; i
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=smpackage - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "smpackage.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "smpackage.mak" CFG="smpackage - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "smpackage - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "smpackage - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "smpackage - Win32 Release"
+
+# PROP BASE Use_MFC 5
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 6
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_AFXDLL" /FR /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
+# ADD LINK32 /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "smpackage - Win32 Debug"
+
+# PROP BASE Use_MFC 5
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 6
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "smpackage - Win32 Release"
+# Name "smpackage - Win32 Debug"
+# Begin Group "Stepmania Package files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\RageUtil.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\RageUtil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\smpackage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\smpackage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\smpackage.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\smpackage.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\smpackage.rc2
+# End Source File
+# Begin Source File
+
+SOURCE=.\smpackageDlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\smpackageDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMPackageInstallDlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SMPackageInstallDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\install.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\manage.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ReadMe.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\smpackage.ICO
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\StepMania.ICO
+# End Source File
+# End Target
+# End Project
diff --git a/stepmania/src/smpackage/smpackage.h b/stepmania/src/smpackage/smpackage.h
new file mode 100644
index 0000000000..fab6370972
--- /dev/null
+++ b/stepmania/src/smpackage/smpackage.h
@@ -0,0 +1,49 @@
+// smpackage.h : main header file for the SMPACKAGE application
+//
+
+#if !defined(AFX_SMPACKAGE_H__FBCA9E6C_86A9_4271_8304_83CC34A31687__INCLUDED_)
+#define AFX_SMPACKAGE_H__FBCA9E6C_86A9_4271_8304_83CC34A31687__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageApp:
+// See smpackage.cpp for the implementation of this class
+//
+
+class CSmpackageApp : public CWinApp
+{
+public:
+ CSmpackageApp();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSmpackageApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CSmpackageApp)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_SMPACKAGE_H__FBCA9E6C_86A9_4271_8304_83CC34A31687__INCLUDED_)
diff --git a/stepmania/src/smpackage/smpackage.opt b/stepmania/src/smpackage/smpackage.opt
new file mode 100644
index 0000000000000000000000000000000000000000..d96c8d6eb0f4f72d67085e507a3aff504aa48152
GIT binary patch
literal 54784
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",IDOK,200,215,55,15
+ PUSHBUTTON "Cancel",IDCANCEL,275,215,50,15
+ PUSHBUTTON "< Back",IDC_BUTTON_BACK,145,215,55,15,WS_DISABLED
+ CONTROL 133,IDC_STATIC,"Static",SS_BITMAP,0,0,258,37
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "smpackage MFC Application\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "smpackage\0"
+ VALUE "LegalCopyright", "Copyright (C) 2002\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "smpackage.EXE\0"
+ VALUE "ProductName", "smpackage Application\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_MANAGER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 325
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 227
+ END
+
+ IDD_INSTALL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 325
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 227
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+INSTALL BITMAP DISCARDABLE "install.bmp"
+MANAGE BITMAP DISCARDABLE "manage.bmp"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif //_WIN32
+#include "res\smpackage.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/stepmania/src/smpackage/smpackageDlg.cpp b/stepmania/src/smpackage/smpackageDlg.cpp
new file mode 100644
index 0000000000..b9ab0f9168
--- /dev/null
+++ b/stepmania/src/smpackage/smpackageDlg.cpp
@@ -0,0 +1,210 @@
+// smpackageDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "smpackage.h"
+#include "smpackageDlg.h"
+#include "../RageUtil.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageDlg dialog
+
+CSmpackageDlg::CSmpackageDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CSmpackageDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CSmpackageDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+ // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
+ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+void CSmpackageDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CSmpackageDlg)
+ DDX_Control(pDX, IDC_BUTTON_EXPORT, m_buttonExport);
+ DDX_Control(pDX, IDC_LIST_SONGS, m_listBoxSongs);
+ //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CSmpackageDlg, CDialog)
+ //{{AFX_MSG_MAP(CSmpackageDlg)
+ ON_WM_PAINT()
+ ON_WM_QUERYDRAGICON()
+ ON_LBN_SELCHANGE(IDC_LIST_SONGS, OnSelchangeListSongs)
+ ON_BN_CLICKED(IDC_BUTTON_EXPORT, OnButtonExport)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageDlg message handlers
+
+BOOL CSmpackageDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ // Set the icon for this dialog. The framework does this automatically
+ // when the application's main window is not a dialog
+ SetIcon(m_hIcon, TRUE); // Set big icon
+ SetIcon(m_hIcon, FALSE); // Set small icon
+
+ //
+ // TODO: Add extra initialization here
+ //
+
+ // Find all song directories
+ CStringArray arrayGroupDirs;
+ GetDirListing( "Songs\\*.*", arrayGroupDirs, true );
+
+ for( int i=0; iDelete();
+ return;
+ }
+
+
+ CStringArray arrayFiles;
+ GetDirListing( sSongDir + "\\*.*", arrayFiles );
+ //m_zip.AddNewFile( sRelPathToSelectedSong, 0, true ); // add the directory
+
+ m_zip.AddNewFile( "Songs", 0, true );
+ m_zip.AddNewFile( sGroupDir, 0, true );
+ m_zip.AddNewFile( sSongDir, 0, true );
+
+ for( int i=0; iDelete();
+ return;
+ }
+ }
+
+ AfxMessageBox( ssprintf("Successfully exported '%s' to '%s' on your Desktop.", sSongDir, sZipFileName) );
+
+
+ m_zip.Close();
+
+}
+
+
+
diff --git a/stepmania/src/smpackage/smpackageDlg.h b/stepmania/src/smpackage/smpackageDlg.h
new file mode 100644
index 0000000000..1e196b5ae8
--- /dev/null
+++ b/stepmania/src/smpackage/smpackageDlg.h
@@ -0,0 +1,57 @@
+// smpackageDlg.h : header file
+//
+
+#if !defined(AFX_SMPACKAGEDLG_H__E60DA2DD_D8D6_42BC_9049_631EAFBAA1F6__INCLUDED_)
+#define AFX_SMPACKAGEDLG_H__E60DA2DD_D8D6_42BC_9049_631EAFBAA1F6__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// CSmpackageDlg dialog
+
+
+#include "ZipArchive\ZipArchive.h"
+
+
+class CSmpackageDlg : public CDialog
+{
+// Construction
+public:
+ CSmpackageDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CSmpackageDlg)
+ enum { IDD = IDD_SMPACKAGE_DIALOG };
+ CButton m_buttonExport;
+ CListBox m_listBoxSongs;
+ //}}AFX_DATA
+
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSmpackageDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ HICON m_hIcon;
+ CZipArchive m_zip;
+
+
+ // Generated message map functions
+ //{{AFX_MSG(CSmpackageDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnPaint();
+ afx_msg HCURSOR OnQueryDragIcon();
+ afx_msg void OnSelchangeListSongs();
+ afx_msg void OnButtonExport();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_SMPACKAGEDLG_H__E60DA2DD_D8D6_42BC_9049_631EAFBAA1F6__INCLUDED_)