Source file: /~heha/mb-iwp/bin2graf.zip/src/bin2graf.cpp

/*
 Ein Hilfsprogramm, um bei unbekanntem Format einer Binär-Messdaten-Datei
 die eigentlichen Diagrammdaten auszulesen.
 Wenn sich ein sinnvoller Kurvenzug ergibt, wurde der richtige
 Angangs-Offset, End-Offset, Inkrement sowie Datentyp gefunden.
 Anmerkung: Zumeist werden float-Daten gespeichert (4 Byte pro Wert),
 manchmal double (8 Byte pro Wert), zumeist von Matlab.
 
 Hier auch mal eine Demonstration, um ohne Laufzeitbibliothek
 einen eigenen "std::vector" als variables Array nachzuahmen.
 Nur die unbedingt benötigten Funktionen und ohne Bereichsüberlauftest.
*/

#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501	// WM_THEMECHANGED aktivieren
#include <windows.h>
#include <windowsx.h>	// Makros
#include <commdlg.h>	// Datei öffnen/speichern
#include <commctrl.h>	// Listenfenster für die Zeitschritte
#include <shlwapi.h>	// nützliche Funktionen
#include <shellapi.h>	// HDROP, DragQueryFile()
#include <mmsystem.h>

#include <stdio.h>
#include <tchar.h>

#include "vector.h"

#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#define nobreak

#ifdef _DEBUG
void _cdecl DebugPrintf(PCSTR s,...) {
 char buf[256];
 va_list va;
 va_start(va,s);
 _vsnprintf(buf,elemof(buf),s,va);
 OutputDebugStringA(buf);
}
# define _debug(x) DebugPrintf x
#else
# define _debug(x)
#endif

HINSTANCE ghInstance;
HWND ghMainWnd;
HWND ghDlgWnd;
HWND DispInfoDlg;
TCHAR StdMBoxTitle[64];

/****************
 * aus WUTILS.C *
 ****************/

//Win32-typische Strukturen mit DWORD-Ausrichtung initialisieren
void _fastcall InitStruct(LPVOID p, UINT len) {
 LPUINT p2=(LPUINT)p;		// sonst hat C++ Verdauungsstörungen
 *p2=len; len/=sizeof(UINT); len--;
 if (len) do *++p2=0; while (--len);
}

int vMBox(HWND Wnd, LPCTSTR Text, UINT Type, va_list va) {
 TCHAR buf[256],buf2[256];
 if (!((DWORD_PTR)Text>>16)) {
  LoadString(ghInstance,(UINT)(DWORD_PTR)Text,buf2,elemof(buf2));
  Text=buf2;
 }
 _vsntprintf(buf,elemof(buf),Text,va);
 return MessageBox(Wnd,buf,StdMBoxTitle,Type);
}

int _cdecl MBox(HWND Wnd, LPCTSTR Text, UINT Type, ...) {
 return vMBox(Wnd,Text,Type,(va_list)(&Type+1));
}

#define WM_OPENFILE (WM_USER+101)	// wParam=FilterIndex, HIWORD=Multi-Flag, 

// Diese Universalroutine müsste mal „kugelsicher“ und universell geschrieben werden…
// Einmal SDI, einmal MDI
void OnFileOpen(HWND Wnd) {
#define BUFSIZE 8192
 OPENFILENAME ofn;
 TCHAR sFilter[256];
 LPTSTR sFileNames;
 sFilter[LoadString(ghInstance,2,sFilter,elemof(sFilter)-1)+1]=0;
 sFileNames=(LPTSTR)LocalAlloc(LPTR,BUFSIZE*sizeof(TCHAR));
 InitStruct(&ofn,sizeof(ofn));
 ofn.hwndOwner=Wnd;
 ofn.lpstrFilter=sFilter;
 ofn.lpstrFile=sFileNames;
 ofn.nMaxFile=BUFSIZE;
 ofn.Flags=OFN_ALLOWMULTISELECT|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
 if (GetOpenFileName(&ofn)) {
  UINT len;
// herausfinden, ob Single- oder Multi-Select
  len=lstrlen(sFileNames);
  if (sFileNames[len+1]) {	// Multi-Select
   LPTSTR d,s;
   TCHAR FileName[MAX_PATH];
   lstrcpyn(FileName,sFileNames,elemof(FileName));	// Pfad kopieren
   d=PathAddBackslash(FileName);
   s=sFileNames+ofn.nFileOffset;
   for (UINT i=0; *s; s+=lstrlen(s)+1, i++) {
    lstrcpyn(d,s,(int)(FileName+elemof(FileName)-d));
    SendMessage(Wnd,WM_OPENFILE,i,(LPARAM)FileName);
   }
  }else SendMessage(Wnd,WM_OPENFILE,0,(LPARAM)sFileNames);
 }
 LocalFree(sFileNames);
#undef BUFSIZE
}

enum eTypeCode {i8,u8,i16,u16,i32,u32,i64,u64,f32,f64};

