int ExtractFile(char* filename)
{
	char* outputFolder = "temp\\";
	HANDLE                  hData;
	INT                     RHCode;
	INT                     PFCode;
	RARHeaderData           HeaderData;
	RAROpenArchiveDataEx    OpenArchiveData = { 0 };
	{
		OpenArchiveData.ArcName     = filename;
		//OpenArchiveData.CmtBuf    = NULL;
		//OpenArchiveData.CmtBufSize  = 0;
		OpenArchiveData.OpenMode    = RAR_OM_EXTRACT;
	}
	hData = RAROpenArchiveEx(&OpenArchiveData);
	if(OpenArchiveData.OpenResult != 0)
	{
		char buf[128];
		memset(buf, 0, sizeof(buf));
		sprintf_s(buf, "Error opening <%s>", filename);
		MessageBox(NULL, "Error!", buf, MB_OK|MB_ICONERROR);
		return -1;
	}
	RARSetPassword(hData, "8863da099df8adc830836744e19293ef");

	while((RHCode = RARReadHeader(hData, &HeaderData)) == 0)
	{
		PFCode = RARProcessFile(hData, RAR_EXTRACT, outputFolder, NULL);
		if(PFCode != 0)
		{
			char buf[128];
			memset(buf, 0, sizeof(buf));
			sprintf_s(buf, "Error extracting <%s>", filename);
			MessageBox(NULL, "Error!", buf, MB_OK|MB_ICONERROR);
			return -1;
		}
		struct stat st;
		std::string file = outputFolder;
		file += HeaderData.FileName;
		stat(file.c_str(), &st);
		if(st.st_mode & S_IFREG)
		{
			vfs->patchfiles.push_back(file);
		}
	}
	if(RHCode == ERAR_BAD_DATA)
	{
		char buf[128];
		memset(buf, 0, sizeof(buf));
		sprintf_s(buf, "Error <%s> is corrupt", filename);
		MessageBox(NULL, "Error!", buf, MB_OK|MB_ICONERROR);
		return -1;
	}
	RARCloseArchive(hData);
	DeleteFile(filename);
	return 0;
}
Exemple #2
0
void YKZip::Extra(const YKString& srcFile, const YKString& desPath, const YK_CHAR* passWord /* = "" */)
{
#if YK_OS == YK_OS_WINDOWS_NT
	setlocale(LC_ALL, NULL);
	HANDLE hArcData;
	int RHCode,PFCode;
	char CmtBuf[16384];
	struct RARHeaderDataEx HeaderData;
	struct RAROpenArchiveDataEx OpenArchiveData;

	memset(&HeaderData,0,sizeof(HeaderData));
	memset(&OpenArchiveData,0,sizeof(OpenArchiveData));

	YKBuffer<YK_WCHAR> buffSrc(srcFile.size()+1);
	std::wcscpy(buffSrc.Begin(), srcFile.c_str());
	YKBuffer<YK_WCHAR> buffDes(desPath.size()+1);
	std::wcscpy(buffDes.Begin(), desPath.c_str());
	OpenArchiveData.ArcNameW = buffSrc.Begin();
	OpenArchiveData.CmtBuf=CmtBuf;
	OpenArchiveData.CmtBufSize=sizeof(CmtBuf);
	OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
	OpenArchiveData.Callback=YK_NULL;
	OpenArchiveData.UserData=0;
	hArcData = RAROpenArchiveEx(&OpenArchiveData);
	if (OpenArchiveData.OpenResult!=0)
		return;

	RARSetPassword(hArcData, const_cast<YK_CHAR*>(passWord));
	while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
	{
		PFCode = RARProcessFileW(hArcData,RAR_EXTRACT,
			buffDes.Begin(), NULL);
	}

	RARCloseArchive(hArcData);
#endif
// 	YKString strExtra = g_Application.GetCurModulePath();
// 	strExtra.Append(L"HaoZip\\HaoZipC.exe x ").Append(srcFile).Append(L" -ao -y -o").Append(desPath);
// 	strExtra.Append(L" -p").Append(L"42F7AA9A-67E0-4CC7-9526-B2E8B358F179");
// 	system(strExtra.ToString().c_str());
// 	return;
// 	HZIP hz = OpenZip(srcFile.c_str(), passWord);
// 	ZIPENTRY ze; 
// 	GetZipItem(hz,-1,&ze);
// 	int num = ze.index;
// 	for (int i = 0; i < num; ++i)
// 	{
// 		GetZipItem(hz, i, &ze);
// 		UnzipItem(hz,i, (desPath + ze.name).c_str());
// 	}
// 
// 	CloseZip(hz);
}
Exemple #3
0
ComicBookRAR::ComicBookRAR(wxString file, wxUint32 cacheLen, COMICAL_ZOOM zoom, long zoomLevel, bool fitOnlyOversize, COMICAL_MODE mode, FREE_IMAGE_FILTER filter, COMICAL_DIRECTION direction, wxInt32 scrollbarThickness) : ComicBook(file, cacheLen, zoom, zoomLevel, fitOnlyOversize, mode, filter, direction, scrollbarThickness)
{
	HANDLE rarFile;
	int RHCode = 0, PFCode = 0;
	struct RARHeaderDataEx header;
	struct RAROpenArchiveDataEx flags;
	wxString page, new_password;
	
	open_rar:
	
	rarFile = openRar(&flags, &header, RAR_OM_LIST);

	if (flags.Flags & 0x0080) { // if the headers are encrypted
		new_password = wxGetPasswordFromUser(
				wxT("This archive is password-protected.  Please enter the password."),
				wxT("Enter Password"));
		if (new_password.IsEmpty()) { // the dialog was cancelled, and the archive cannot be opened
			closeRar(rarFile, &flags);
			throw ArchiveException(filename, wxT("Comical could not open this file because it is password-protected."));
		}
		SetPassword(new_password.ToAscii());
	}
	if (password)
		RARSetPassword(rarFile, password);

	while ((RHCode = RARReadHeaderEx(rarFile, &header)) == 0) {
#ifdef wxUSE_UNICODE
		page = wxString(header.FileNameW);
#else
		page = wxString(header.FileName);
#endif
		if(page.Right(5).Upper() == wxT(".JPEG") || page.Right(4).Upper() == wxT(".JPG") ||
		page.Right(4).Upper() == wxT(".GIF") ||
		page.Right(4).Upper() == wxT(".PNG"))
			Filenames->Add(page);
		
		if ((PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL)) != 0) {
			closeRar(rarFile, &flags);
			throw ArchiveException(filename, ProcessFileError(PFCode, page));
		}
	}

	closeRar(rarFile, &flags);
	
	// Wrong return code + needs password = wrong password given
	if (RHCode != ERAR_END_ARCHIVE && flags.Flags & 0x0080) 
		goto open_rar;

	postCtor();
	Create(); // create the wxThread
}
bool ComicBookRAR::TestPassword()
{
	HANDLE rarFile;
	int RHCode = 0, PFCode = 0;
	struct RARHeaderDataEx header;
	struct RAROpenArchiveDataEx flags;
	bool passwordCorrect = true;
	
	if (Pages.size() == 0)
		// nothing in the archive to open
		return true;

	wxString page = Pages.at(0)->Filename; // test using the first page
	
	rarFile = openRar(&flags, &header, RAR_OM_EXTRACT);

	if (password)
		RARSetPassword(rarFile, password);

	while ((RHCode = RARReadHeaderEx(rarFile, &header)) == 0) {
		if (page.Cmp(header.FileNameW) == 0) {
			break;
		} else {
			if ((PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL)) != 0) {
				closeRar(rarFile, &flags);
				throw ArchiveException(filename, ProcessFileError(PFCode, page));
			}
		}
	}
	
	if (RHCode != 0) {
		closeRar(rarFile, &flags);
		throw new ArchiveException(filename, OpenArchiveError(RHCode));
	}

	RARSetCallback(rarFile, TestPasswordCallbackProc, (long) &passwordCorrect);
	PFCode = RARProcessFile(rarFile, RAR_TEST, NULL, NULL);

	closeRar(rarFile, &flags);

	// If the password is wrong, RARProcessFile will return ERAR_BAD_DATA.  Of
	// course, it will also return ERAR_BAD_DATA when the first file in the archive
	// is corrupted.  How does one tell the difference?
	if (PFCode == ERAR_BAD_DATA)
		return false;

	return passwordCorrect;
}
Exemple #5
0
//////////////////////////////////////////////////////////
//
// ExtractFiles
//
// Extract files from supplied archive filename
//
//////////////////////////////////////////////////////////
bool ExtractFiles ( const SString& strFile )
{
    // Open archive
    RAROpenArchiveData archiveData;
    memset ( &archiveData, 0, sizeof ( archiveData ) );
    archiveData.ArcName = (char*)*strFile;
    archiveData.OpenMode = RAR_OM_EXTRACT;
    HANDLE hArcData = RAROpenArchive ( &archiveData );

    if ( !hArcData )
        return false;

    char* szPassword = "******";
    RARSetPassword ( hArcData, szPassword );

    bool bOk = false;

    // Do each file
    while ( true )
    {
        // Read file header
        RARHeaderData headerData;
        memset ( &headerData, 0, sizeof ( headerData ) );
        int iStatus = RARReadHeader ( hArcData, &headerData );

        if ( iStatus != 0 )
        {
            if ( iStatus == ERAR_END_ARCHIVE )
                bOk = true;
            break;
        }

        // Read file data
        iStatus = RARProcessFile ( hArcData, RAR_EXTRACT, NULL, NULL );

        if ( iStatus != 0 )
            break;
    }

    RARCloseArchive ( hArcData );
    return bOk;
}
Exemple #6
0
wxRarInputStream::wxRarInputStream(const wxChar* szFile)
{
	    RAROpenArchiveDataEx rx;
	    memset(&rx,0,sizeof(rx));
#if wxUSE_UNICODE
        rx.ArcNameW =((wxChar*) szFile);
#else /* !wxUSE_UNICODE */
	    rx.ArcName  =((wxChar*) szFile);
#endif
        rx.OpenMode=RAR_OM_EXTRACT;
	    rx.CmtBuf=m_Info.szComment=new char[2000];
	    rx.CmtBufSize=2000;
	    m_hRar = RAROpenArchiveEx(&rx);

        if (!m_hRar)
        {
            wxLogSysError(wxString::Format(_("Couldn't open rar file %s"), szFile));
            delete m_Info.szComment;
        }

	    RARSetPassword(m_hRar,"");
}
Exemple #7
0
Fichier : unrar.c Projet : layus/Os
int
unrar_test_password(const char * file, const char * pwd) 
{
        void                      * unrar;
        struct RARHeaderData        headerdata;
        struct RAROpenArchiveData   archivedata;
        int                         password_incorrect;

        password_incorrect = 0;
        memset(&headerdata, 0, sizeof(headerdata));
        memset(&archivedata, 0, sizeof(archivedata));
        archivedata.ArcName  = (char *) file;
        archivedata.OpenMode = RAR_OM_EXTRACT;

        unrar = RAROpenArchive(&archivedata);
        if (!unrar || archivedata.OpenResult)
                return -2;

        RARSetPassword(unrar, (char *) pwd);

        RARSetCallback(unrar, _unrar_test_password_callback, (long) &password_incorrect);

        if (RARReadHeader(unrar, &headerdata) != 0)
                goto error;

        if (RARProcessFile(unrar, RAR_TEST, NULL, NULL) != 0)
                goto error;

        if (password_incorrect)
                goto error;

        RARCloseArchive(unrar);
        return 0;

error:
        RARCloseArchive(unrar);
        return -1;
}
Exemple #8
0
/*
=======================================
    RAR 文件读取
=======================================
*/
CR_API sFMT_PRT*
load_rar (
  __CR_IO__ iDATIN*         datin,
  __CR_IN__ const sLOADER*  param
    )
{
    HANDLE                  rar;
    sARRAY                  list;
    int32u                  attr;
    sint_t                  retc;
    leng_t                  fpos;
    iPAK_RAR*               port;
    sFMT_PRT*               rett;
    sPAK_RAR_FILE           temp;
    RARHeaderDataEx         info;
    RAROpenArchiveDataEx    open;

    /* 只支持磁盘文件 */
    if (param->type != CR_LDR_ANSI &&
        param->type != CR_LDR_WIDE)
        return (NULL);

    /* 列表模式打开 RAR 文件 */
    struct_zero(&open, RAROpenArchiveDataEx);
    if (param->type == CR_LDR_ANSI)
        open.ArcName = (ansi_t*)param->name.ansi;
    else
        open.ArcNameW = (wide_t*)param->name.wide;
    open.OpenMode = RAR_OM_LIST;
    rar = RAROpenArchiveEx(&open);
    if (rar == NULL)
        return (NULL);
    if (param->aprm != NULL &&
        *(byte_t*)param->aprm != 0x00) {
        RARSetPassword(rar, (ansi_t*)param->aprm);
        attr = PAK_FILE_ENC;
    }
    else {
        attr = 0;
    }

    /* 开始逐个文件读取信息并定位 */
    array_initT(&list, sPAK_RAR_FILE);
    list.free = rar_free;
    struct_zero(&info, RARHeaderDataEx);
    for (fpos = 0; ; fpos++)
    {
        /* 读取一个文件记录头 */
        retc = RARReadHeaderEx(rar, &info);
        if (retc == ERAR_END_ARCHIVE)
            break;
        if (retc != ERAR_SUCCESS)
            goto _failure1;

        /* 目录文件不加入列表 */
        if (info.Flags & RHDF_DIRECTORY) {
            retc = RARProcessFile(rar, RAR_SKIP, NULL, NULL);
            if (retc != ERAR_SUCCESS)
                goto _failure1;
            continue;
        }

        /* 文件名统一使用 UTF-8 编码 */
        struct_zero(&temp, sPAK_RAR_FILE);
        temp.base.name = local_to_utf8(param->page, info.FileName);
        if (temp.base.name == NULL)
            goto _failure1;

        /* 设置公用文件属性 (偏移没有实际用处) */
        temp.base.skip = sizeof(sPAK_RAR_FILE);
        temp.base.attr = attr;
        temp.base.offs = 0;
        temp.base.pack = mk_size(info.PackSizeHigh, info.PackSize);
        temp.base.size = mk_size(info.UnpSizeHigh, info.UnpSize);
        if (info.Method != 0x30)
            temp.base.attr |= PAK_FILE_CMP;
        if (info.Flags & RHDF_ENCRYPTED)
            temp.base.attr |=  PAK_FILE_ENC;
        else
            temp.base.attr &= ~PAK_FILE_ENC;
        switch (info.Method)
        {
            case 0x30: temp.base.memo = "Storing";             break;
            case 0x31: temp.base.memo = "Fastest compression"; break;
            case 0x32: temp.base.memo = "Fast compression";    break;
            case 0x33: temp.base.memo = "Normal compression";  break;
            case 0x34: temp.base.memo = "Good compression";    break;
            case 0x35: temp.base.memo = "Best compression";    break;
            default:   temp.base.memo = "Unknown compression"; break;
        }

        /* 设置私有文件属性 */
        temp.id = fpos;
        temp.crc32 = (int32u)(info.FileCRC);
        temp.fattr = (int32u)(info.FileAttr);
        temp.ftime = (int16u)(info.FileTime & 0xFFFF);
        temp.fdate = (int16u)(info.FileTime >> 16);
        temp.htype = (int32u)(info.HashType);
        mem_cpy(temp.hash, info.Hash, sizeof(temp.hash));

        /* 文件信息压入列表 */
        if (array_push_growT(&list, sPAK_RAR_FILE, &temp) == NULL) {
            mem_free(temp.base.name);
            goto _failure1;
        }

        /* 跳过当前已读文件 */
        retc = RARProcessFile(rar, RAR_SKIP, NULL, NULL);
        if (retc != ERAR_SUCCESS && retc != ERAR_BAD_DATA)
            goto _failure1;
    }

    /* 固定一下列表大小 */
    if (!array_no_growT(&list, sPAK_RAR_FILE))
        goto _failure1;

    /* 生成读包接口对象 */
    port = struct_new(iPAK_RAR);
    if (port == NULL)
        goto _failure1;

    /* 保存需要用到的参数 */
    port->m_temp = NULL;
    if (attr == 0) {
        port->m_pass = NULL;
    }
    else {
        port->m_pass = str_dupA((ansi_t*)param->aprm);
        if (port->m_pass == NULL)
            goto _failure2;
    }
    if (param->type == CR_LDR_ANSI) {
        port->m_wide = NULL;
        port->m_ansi = str_dupA(param->name.ansi);
        if (port->m_ansi == NULL)
            goto _failure3;
    }
    else {
        port->m_ansi = NULL;
        port->m_wide = str_dupW(param->name.wide);
        if (port->m_wide == NULL)
            goto _failure3;
    }
    port->m_rar = NULL;
    port->m_cur = (leng_t)-1;
    port->m_cnt = array_get_sizeT(&list, sPAK_RAR_FILE);
    port->pack.__filelst__ = array_get_dataT(&list, sPAK_FILE);
    port->pack.__vptr__ = &s_pack_vtbl;
    if (!pack_init_list((iPACKAGE*)port, TRUE))
        goto _failure4;
    RARCloseArchive(rar);

    /* 返回读取的文件数据 */
    rett = struct_new(sFMT_PRT);
    if (rett == NULL) {
        iPAK_RAR_release((iPACKAGE*)port);
        return (NULL);
    }
    CR_NOUSE(datin);
    rett->type = CR_FMTZ_PRT;
    rett->port = (iPORT*)port;
    rett->more = "iPACKAGE";
    rett->infor = "Roshal ARchive (RAR)";
    return (rett);

_failure4:
    TRY_FREE(port->m_ansi);
    TRY_FREE(port->m_wide);
_failure3:
    TRY_FREE(port->m_pass);
_failure2:
    mem_free(port);
_failure1:
    array_freeT(&list, sPAK_RAR_FILE);
    RARCloseArchive(rar);
    return (NULL);
}
Exemple #9
0
/*
---------------------------------------
    读取文件数据
---------------------------------------
*/
static bool_t
iPAK_RAR_getFileData (
  __CR_IN__ iPACKAGE*   that,
  __CR_OT__ sBUFFER*    buff,
  __CR_IN__ int64u      index,
  __CR_IN__ bool_t      hash
    )
{
    sint_t                  rett;
    int64u                  size;
    void_t*                 data;
    iPAK_RAR*               real;
    sPAK_RAR_FILE*          item;
    RARHeaderDataEx         info;
    RAROpenArchiveDataEx    open;

    /* 定位文件索引 */
    CR_NOUSE(hash);
    real = (iPAK_RAR*)that;
    if (index >= real->m_cnt)
        return (FALSE);
    item = (sPAK_RAR_FILE*)real->pack.__filelst__;
    item += (leng_t)index;

    /* 获取文件数据 (0大小文件分配1个字节) */
    size = item->base.size;
    if (size == 0) {
        data = mem_malloc(1);
        if (data == NULL)
            return (FALSE);
        size = 1;
        *(byte_t*)data = 0x00;
    }
    else {
        real->m_temp = data = mem_malloc64(size);
        if (data == NULL)
            return (FALSE);

        /* RAR 只能顺序读取文件 */
        if (real->m_rar == NULL || item->id < real->m_cur)
        {
            /* 需要重新打开封包 */
            if (real->m_rar != NULL) {
                RARCloseArchive(real->m_rar);
                real->m_rar = NULL;
            }
            struct_zero(&open, RAROpenArchiveDataEx);
            if (real->m_ansi != NULL)
                open.ArcName = real->m_ansi;
            else
                open.ArcNameW = real->m_wide;
            open.OpenMode = RAR_OM_EXTRACT;
            open.Callback = rar_mem_copy;
            open.UserData = (LPARAM)(&real->m_temp);
            real->m_rar = RAROpenArchiveEx(&open);
            if (real->m_rar == NULL)
                goto _failure1;
            if (real->m_pass != NULL)
                RARSetPassword(real->m_rar, real->m_pass);
            real->m_cur = 0;
        }

        /* 定位到指定文件 */
        struct_zero(&info, RARHeaderDataEx);
        while (real->m_cur != item->id) {
            rett = RARReadHeaderEx(real->m_rar, &info);
            if (rett != ERAR_SUCCESS)
                goto _failure2;
            rett = RARProcessFile(real->m_rar, RAR_SKIP, NULL, NULL);
            if (rett != ERAR_SUCCESS && rett != ERAR_BAD_DATA)
                goto _failure2;
            real->m_cur += 1;
        }

        /* 测试目标文件就不会有磁盘操作了 */
        rett = RARReadHeaderEx(real->m_rar, &info);
        if (rett != ERAR_SUCCESS)
            goto _failure2;
        rett = RARProcessFile(real->m_rar, RAR_TEST, NULL, NULL);
        if (rett != ERAR_SUCCESS)
            goto _failure2;
        real->m_cur += 1;
    }

    /* 返回文件数据 */
    return (buffer_init(buff, data, (leng_t)size, TRUE));

_failure2:
    RARCloseArchive(real->m_rar);
    real->m_rar = NULL;
_failure1:
    real->m_cur = (leng_t)-1;
    mem_free(data);
    return (FALSE);
}
ComicBookRAR::ComicBookRAR(wxString file, wxUint32 cacheLen, COMICAL_ZOOM zoom, long zoomLevel, bool fitOnlyOversize, COMICAL_MODE mode, FREE_IMAGE_FILTER filter, COMICAL_DIRECTION direction, wxInt32 scrollbarThickness) : ComicBook(file, cacheLen, zoom, zoomLevel, fitOnlyOversize, mode, filter, direction, scrollbarThickness)
{
	HANDLE rarFile;
	int RHCode = 0, PFCode = 0;
	struct RARHeaderDataEx header;
	struct RAROpenArchiveDataEx flags;
	wxString path, new_password;
	wxInputStream *stream;
	ComicPage *page;
	int numEntries, progress=0;
	
	open_rar:
	
	rarFile = openRar(&flags, &header, RAR_OM_LIST);

	if (flags.Flags & 0x0080) { // if the headers are encrypted
		new_password = wxGetPasswordFromUser(
				wxT("This archive is password-protected.  Please enter the password."),
				wxT("Enter Password"));
		if (new_password.IsEmpty()) { // the dialog was cancelled, and the archive cannot be opened
			closeRar(rarFile, &flags);
			throw ArchiveException(filename, wxT("Comical could not open this file because it is password-protected."));
		}
		SetPassword(new_password.ToAscii());
	}
	if (password)
		RARSetPassword(rarFile, password);

	// skip through the entire archive to count the number of entries
	for (numEntries = 0; RARReadHeaderEx(rarFile, &header) == 0; numEntries++) {
		if ((PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL)) != 0) {
			closeRar(rarFile, &flags);
			throw ArchiveException(filename, ProcessFileError(PFCode, header.FileNameW));
		}
	}

	wxProgressDialog progressDlg(wxString(wxT("Opening ")) + file, wxString(), numEntries);
	progressDlg.SetMinSize(wxSize(400, -1));

	// close and re-open the archive to restart at the first header
	closeRar(rarFile, &flags);
	rarFile = openRar(&flags, &header, RAR_OM_LIST);

	while ((RHCode = RARReadHeaderEx(rarFile, &header)) == 0) {
		path = header.FileNameW;

		progressDlg.Update(progress, wxString(wxT("Scanning: ")) + path);
		progressDlg.CentreOnParent(wxHORIZONTAL);

		stream = ExtractStream(path);
		page = new ComicPage(path, stream);
		if (page->GetBitmapType() == wxBITMAP_TYPE_INVALID)
			delete page;
		else
			Pages.push_back(page);

		wxDELETE(stream);

		if ((PFCode = RARProcessFileW(rarFile, RAR_SKIP, NULL, NULL)) != 0) {
			closeRar(rarFile, &flags);
			throw ArchiveException(filename, ProcessFileError(PFCode, path));
		}

		progressDlg.Update(++progress);
	}

	closeRar(rarFile, &flags);
	
	// Wrong return code + needs password = wrong password given
	if (RHCode != ERAR_END_ARCHIVE && flags.Flags & 0x0080) 
		goto open_rar;

	postCtor();
	Create(); // create the wxThread
}
Exemple #11
0
wxInputStream * ComicBookRAR::ExtractStream(wxUint32 pageindex)
{
	HANDLE rarFile;
	int RHCode = 0, PFCode = 0;
	struct RARHeaderDataEx header;
	struct RAROpenArchiveDataEx flags;
	
	wxString page = Filenames->Item(pageindex);
	size_t length = 0;
	
	rarFile = openRar(&flags, &header, RAR_OM_EXTRACT);

	if (password)
		RARSetPassword(rarFile, password);

	while ((RHCode = RARReadHeaderEx(rarFile, &header)) == 0) {
#ifdef wxUSE_UNICODE
		if (page.IsSameAs(wxString(header.FileNameW))) {
#else // ASCII
		if (page.IsSameAs(header.FileName)) {
#endif
			length = header.UnpSize;
			break;	
		} else {
			if ((PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL)) != 0) {
				closeRar(rarFile, &flags);
				throw ArchiveException(filename, ProcessFileError(PFCode, page));
			}
		}
	}
	
	if (length == 0) { // archived file not found
		closeRar(rarFile, &flags);
		throw new ArchiveException(filename, page + wxT(" not found in this archive."));
	}
	if (RHCode) {
		closeRar(rarFile, &flags);
		throw new ArchiveException(filename, OpenArchiveError(PFCode));
	}

	wxUint8 *buffer = new wxUint8[length];
	wxUint8 *callBackBuffer = buffer;

	RARSetCallback(rarFile, CallbackProc, (long) &callBackBuffer);

	PFCode = RARProcessFile(rarFile, RAR_TEST, NULL, NULL);

	closeRar(rarFile, &flags);
	
	if (PFCode != 0)
		throw new ArchiveException(filename, ProcessFileError(PFCode, page));

	return new wxMemoryInputStream(buffer, length);
}

