%% options # __CHANGE__ 001: Correct copyright owner if necessary. copyright owner = Dirk Krause # __CHANGE__ 003: Correct copyright year(s) if necessary. copyright year = 2015-xxxx # __CHANGE__ 002: Correct license type if necessary. # Use "bsd", "gpl", "lgpl", or "commercial". license = bsd %% wx-gui type = frame contents = mainSizer icon = wxdkfcs_icon status bar = 1 sTexts[8] menu bar = mbMain [wxMenuBar mbMain] contents = menuFile contents = menuHelp [wxMenu menuFile] text = sTexts[0] contents = miFileOpen contents = miFileExit [wxMenuItem miFileOpen] id = Dk4FcsFrame_Open text = sTexts[23] tip = sTexts[24] [wxMenuItem miFileExit] id = Dk4FcsFrame_Quit text = sTexts[1] tip = sTexts[2] [wxMenu menuHelp] text = sTexts[3] contents = miHelpAbout contents = miHelpContents [wxMenuItem miHelpAbout] id = Dk4FcsFrame_Help_About text = sTexts[4] tip = sTexts[5] [wxMenuItem miHelpContents] id = Dk4FcsFrame_Help_Contents text = sTexts[6] tip = sTexts[7] [wxBoxSizer mainSizer] direction = horizontal grow = yes proportion = 1 contents = $space(10) contents = verticalSizer contents = $space(10) [wxBoxSizer verticalSizer] direction = vertical grow = yes proportion = 1 contents = $space(10) contents = contentsSizer contents = $space(10) [wxGridBagSizer contentsSizer] grid = 5 5 grow = yes proportion = 1 growable column = 1 growable row = 1 contents = lFile 0 0 1 1 right contents = tFile . +1 1 1 left contents = gResults +1 0 1 2 left [wxStaticText lFile] text = sTexts[13] [wxStaticText tFile] text = wxT("") [wxGrid gResults] grow = yes proportion = 1 text style = readonly minimum size = 300 200 column head = sTexts[21] row head = sTexts[14] row head = sTexts[15] row head = sTexts[16] row head = sTexts[17] row head = sTexts[18] row head = sTexts[19] row head = sTexts[20] cell data = 0 0 sNlWx[17] cell data = 1 0 sNlWx[17] cell data = 2 0 sNlWx[17] cell data = 3 0 sNlWx[17] cell data = 4 0 sNlWx[17] cell data = 5 0 sNlWx[17] cell data = 6 0 sNlWx[17] grid style = autosize-data autosize-labels %% header start %% class start class Dk4FcsFrame : public Dk4WxFrame { private: /** Event table for frame. */ DECLARE_EVENT_TABLE() protected: /** Autostart controller. */ Dk4WxAutostartController oAsc; /** Localized texts. */ wxChar const * const *sTexts; /** Non-localized texts. */ wxChar const * const *sNlWx; /** Non-localized texts. */ dkChar const * const *sNlDk; /** File name to process. */ wxString sFileName; /** Default directory. */ wxString sDirectory; /** Flag: Active (responding to idle events). */ bool bActive; %% class end public: /** Constructor. @param wxid Window ID. @param applicationHelper Application helper object. @param hc Help controller for online help. @param argc Number of command line arguments. @param argv Command line arguments array. @param localizedTexts Localized wxChar texts. @param nlWx Non-localized wxChar texts. @param nlDk Non-localized dkChar texts. */ Dk4FcsFrame( int wxid, Dk4WxApplicationHelper *applicationHelper, Dk4WxHelpController *hc, int argc, wxChar **argv, wxChar const * const *localizedTexts, wxChar const * const *nlWx, dkChar const * const *nlDk ); /** Destructor. */ ~Dk4FcsFrame(); /** Check whether we can close the window. @param isFinal Flag: Last main window to close. */ bool CanClose(bool isFinal); /** Open a file and create checksums for it. @param event Event to process. */ void OnOpen(wxCommandEvent & event); /** Handler for File/Exit. @param event Event to process. */ void OnQuit(wxCommandEvent & event); /** Handler for Help/About. @param event Event to process. */ void OnAbout(wxCommandEvent & event); /** Handler for Help/Contents. @param event Event to process. */ void OnHelpContents(wxCommandEvent & event); /** Handler for idle events. */ void OnIdle(wxIdleEvent & event); /* Event handlers for further events. */ /* Further methods. */ private: /** Convert binary data to hex notation and set grid cell. @param rowno Row number in table. @param buf Buffer containing binary data. @param bytes Number of bytes in buffer. */ void SetCellValueBinary( int rowno, unsigned char *buf, size_t bytes ); /** Produce checksums. */ bool RunChecksumming(void); }; %% header end %% module start #include "wxdkfcs.h" #include "dk4mem.h" #include "dk4verswx.h" #if DK4_HAVE_OPENSSL_MD5_H #ifndef OPENSSL_MD5_H_INCLUDED #include #define OPENSSL_MD5_H_INCLUDED 1 #endif #endif #if DK4_HAVE_OPENSSL_RIPEMD_H #ifndef OPENSSL_RIPEMD_H_INCLUDED #include #define OPENSSL_RIPEMD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_OPENSSL_SHA_H #ifndef OPENSSL_SHA_H_INCLUDED #include #define OPENSSL_SHA_H_INCLUDED 1 #endif #endif #if !defined(__WXMSW__) #include "dkicon.xpm" #endif $!trace-include BEGIN_EVENT_TABLE(Dk4FcsFrame, wxFrame) EVT_MENU(Dk4FcsFrame_Quit, Dk4FcsFrame::OnQuit) EVT_MENU(Dk4FcsFrame_Open, Dk4FcsFrame::OnOpen) EVT_MENU(Dk4FcsFrame_Help_About, Dk4FcsFrame::OnAbout) EVT_MENU(Dk4FcsFrame_Help_Contents, Dk4FcsFrame::OnHelpContents) EVT_IDLE(Dk4FcsFrame::OnIdle) END_EVENT_TABLE() typedef struct { /* Message digests contexts. */ #if DK4_HAVE_OPENSSL_MD5_H MD5_CTX md5; /**< MD5 context. */ #endif #if DK4_HAVE_OPENSSL_RIPEMD_H RIPEMD160_CTX ripemd160; /**< RIPEMD-160 context. */ #endif #if DK4_HAVE_OPENSSL_SHA_H SHA_CTX sha; /**< SHA-1 context. */ #if DK4_HAVE_SHA224 SHA256_CTX sha224; /**< SHA-224 context. */ #endif #if DK4_HAVE_SHA256 SHA256_CTX sha256; /**< SHA-256 context. */ #endif #if DK4_HAVE_SHA384 SHA512_CTX sha384; /**< SHA-384 context. */ #endif #if DK4_HAVE_SHA512 SHA512_CTX sha512; /**< SHA-512 context. */ #endif #endif int iMd5; /**< Flag: Can use Md5. */ int iRipemd160; /**< Flag: Can use RIPEMD-160. */ int iSha1; /**< Flag: Can use SHA-1. */ int iSha224; /**< Flag: Can use SHA-224. */ int iSha256; /**< Flag: Can use SHA-256. */ int iSha384; /**< Flag: Can use SHA-384. */ int iSha512; /**< Flag: Can use SHA-512. */ } MULTI_CTX; static const wxChar dk4fcs_frame_version[] = { DKT_VERSION_WX }; static void multi_ctx_init(MULTI_CTX *mptr) { $? "+ multi_ctx_init" DK4_MEMRES(mptr, sizeof(MULTI_CTX)); #if DK4_HAVE_OPENSSL_MD5_H if (1 == MD5_Init(&(mptr->md5))) { mptr->iMd5 = 1; $? ". MD5" } #endif #if DK4_HAVE_OPENSSL_RIPEMD_H if (1 == RIPEMD160_Init(&(mptr->ripemd160))) { mptr->iRipemd160 = 1; $? ". RIPEMD-160" } #endif #if DK4_HAVE_OPENSSL_SHA_H if (1 == SHA1_Init(&(mptr->sha))) { mptr->iSha1 = 1; $? ". SHA-1" } #if DK4_HAVE_SHA224 if (1 == SHA224_Init(&(mptr->sha224))) { mptr->iSha224 = 1; $? ". SHA-224" } #endif #if DK4_HAVE_SHA256 if (1 == SHA256_Init(&(mptr->sha256))) { mptr->iSha256 = 1; $? ". SHA-256" } #endif #if DK4_HAVE_SHA384 if (1 == SHA384_Init(&(mptr->sha384))) { mptr->iSha384 = 1; $? ". SHA-384" } #endif #if DK4_HAVE_SHA512 if (1 == SHA512_Init(&(mptr->sha512))) { mptr->iSha512 = 1; $? ". SHA-512" } #endif #endif $? "- multi_ctx_init" } static void multi_ctx_add(MULTI_CTX *mptr, void *buffer, size_t sz) { $? "+ multi_ctx_add" #if DK4_HAVE_OPENSSL_MD5_H if (1 != MD5_Update(&(mptr->md5), buffer, (unsigned long)sz)) { mptr->iMd5 = 0; $? "! MD5" } #endif #if DK4_HAVE_OPENSSL_RIPEMD_H if (1 != RIPEMD160_Update(&(mptr->ripemd160), buffer, (unsigned long)sz)) { mptr->iRipemd160 = 0; $? "! RIPEMD-160" } #endif #if DK4_HAVE_OPENSSL_SHA_H if (1 != SHA1_Update(&(mptr->sha), buffer, (unsigned long)sz)) { mptr->iSha1 = 0; $? "! SHA-1" } #if DK4_HAVE_SHA224 if (1 != SHA224_Update(&(mptr->sha224), buffer, (unsigned long)sz)) { mptr->iSha224 = 0; $? "! SHA-224" } #endif #if DK4_HAVE_SHA256 if (1 != SHA256_Update(&(mptr->sha256), buffer, (unsigned long)sz)) { mptr->iSha256 = 0; $? "! SHA-256" } #endif #if DK4_HAVE_SHA384 if (1 != SHA384_Update(&(mptr->sha384), buffer, (unsigned long)sz)) { mptr->iSha384 = 0; $? "! SHA-384" } #endif #if DK4_HAVE_SHA512 if (1 != SHA512_Update(&(mptr->sha512), buffer, (unsigned long)sz)) { mptr->iSha512 = 0; $? "! SHA-512" } #endif #endif $? "- multi_ctx_add" } /** Thread runs while progress dialog is shown. This is a ``fire and forget'' thread destroying itself after running. */ class Dk4FcsThread : public wxThread { protected: /** Buffer for reading input file. */ unsigned char buf[4096]; /** Progress dialog. */ Dk4WxProgressDialog *pPd; /** Multiple message digest contexts. */ MULTI_CTX *pCtx; /** File to read from. */ wxFile *pWxf; public: /** Constructor. @param pd Pointer to progress dialog. @param ctx Pointer to multiple digest contexts collection. @param wxf Pointer to file we read from. */ Dk4FcsThread( Dk4WxProgressDialog *pd, MULTI_CTX *ctx, wxFile *wxf ); /** Thread function. @return Pointer which is ignored. */ virtual void * Entry(); /** Method executed at end of thread. */ virtual void OnExit(); }; Dk4FcsThread::Dk4FcsThread( Dk4WxProgressDialog *pd, MULTI_CTX *ctx, wxFile *wxf ) { $? "+ Dk4FcsThread::Dk4FcsThread" pPd = pd; pCtx = ctx; pWxf = wxf; $? "- Dk4FcsThread::Dk4FcsThread" } void * Dk4FcsThread::Entry() { wxFileOffset fileSize = (wxFileOffset)0UL; wxFileOffset bytesRead = (wxFileOffset)0UL; size_t bytes = 0U; int gauge = 0; int ogauge = 0; bool canContinue = true; bool success = true; $? "+ Dk4FcsThread::Entry" fileSize = pWxf->Length(); while(canContinue) { $? ". loop start" if (pPd->CanContinue()) { $? ". can continue" bytes = pWxf->Read(buf, sizeof(buf)); $? ". bytes = %lu", (unsigned long) bytes if (0 < bytes) { $? ". positive number of bytes" if ((size_t)(wxInvalidOffset) != bytes) { $? ". have bytes" multi_ctx_add(pCtx, buf, bytes); bytesRead += (wxFileOffset)bytes; if (bytesRead >= fileSize) { gauge = 1000; $? ". gauge = %d", gauge } else { gauge = (int)((1000.0 * (double)bytesRead) / ((double)fileSize)); if (1000 < gauge) { gauge = 1000; $? ". gauge = %d", gauge } } if (gauge != ogauge) { $? ". update gauge in progress dialog" pPd->SetGauge(gauge); ogauge = gauge; } } else { $? "! read error" canContinue = false; success = false; } } else { $? ". 0 bytes, finished" canContinue = false; } } else { $? ". aborted" canContinue = false; success = false; } $? ". loop end" } $? ". loop finished" pPd->EndProcessing(success); $? "- Dk4FcsThread::Entry" return NULL; } void Dk4FcsThread::OnExit() { $? "+ Dk4FcsThread::OnExit" $? "- Dk4FcsThread::OnExit" } %% constructor start Dk4FcsFrame::Dk4FcsFrame( int wxid, Dk4WxApplicationHelper *applicationHelper, Dk4WxHelpController *hc, int argc, wxChar **argv, wxChar const * const *localizedTexts, wxChar const * const *nlWx, dkChar const * const *nlDk ) : Dk4WxFrame(nlWx[0], applicationHelper, hc, wxid) { $? "+ Dk4FcsFrame" /* Further local variables. */ /* Initialize further local variables. */ sTexts = localizedTexts; sNlWx = nlWx; sNlDk = nlDk; #if defined(__WXMSW__) wxIcon wxdkfcs_icon(sNlWx[4]); #else wxIcon wxdkfcs_icon(xpm_dkicon); #endif /* Initialize further class members. */ bActive = true; sFileName = wxEmptyString; sDirectory = wxEmptyString; if (1 < argc) { sFileName = argv[1]; oAsc.SetAutoStart(true); { wxFileName wxfn(sFileName); sDirectory = wxfn.GetPath(); } #if 0 /* Just to test auto exit. */ oAsc.SetAutoExit(true); #endif } %% constructor end if(dkctGUILayoutOK) { SetTitle(nlWx[0]); if (1 < argc) { tFile->SetLabel(sFileName); } #if 0 RestorePosition(); #endif gResults->SetCellValue(0, 0, sNlWx[5]); gResults->SetCellValue(1, 0, sNlWx[5]); gResults->SetCellValue(2, 0, sNlWx[5]); gResults->SetCellValue(3, 0, sNlWx[5]); gResults->SetCellValue(4, 0, sNlWx[5]); gResults->SetCellValue(5, 0, sNlWx[5]); gResults->SetCellValue(6, 0, sNlWx[5]); } /* Release resources allocated by local variables. */ $? "- Dk4FcsFrame" } %% module end Dk4FcsFrame::~Dk4FcsFrame() { $? "+ ~Dk4FcsFrame" /* Release resources allocated by further class members. */ $? "- ~Dk4FcsFrame" } bool Dk4FcsFrame::CanClose(bool isFinal) { bool back = true; $? "+ CanClose" $? "- CanClose" return back; } void Dk4FcsFrame::OnQuit(wxCommandEvent & event) { $? "+ OnQuit" Close(); $? "- OnQuit" } void Dk4FcsFrame::OnAbout(wxCommandEvent & event) { wxString text(wxT("")); wxString title(wxT("")); $? "+ OnAbout" /* Construct message text. */ text.Append(sNlWx[0]); text.Append(sNlWx[7]); text.Append(dk4fcs_frame_version); #if 0 text.Append(sNlWx[1]); #endif text.Append(sNlWx[8]); text.Append(sTexts[9]); text.Append(sNlWx[2]); text.Append(sNlWx[8]); text.Append(sNlWx[8]); text.Append(sTexts[11]); text.Append(sNlWx[8]); text.Append(sNlWx[9]); text.Append(sNlWx[8]); text.Append(sNlWx[8]); text.Append(sTexts[12]); text.Append(sNlWx[8]); text.Append(sNlWx[10]); text.Append(sNlWx[8]); text.Append(sNlWx[11]); text.Append(sNlWx[8]); text.Append(sNlWx[12]); text.Append(sNlWx[8]); text.Append(sNlWx[13]); text.Append(sNlWx[8]); text.Append(sNlWx[14]); text.Append(sNlWx[8]); text.Append(sNlWx[15]); text.Append(sNlWx[8]); text.Append(sNlWx[16]); text.Append(sNlWx[8]); text.Append(sNlWx[8]); text.Append(sNlWx[18]); text.Append(sNlWx[8]); text.Append(sNlWx[19]); text.Append(sNlWx[8]); text.Append(sNlWx[20]); text.Append(sNlWx[8]); text.Append(sNlWx[21]); text.Append(sNlWx[8]); text.Append(sNlWx[22]); /* Construct dialog box title. */ title.Append(sTexts[10]); title.Append(sNlWx[0]); /* Show dialog box. */ wxMessageBox(text, title); $? "- OnAbout" } void Dk4FcsFrame::OnHelpContents(wxCommandEvent & event) { $? "+ OnHelpContents" DisplayContents(); $? "- OnHelpContents" } /* __CHANGE__ 017: Event handlers for further events. */ /** Hexadecimal digits. */ static const wxChar hexdig[] = { wxT("0123456789abcdef") }; void Dk4FcsFrame::SetCellValueBinary( int rowno, unsigned char *buf, size_t bytes ) { wxChar obuf[144]; wxChar *obptr; unsigned short u; $? "+ SetCellValueBinary %lu", (unsigned long)bytes if (64 >= bytes) { obptr = obuf; while(bytes--) { u = (unsigned short)(*buf); u = u >> 4; u &= 15; *(obptr++) = hexdig[u]; $? ". hexdig = %!wc", hexdig[u] u = (unsigned short)(*buf); u &= 15; *(obptr++) = hexdig[u]; $? ". hexdig = %!wc", hexdig[u] buf++; } *obptr = wxT('\0'); { wxString testString(obuf); gResults->SetCellValue(rowno, 0, testString); } } else { /* ERROR: message digest too long, need larger obuf! */ } $? "- SetCellValueBinary" } bool Dk4FcsFrame::RunChecksumming(void) { MULTI_CTX ctx; // Digests contexts collection unsigned char obuf[128]; // Binary message digests Dk4WxProgressDialog *pd = NULL; // Progress dialog Dk4FcsThread *pt = NULL; // Thread int res = 0; // Operation result bool updateTable = false; // Flag: Update the table $? "+ RunChecksumming" /* Reset all values. */ gResults->BeginBatch(); gResults->SetCellValue(0, 0, sNlWx[5]); gResults->SetCellValue(1, 0, sNlWx[5]); gResults->SetCellValue(2, 0, sNlWx[5]); gResults->SetCellValue(3, 0, sNlWx[5]); gResults->SetCellValue(4, 0, sNlWx[5]); gResults->SetCellValue(5, 0, sNlWx[5]); gResults->SetCellValue(6, 0, sNlWx[5]); gResults->EndBatch(); gResults->ForceRefresh(); Refresh(); Update(); /* Attempt to build checksum. */ if (wxFile::Exists(sFileName)) { $? ". file exists" { wxFile wxf(sFileName); if (wxf.IsOpened()) { $? ". file opened" pd = new Dk4WxProgressDialog(this, pAppHelp); if (NULL != pd) { $? ". progress dialog" pt = new Dk4FcsThread(pd, &ctx, &wxf); if (NULL != pt) { $? ". thread instance" multi_ctx_init(&ctx); if(wxTHREAD_NO_ERROR == pt->Create()) { $? ". thread create" pt->SetPriority(WXTHREAD_DEFAULT_PRIORITY); pt->Run(); res = pd->ShowModal(); if (wxID_OK == res) { $? ". success" updateTable = true; } else { $? "! aborted" /* !!!!! ERROR: Aborted by user */ } } else { $? "! thread create" delete(pt); pt = NULL; /* !!!!! ERROR: Failed to create thread */ } } else { $? "! thread instance" /* !!!!! ERROR: No thread */ } pd->Destroy(); } else { $? "! progress dialog" /* !!!!! ERROR: No progress dialog */ } } else { $? "! failed to open file" /* !!!!! ERROR: Failed to open file */ } } if (updateTable) { $? ". table update" gResults->BeginBatch(); #if DK4_HAVE_OPENSSL_MD5_H if (0 != ctx.iMd5) { $? ". MD5" if (1 == MD5_Final(obuf, &(ctx.md5))) { $? ". MD5 final" SetCellValueBinary(0, obuf, 16); } } #endif #if DK4_HAVE_OPENSSL_RIPEMD_H if (0 != ctx.iRipemd160) { $? ". RIPEMD-160" if (1 == RIPEMD160_Final(obuf, &(ctx.ripemd160))) { SetCellValueBinary(1, obuf, 20); $? ". RIPEMD-160 final" } } #endif #if DK4_HAVE_OPENSSL_SHA_H if (0 != ctx.iSha1) { $? ". SHA-1" if (1 == SHA1_Final(obuf, &(ctx.sha))) { $? ". SHA-1 final" SetCellValueBinary(2, obuf, 20); } } #if DK4_HAVE_SHA224 if (0 != ctx.iSha224) { $? ". SHA-224" if (1 == SHA224_Final(obuf, &(ctx.sha224))) { $? ". SHA-224 final" SetCellValueBinary(3, obuf, 28); } } #endif #if DK4_HAVE_SHA256 if (0 != ctx.iSha256) { $? ". SHA-256" if (1 == SHA256_Final(obuf, &(ctx.sha256))) { $? ". SHA-256 final" SetCellValueBinary(4, obuf, 32); } } #endif #if DK4_HAVE_SHA384 if (0 != ctx.iSha384) { $? ". SHA-384" if (1 == SHA384_Final(obuf, &(ctx.sha384))) { $? ". SHA-384 final" SetCellValueBinary(5, obuf, 48); } } #endif #if DK4_HAVE_SHA512 if (0 != ctx.iSha512) { $? ". SHA-512" if (1 == SHA512_Final(obuf, &(ctx.sha512))) { $? ". SHA-512 final" SetCellValueBinary(6, obuf, 64); } } #endif #endif gResults->AutoSize(); gResults->EndBatch(); gResults->ForceRefresh(); { int x, y, w, h; GetPosition(&x, &y); GetSize(&w, &h); mainSizer->Fit(this); SetSize(x, y, w, h); } Refresh(); Update(); } else { $? ". no table update" } } else { $? "! file does not exist" /* !!!!! ERROR: File does not exist */ } $? "- RunChecksumming" return updateTable; } void Dk4FcsFrame::OnOpen(wxCommandEvent & event) { bool canRun = true; int res = 0; $? "+ OnOpen" { wxFileDialog dlg(this, sTexts[22], sDirectory); res = dlg.ShowModal(); if (wxID_OK == res) { sFileName = dlg.GetPath(); tFile->SetLabel(sFileName); { wxFileName wxfn(sFileName); sDirectory = wxfn.GetPath(); } canRun = true; } else { canRun = false; } } if (canRun) { (void)RunChecksumming(); } $? "- OnOpen" } void Dk4FcsFrame::OnIdle(wxIdleEvent & event) { bool success = false; $? "+ OnIdle" if (bActive) { /* event.RequestMore(); */ switch (oAsc.GetReaction()) { #if 0 case DK4WX_AUTOSTART_REACTION_IGNORE : { } break; #endif case DK4WX_AUTOSTART_REACTION_START : { oAsc.StartProcessing(); success = RunChecksumming(); oAsc.EndProcessing(success); } break; case DK4WX_AUTOSTART_REACTION_MORE : { event.RequestMore(); } break; case DK4WX_AUTOSTART_REACTION_EXIT : { bActive = false; Close(); } break; } } event.Skip(); $? "- OnIdle" }