struct {
 UINT a,e;	// Anfang und Ende der Daten, in Bytes
 UINT g;	// Granularität (1 = Byte, 2 = WORD usw.)
 eTypeCode t;	// Interpretationsweise
} gDispInfo;

struct {
 HANDLE f;	// Datei-Handle
 HANDLE m;	// Mapping-Handle
 LPVOID p;	// Map-Zeiger
 DWORD  l;	// Datei-Länge (in Bytes)
} gFile;

void SetDlgItemHex(HWND Wnd, UINT id, UINT val) {
 TCHAR s[32];
 _sntprintf(s,elemof(s),T("0x%X"),val);
 if (id!=(UINT)-1) SetDlgItemText(Wnd,id,s); else SetWindowText(Wnd,s);
}

bool GetDlgItemHex(HWND Wnd, UINT id, UINT*val) {
 TCHAR s[32];
 if (id!=(UINT)-1) GetDlgItemText(Wnd,id,s,elemof(s)); else GetWindowText(Wnd,s,elemof(s));
 return _stscanf(s,T("%i"),val)==1;
}

BOOL CALLBACK DispInfoDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
   DispInfoDlg=Wnd;
   SetDlgItemHex(Wnd,16,gDispInfo.a);
   SetDlgItemHex(Wnd,17,gDispInfo.e);
   HWND hCombo=GetDlgItem(Wnd,18);
   ComboBox_ResetContent(hCombo);
   TCHAR s[256],*p;
   for (int i=1; i<=32; i<<=1) {
    _sntprintf(s,elemof(s),T("%d"),i);
    ComboBox_AddString(hCombo,s);
   }
   SetDlgItemInt(Wnd,18,gDispInfo.g,FALSE);
   hCombo=GetDlgItem(Wnd,19);
   ComboBox_ResetContent(hCombo);
   s[LoadString(ghInstance,3,s,elemof(s)-1)+1]=0;
   for(p=s;*p;p+=lstrlen(p)+1) ComboBox_AddString(hCombo,p);
   ComboBox_SetCurSel(hCombo,gDispInfo.t);
  }return TRUE;
  
  case WM_ACTIVATE: ghDlgWnd=wParam?Wnd:0; break;
  
  case WM_COMMAND: switch (wParam) {
   case 1:
   case 2: DestroyWindow(Wnd); break;
   case MAKELONG(16,EN_CHANGE): {
    GetDlgItemHex((HWND)lParam,-1,&gDispInfo.a);
    InvalidateRect(ghMainWnd,NULL,TRUE);
   }break;
   case MAKELONG(17,EN_CHANGE): {
    GetDlgItemHex((HWND)lParam,-1,&gDispInfo.e);
    InvalidateRect(ghMainWnd,NULL,TRUE);
   }break;
   case MAKELONG(18,CBN_EDITUPDATE):
   case MAKELONG(18,CBN_SELCHANGE): {
    GetDlgItemHex((HWND)lParam,-1,&gDispInfo.g);
    InvalidateRect(ghMainWnd,NULL,TRUE);
   }break;
   case MAKELONG(19,CBN_SELCHANGE): {
    gDispInfo.t=(eTypeCode)ComboBox_GetCurSel((HWND)lParam);
    InvalidateRect(ghMainWnd,NULL,TRUE);
   }
  }break;
  
  case WM_DESTROY: DispInfoDlg=0; break;
 }
 return FALSE;
}