bool ComicBookRAR::TestPassword()
{
	HANDLE rarFile;
	int RHCode = 0, PFCode = 0;
	struct RARHeaderDataEx header;
	struct RAROpenArchiveDataEx flags;
	bool passwordCorrect = true;
	
	wxString page = Filenames->Item(0); // test using the first page
	
	rarFile = openRar(&flags, &header, RAR_OM_EXTRACT);

	if (password)
		RARSetPassword(rarFile, password);

	while ((RHCode = RARReadHeaderEx(rarFile, &header)) == 0) {
#ifdef wxUSE_UNICODE
		if (page.IsSameAs(wxString(header.FileNameW))) {
#else // ASCII
		if (page.IsSameAs(header.FileName)) {
#endif
			break;	
		} else {
			if ((PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL)) != 0) {
				closeRar(rarFile, &flags);
				throw ArchiveException(filename, ProcessFileError(PFCode, page));
			}
		}
	}
	
	if (RHCode != 0) {
		closeRar(rarFile, &flags);
		throw new ArchiveException(filename, OpenArchiveError(RHCode));
	}

	RARSetCallback(rarFile, TestPasswordCallbackProc, (long) &passwordCorrect);
	PFCode = RARProcessFile(rarFile, RAR_TEST, NULL, NULL);

	closeRar(rarFile, &flags);

	// If the password is wrong, RARProcessFile will return ERAR_BAD_DATA.  Of
	// course, it will also return ERAR_BAD_DATA when the first file in the archive
	// is corrupted.  How does one tell the difference?
	if (PFCode == ERAR_BAD_DATA)
		return false;

	return passwordCorrect;
}

wxString ComicBookRAR::OpenArchiveError(int Error)
{
	wxString prefix = wxT("Could not open ") + filename;
	switch(Error) {
		case ERAR_NO_MEMORY:
			return wxString(prefix + wxT(": out of memory"));
		case ERAR_EOPEN:
			return prefix;
		case ERAR_BAD_ARCHIVE:
			return wxString(prefix + wxT(": it is not a valid RAR archive"));
		case ERAR_BAD_DATA:
			return wxString(prefix + wxT(": archive header broken"));
		case ERAR_UNKNOWN:
			return wxString(prefix + wxT(": unknown error"));
		default:
			return prefix;
	}
}
void extract(const std::string & archive_name, const std::string & dest_dir, const std::string & password)
{
	bool already_extracted;
#ifdef WINDOWS
	already_extracted = contains(extracted_files, archive_name, false);
#else
	already_extracted = contains(extracted_files, archive_name, true);
#endif

	if (already_extracted)
		return;

	fprintf(stdout, "Extracting %s to %s\n", archive_name.c_str(), dest_dir.c_str());

	HANDLE archive;
	struct RAROpenArchiveData data;
	struct RARHeaderData header;

	if (!fileExists(archive_name))
		return;

	if (!createDir(dest_dir))
		return;

	data.ArcName = (char *)archive_name.c_str();
	data.OpenMode = RAR_OM_EXTRACT;
	data.CmtBuf = NULL;
	data.CmtBufSize = 0;


	//fprintf(stdout, "Opening %s\n", argv[1]);
	archive = RAROpenArchive(&data);

	if (!archive || data.OpenResult != 0)
	{
		fprintf(stderr, "Couldn't open %s\n", archive_name.c_str());
		return;
	}

	header.CmtBuf = NULL;

	//fprintf(stdout, "Clearing password\n");
	RARSetPassword(archive, (char*)password.c_str());

	MultipartInfo info;
	//fprintf(stdout, "Setting callback\n");
	RARSetCallback(archive, &missing_file, (ssize_t)&info);

	//fprintf(stdout, "Starting to process file\n");

	// the complete path to the file to be extracted
	std::string dest_path;

	start_timer();
	while (!RARReadHeader(archive, &header))
	{
		dest_path = dest_dir + PATH_SEP + header.FileName;
		if (pathExists(dest_path))
		{
			fprintf(stderr, "Skpping %s\n",  header.FileName);
			continue;
		}
		if (RARProcessFile(archive, RAR_EXTRACT, (char *)dest_dir.c_str(), NULL))
		{
			/*if (!pathExists(dest_path))
			{
				fprintf(stderr, "Couldn't create %s\n",  dest_path.c_str());
				break;
			}*/

			if (elapsed(five_seconds))
			{
				info.bytes_processed = 0;
				start_timer();
			}
		}
		else
		{
			break;
		}

		// (bytes / (1024 * 1024) = MBytes
		// ms / 1000 = s
		// (bytes / (1024 * 1024) / (ms / 1000) = 0.00095367431640625 * bytes/ms
		//fprintf(stdout, "%d MB/s", (int)(0.00095367431640625 * (info.bytes_processed / calc_elapsed())));
	}
	//fprintf(stdout, "Closing file\n");
	RARCloseArchive(archive);

	extracted_files.push_back(archive_name);
}