void HandleOpenFile(LPTSTR FileName) {
 gFile.f=CreateFile(FileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
 if (gFile.f==INVALID_HANDLE_VALUE) return;
 gFile.l=GetFileSize(gFile.f,NULL);
 if (!gFile.l) return;
 gFile.m=CreateFileMapping(gFile.f,NULL,PAGE_READONLY,0,0,NULL);
 gFile.p=MapViewOfFile(gFile.m,FILE_MAP_READ,0,0,0);
 gDispInfo.a=0;//0x7568;
 gDispInfo.e=gFile.l;//0x9560;
 gDispInfo.g=1;
 gDispInfo.t=u8;
 if (ghDlgWnd) PostMessage(ghDlgWnd,WM_INITDIALOG,0,0);
}

union PTYP{
 void *v;
 char *c;
 unsigned char *b;
 short *s;
 unsigned short *us;
 long *l;
 unsigned long *ul;
 __int64 *ll;
 unsigned __int64 *ull;
 float *f;
 double *lf;
 double getDouble(enum eTypeCode);
};

double PTYP::getDouble(enum eTypeCode tc) {
 switch (tc) {
  case i8: return *c;
  case u8: return *b;
  case i16: return *s;
  case u16: return *us;
  case i32: return *l;
  case u32: return *ul;
  case i64: return (double)*ll;
  case u64: return (double)*ull;
  case f32: return *f;
  case f64: return *lf;
 }
 return 0;
}

#ifdef _M_IX86
__forceinline __int64 rndint64(double f) {
 __int64 i;
 _asm	fld	f
 _asm	fistp	i
 return i;
}
#endif
#define rndint(x) (int)rndint64(x)
extern "C" int _fltused;
int _fltused;

void OnPaint(HDC dc) {
 RECT r;
 GetClientRect(ghMainWnd,&r);
 PTYP p;
 POINT *pa;
 int x;
 double ymin,ymax;
 if (!gDispInfo.g) return;
 if (gDispInfo.a>=gDispInfo.e) return;
 vector<POINT>a((gDispInfo.e-gDispInfo.a)/gDispInfo.g);	// Anzahl Punkte
 ymin=1E100;
 ymax=-ymin;
 for (p.c=(char*)gFile.p+gDispInfo.a,x=0; x<a.size(); p.c+=gDispInfo.g,x++) {
  double y=p.getDouble(gDispInfo.t);
  if (ymin>y) ymin=y;
  if (ymax<y) ymax=y;
 }
 ymax-=ymin;
 for (pa=a, p.c=(char*)gFile.p+gDispInfo.a, x=0; x<a.size(); p.c+=gDispInfo.g,x++) {
  pa->x=MulDiv(x,r.right,a.size());
  pa->y=rndint((p.getDouble(gDispInfo.t)-ymin)*r.bottom/ymax);
  pa++;
 }
 Polyline(dc,a,a.size());
 WCHAR s[32];
 TextOutW(dc,0,0,s,_snwprintf(s,elemof(s),L"%G",ymax));
 SetTextAlign(dc,TA_BOTTOM);
 TextOutW(dc,0,r.bottom,s,_snwprintf(s,elemof(s),L"%G",ymin));
}

/********************
 * Fenster-Prozedur *
 ********************/
LRESULT CALLBACK MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 switch (Msg) {
  case WM_CREATE: {
   ghMainWnd=Wnd;
   LPCREATESTRUCT cs=(LPCREATESTRUCT)lParam;
   if (cs->lpCreateParams) {	// Kommandozeile: zerpflücken
    LPTSTR arg=PathGetArgs((LPTSTR)cs->lpCreateParams);
    if (*arg) SendMessage(Wnd,WM_OPENFILE,0,(LPARAM)arg);
   }
  }break;
  
  case WM_CLOSE: PostQuitMessage(0); break;
  
  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 2: SendMessage(Wnd,WM_CLOSE,0,0); break;
   case 101: OnFileOpen(Wnd); break;
   case 102: if (DispInfoDlg) SetActiveWindow(DispInfoDlg);
     else CreateDialog(ghInstance,MAKEINTRESOURCE(102),Wnd,DispInfoDlgProc);
   break;
  }break;
  
  case WM_PAINT: {
   PAINTSTRUCT ps;
   ps.hdc=BeginPaint(Wnd,&ps);
   OnPaint(ps.hdc);
   EndPaint(Wnd,&ps);
  }return 0;
  
  case WM_PRINT:
  case WM_PRINTCLIENT: {
   OnPaint((HDC)wParam);
  }return 0;
  
  case WM_OPENFILE: {
   HandleOpenFile((LPTSTR)lParam);
   InvalidateRect(Wnd,NULL,TRUE);
  }break;
  
  case WM_DROPFILES: {
   UINT j=DragQueryFile((HDROP)wParam,(UINT)-1,NULL,0);
   for (UINT i=0; i<j; i++) {
    TCHAR s[MAX_PATH];
    DragQueryFile((HDROP)wParam,i,s,elemof(s));
    SendMessage(Wnd,WM_OPENFILE,i,(LPARAM)(LPTSTR)s);
   }
   DragFinish((HDROP)wParam);
  }break;
 }
 return DefWindowProc(Wnd,Msg,wParam,lParam);
}


/******************************
 * Hauptprogramm (lächerlich) *
 ******************************/
 
int _stdcall WinMainCRTStartup(void) {
 ghInstance=GetModuleHandle(NULL);
 
 WNDCLASSEX wc;
 InitStruct(&wc,sizeof(wc));
  wc.style=CS_HREDRAW|CS_VREDRAW;
  wc.lpfnWndProc=MainWndProc;
  wc.hInstance=ghInstance;
  wc.hCursor=LoadCursor(0,IDC_ARROW);
  wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
  wc.lpszMenuName=MAKEINTRESOURCE(100);
  wc.lpszClassName=MAKEINTRESOURCE(100);

 RegisterClassEx(&wc);
 InitCommonControls();
 ghMainWnd=CreateWindowEx(WS_EX_ACCEPTFILES,MAKEINTRESOURCE(100),T("bin2graf"),WS_OVERLAPPEDWINDOW,
   CW_USEDEFAULT,0,
   CW_USEDEFAULT,0,
   0,0,ghInstance,GetCommandLine());
 ShowWindow(ghMainWnd,SW_SHOWDEFAULT);
 
 MSG Msg;
 while (GetMessage(&Msg,0,0,0)) {
  if (ghDlgWnd && IsDialogMessage(ghDlgWnd,&Msg)) continue;
  TranslateMessage(&Msg);
  DispatchMessage(&Msg);
 }
 ExitProcess((UINT)Msg.wParam);
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded