summaryrefslogtreecommitdiffabout
path: root/shared-code
Side-by-side diff
Diffstat (limited to 'shared-code') (more/less context) (ignore whitespace changes)
-rw-r--r--shared-code/BTreendex.h595
-rw-r--r--shared-code/BellsNWhistles.h146
-rw-r--r--shared-code/BitSet.h105
-rw-r--r--shared-code/Dynamide.h443
-rw-r--r--shared-code/FindIFace.h125
-rw-r--r--shared-code/LRUCache.h113
-rw-r--r--shared-code/RegEx.cpp1697
-rw-r--r--shared-code/RegEx.h158
-rw-r--r--shared-code/SNMPExtDll.h252
-rw-r--r--shared-code/SNMPOIDs.h221
-rw-r--r--shared-code/SNMPeer.h286
-rw-r--r--shared-code/install.h370
-rw-r--r--shared-code/ip_icmp.h91
-rw-r--r--shared-code/kHelpers.h159
-rw-r--r--shared-code/kICMP.cpp300
-rw-r--r--shared-code/kICMP.h80
-rw-r--r--shared-code/kinhelp.xsl250
-rw-r--r--shared-code/ms_icmp.h77
18 files changed, 5468 insertions, 0 deletions
diff --git a/shared-code/BTreendex.h b/shared-code/BTreendex.h
new file mode 100644
index 0000000..88109ab
--- a/dev/null
+++ b/shared-code/BTreendex.h
@@ -0,0 +1,595 @@
+#ifndef __BTREENDEX_H
+#define __BTREENDEX_H
+
+#include "Dynamide.h"
+
+namespace Klever {
+
+template<class key,class value,int treeOrder,int cluster>
+class CBTreendex : public CObject {
+public:
+ typedef LONG CBTPageRef;
+ struct CBTRecordRef {
+ CBTPageRef m_Page;
+ INT m_Offset;
+ CBTRecordRef(CBTPageRef page=-1,INT offset=-1) : m_Page(page), m_Offset(offset) {}
+ };
+ class CBTRecord : public CObject {
+ public:
+ CBTPageRef m_ptrLeft;
+ CBTPageRef m_ptrRight;
+ key m_Key;
+ value m_Value;
+ CBTRecord() : m_ptrLeft(-1), m_ptrRight(-1) {}
+ CBTRecord(key& _key,value& _value,CBTPageRef left=-1,CBTPageRef right=-1) : m_Key(_key), m_Value(_value), m_ptrLeft(left), m_ptrRight(right) {}
+ CBTRecord(CBTRecord& r) : m_Key(r.m_Key), m_Value(r.m_Value), m_ptrLeft(r.m_ptrLeft), m_ptrRight(r.m_ptrRight) {}
+
+ CBTRecord& operator=(CBTRecord& r) {m_Key=r.m_Key, m_Value=r.m_Value, m_ptrLeft=r.m_ptrLeft, m_ptrRight=r.m_ptrRight;return *this;}
+
+ void Serialize(CArchive& ar) {
+ if(ar.IsStoring()){
+ ar << m_ptrLeft;
+ ar << m_ptrRight;
+ }else{
+ ar >> m_ptrLeft;
+ ar >> m_ptrRight;
+ }
+ SerializeElements(ar,&m_Key,1);
+ SerializeElements(ar,&m_Value,1);
+ }
+ };
+ class CBTPage : public CArray<CBTRecord,CBTRecord&> {
+ public:
+ void Serialize(CArchive& ar) {
+ int nCount = -1;
+ if(ar.IsStoring()){
+ nCount = GetSize();
+ ar << nCount;
+ }else{
+ nCount = 0;
+ ar >> nCount;
+ RemoveAll();
+ SetSize(nCount);
+ }
+ for(int tmp=0;tmp<nCount;tmp++)
+ ElementAt(tmp).Serialize(ar);
+ }
+ };
+ typedef CDynamide<256,cluster> CBTDyna;
+ typedef CBTDyna::CDynaFile CBTDynaFile;
+ typedef CArray<CBTRecordRef,CBTRecordRef&> CBTRStack;
+
+ CBTDyna m_BT;
+ struct _btCrap {
+ BOOL m_bRootSet;
+ CBTPageRef m_Root;
+ } *m_BTCrap;
+ BOOL m_bRO;
+ CBTRStack m_btStack;
+ CBTPage m_stackTop;
+
+ CBTreendex() {}
+ ~CBTreendex() { Close(); }
+ BOOL Attach(CFile* file,BOOL bAutodelete) {
+ m_bRO = FALSE;
+ if(!m_BT.Attach(file,bAutodelete))
+ return FALSE;
+ return Attach();
+ }
+ BOOL Open(LPCTSTR file,BOOL bReadOnly) {
+ if(!m_BT.Open(file,bReadOnly))
+ return FALSE;
+ m_bRO = bReadOnly;
+ return Attach();
+ }
+ BOOL Create(LPCTSTR file) {
+ try{
+ CFile* f = new CFile(file,CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyRead|CFile::shareDenyWrite|CFile::typeBinary);
+ ASSERT(f);
+ return Attach(f,TRUE);
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ }
+ BOOL Attach() {
+ ASSERT(m_BT.IsOpened());
+ m_BTCrap = (_btCrap*)m_BT.m_FB.crap;
+ if(!m_BTCrap->m_bRootSet){
+ m_BTCrap->m_Root = AllocatePage();
+ if(m_BTCrap->m_Root<0)
+ return FALSE;
+ m_BTCrap->m_bRootSet = TRUE;
+ m_BT.Write1stBlock();
+ }
+ return TRUE;
+ }
+ BOOL Close() {
+ m_BT.Close();
+ return TRUE;
+ }
+ BOOL IsOpened() {
+ return m_BT.IsOpened();
+ }
+
+ BOOL Lookup(key& _key,value& value) {
+ if(!IsOpened())
+ return FALSE;
+ ASSERT(m_BTCrap->m_bRootSet);
+ if(!SeekToPage(_key))
+ return FALSE;
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(rr.m_Offset<0)
+ return FALSE;
+ ASSERT(rr.m_Offset<m_stackTop.GetSize());
+ if(_key != m_stackTop[rr.m_Offset].m_Key)
+ return FALSE;
+ value = m_stackTop[rr.m_Offset].m_Value;
+ return TRUE;
+ }
+ BOOL Add(key& _key,value& _value) {
+ if(!IsOpened())
+ return FALSE;
+ ASSERT(m_BTCrap->m_bRootSet);
+ if(!SeekToPage(_key))
+ return FALSE;
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ CBTRecord nuRecord(_key,_value);
+ if(rr.m_Offset<0){
+ if(m_stackTop.GetSize())
+ nuRecord.m_ptrLeft = m_stackTop[m_stackTop.GetUpperBound()].m_ptrRight;
+ }else if(rr.m_Offset==0){
+ nuRecord.m_ptrRight = m_stackTop[0].m_ptrLeft;
+ }else{
+ nuRecord.m_ptrLeft = m_stackTop[rr.m_Offset-1].m_ptrRight;
+ nuRecord.m_ptrRight = m_stackTop[rr.m_Offset].m_ptrLeft;
+ }
+// ASSERT(rr.m_Offset==0 || (m_stackTop[rr.m_Offset-1].m_Key<_key && m_stackTop[rr.m_Offset-1].m_ptrRight<0));
+// ASSERT(rr.m_Offset<0 || m_stackTop[rr.m_Offset].m_Key>=_key && m_stackTop[rr.m_Offset].m_ptrLeft<0);
+ if(rr.m_Offset>=0 && m_stackTop[rr.m_Offset].m_Key==_key){
+ // Exact match found - just replace.
+ m_stackTop[rr.m_Offset].m_Value = _value;
+ if(!SavePage(rr.m_Page,m_stackTop))
+ return FALSE;
+ return TRUE;
+ }
+ // Split the page and propagate the split if needed..
+ // Insert new element at rr.m_Offset..
+ BOOL nuisnew = TRUE;
+ for(int sp=m_btStack.GetUpperBound();sp>=0;sp--){
+ CBTPageRef opr = m_btStack[sp].m_Page;
+ int iAt = m_btStack[sp].m_Offset;
+ CBTPage op;
+ VERIFY(LoadPage(opr,op));
+ if(iAt<0)
+ iAt = op.GetSize();
+ else{
+ if(op[iAt].m_Key<nuRecord.m_Key)
+ iAt++;
+ ASSERT(iAt==op.GetSize() || op[iAt].m_Key > nuRecord.m_Key);
+ }
+ op.InsertAt(iAt,nuRecord);
+ if(iAt>0)
+ op[iAt-1].m_ptrRight=nuRecord.m_ptrLeft;
+ if(iAt<op.GetUpperBound())
+ op[iAt+1].m_ptrLeft=nuRecord.m_ptrRight;
+ if(op.GetSize()<=treeOrder*2){
+ // This isn't causing overflow
+ VERIFY(SavePage(opr,op));
+ return TRUE;
+ }
+ TRACE0("Split\n");
+ ASSERT(op.GetSize()==(treeOrder*2+1));
+ CBTPageRef npr = AllocatePage();
+ ASSERT(npr>=0);
+ CBTPage np;
+ ASSERT(LoadPage(npr,np));
+ ASSERT(!np.GetSize());
+ nuRecord = op[treeOrder];
+ if(iAt==treeOrder){
+ // We're inserting central element! - drop out the stack top if this is still new one
+ for(int tmp=0;tmp<treeOrder;tmp++)
+ np.InsertAt(tmp,op[tmp]);
+ op.RemoveAt(0,treeOrder+1);
+ nuRecord.m_ptrLeft = npr;
+ nuRecord.m_ptrRight = opr;
+ if(nuisnew)
+ m_btStack.RemoveAt(m_btStack.GetUpperBound());
+ }else{
+ if(iAt<treeOrder){
+ // We're inserting in the left subtree.
+ // Make newpage the right one and forget it.
+ for(int tmp=0;tmp<treeOrder;tmp++)
+ np.InsertAt(tmp,op[tmp+treeOrder+1]);
+ op.RemoveAt(treeOrder,treeOrder+1);
+ nuRecord.m_ptrLeft = opr;
+ nuRecord.m_ptrRight = npr;
+ }else{
+ // We're inserting in the right subtree.
+ // Make newpage the left one, forget it, but also adjust offset in the stack
+ for(int tmp=0;tmp<treeOrder;tmp++)
+ np.InsertAt(tmp,op[tmp]);
+ op.RemoveAt(0,treeOrder+1);
+ nuRecord.m_ptrLeft = npr;
+ nuRecord.m_ptrRight = opr;
+ m_btStack[sp].m_Offset-=treeOrder+1;
+ }
+ // Note that we're not inserting new element anymore.
+ nuisnew = FALSE;
+ }
+ // Do, excessive sanity checks and save pages
+ ASSERT(op.GetSize());
+ ASSERT(np.GetSize());
+ VERIFY(SavePage(opr,op));
+ VERIFY(SavePage(npr,np));
+ }
+ // Here we have root page overflow, which means that we're simply putting new
+ // record in this brand new root page and also inserting this page on the bottom of the stack
+ CBTPageRef nuroot = AllocatePage();
+ ASSERT(nuroot>=0);
+ CBTPage nurpa;
+ ASSERT(LoadPage(nuroot,nurpa));
+ ASSERT(!nurpa.GetSize());
+ nurpa.Add(nuRecord);
+ VERIFY(SavePage(nuroot,nurpa));
+ m_btStack.InsertAt(0,CBTRecordRef(nuroot,0));
+ m_BTCrap->m_Root = nuroot;
+ m_BT.Write1stBlock();
+ return TRUE;
+ }
+ BOOL Delete(key& _key) {
+ if(!IsOpened())
+ return FALSE;
+ ASSERT(m_BTCrap->m_bRootSet);
+ value _value;
+ if(!Lookup(_key,_value))
+ return FALSE;
+ // Found key, check if it's a leaf
+ {
+ CBTRecordRef* rr = &m_btStack[m_btStack.GetUpperBound()];
+ int rrIdx = m_btStack.GetUpperBound();
+ if(m_stackTop[rr->m_Offset].m_ptrLeft>=0){
+ ASSERT(m_stackTop[rr->m_Offset].m_ptrRight>=0);
+ // It isn't - scan for the _next_ key and do dirty deeds
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr->m_Offset].m_ptrRight,0));
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ if(m_stackTop[0].m_ptrLeft<0)
+ break;
+ m_btStack.Add(CBTRecordRef(m_stackTop[0].m_ptrLeft,0));
+ }
+ // We have a leaf node here, replace victim with the first element and kill it.
+ CBTPage uppage;
+ rr = &m_btStack[rrIdx];
+ if(!LoadPage(rr->m_Page,uppage))
+ return FALSE;
+ uppage[rr->m_Offset].m_Key=m_stackTop[0].m_Key; uppage[rr->m_Offset].m_Value=m_stackTop[0].m_Value;
+ m_stackTop.RemoveAt(0);
+ if(!(SavePage(rr->m_Page,uppage) && SavePage(m_btStack[m_btStack.GetUpperBound()].m_Page,m_stackTop)))
+ return FALSE;
+ }else{
+ ASSERT(m_stackTop[rr->m_Offset].m_ptrRight<0);
+ m_stackTop.RemoveAt(rr->m_Offset);
+ if(!SavePage(rr->m_Page,m_stackTop))
+ return FALSE;
+ }
+ }
+ // We have a page to check for underflow at the top of the stack now.
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ if(m_stackTop.GetSize()>=treeOrder || m_btStack.GetSize()==1)
+ return TRUE;
+ CBTRecordRef& rr1 = m_btStack[m_btStack.GetUpperBound()-1];
+ CBTPage daddy;
+ if(!LoadPage(rr1.m_Page,daddy))
+ return FALSE;
+ CBTPageRef nPage = daddy[rr1.m_Offset].m_ptrRight;
+ BOOL bRight=TRUE;
+ if(nPage<0 || nPage==rr.m_Page){
+ nPage = daddy[rr1.m_Offset].m_ptrLeft;
+ bRight = FALSE;
+ }
+ ASSERT(nPage>=0 && nPage!=rr.m_Page);
+ CBTPage neighbor;
+ if(!LoadPage(nPage,neighbor))
+ return FALSE;
+ // Here we have possibly two cases:
+ // 1. Neighboring page can share some data with use, then do share and leave
+ // 2. Neighboring page is of treeorder in size, then merge and propagate
+ if(neighbor.GetSize()>treeOrder){
+ TRACE0("Redistributing..\n");
+ // Borrow some data from there.
+ int toBorrow = neighbor.GetSize()-treeOrder;
+ toBorrow=toBorrow/2+1;
+ ASSERT(toBorrow);
+ if(bRight)
+ m_stackTop.Add(CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,m_stackTop[m_stackTop.GetUpperBound()].m_ptrRight,neighbor[0].m_ptrLeft));
+ else
+ m_stackTop.InsertAt(0,CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,neighbor[neighbor.GetUpperBound()].m_ptrRight,m_stackTop[0].m_ptrLeft));
+ for(toBorrow--;toBorrow;toBorrow--){
+ if(bRight){
+ m_stackTop.Add(neighbor[0]);
+ neighbor.RemoveAt(0);
+ }else{
+ m_stackTop.InsertAt(0,neighbor[neighbor.GetUpperBound()]);
+ neighbor.RemoveAt(neighbor.GetUpperBound());
+ }
+ }
+ daddy[rr1.m_Offset].m_Key = neighbor[bRight?0:neighbor.GetUpperBound()].m_Key; daddy[rr1.m_Offset].m_Value = neighbor[bRight?0:neighbor.GetUpperBound()].m_Value;
+ neighbor.RemoveAt(bRight?0:neighbor.GetUpperBound());
+ if(!(SavePage(rr1.m_Page,daddy) && SavePage(nPage,neighbor) && SavePage(rr.m_Page,m_stackTop)))
+ return FALSE;
+ rr.m_Offset = -1; // *** Point to the next??
+ return TRUE;
+ }
+ TRACE0("Merging..\n");
+ // We need to merge pages here..
+ // We will merge them at stacktop, then we'll discard neighbor guy..
+ if(bRight)
+ m_stackTop.Add(CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,m_stackTop[m_stackTop.GetUpperBound()].m_ptrRight,neighbor[0].m_ptrLeft));
+ else
+ m_stackTop.InsertAt(0,CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,neighbor[neighbor.GetUpperBound()].m_ptrRight,m_stackTop[0].m_ptrLeft));
+ if(bRight){
+ while(neighbor.GetSize()){
+ m_stackTop.Add(neighbor[0]);
+ neighbor.RemoveAt(0);
+ }
+ }else{
+ while(neighbor.GetSize()){
+ m_stackTop.InsertAt(0,neighbor[neighbor.GetUpperBound()]);
+ neighbor.RemoveAt(neighbor.GetUpperBound());
+ }
+ }
+ if(rr1.m_Offset>0)
+ daddy[rr1.m_Offset-1].m_ptrRight=rr.m_Page;
+ if(rr1.m_Offset<daddy.GetUpperBound())
+ daddy[rr1.m_Offset+1].m_ptrLeft=rr.m_Page;
+ daddy.RemoveAt(rr1.m_Offset);
+ if(!(SavePage(rr1.m_Page,daddy) && SavePage(rr.m_Page,m_stackTop)))
+ return FALSE;
+ VERIFY(DeallocatePage(nPage));
+ m_btStack.RemoveAt(m_btStack.GetUpperBound());
+ }
+ return FALSE;
+ }
+ BOOL GoFirst() {
+ if(!IsOpened())
+ return FALSE;
+ ASSERT(m_BTCrap->m_bRootSet);
+ m_btStack.RemoveAll();
+ m_btStack.Add(CBTRecordRef(m_BTCrap->m_Root,-1));
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ if(!m_stackTop.GetSize()){
+ ASSERT(m_btStack.GetSize()==1);
+ return FALSE;
+ }
+ rr.m_Offset = 0;
+ if(m_stackTop[rr.m_Offset].m_ptrLeft<0)
+ return TRUE;
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,-1));
+ }
+ }
+ BOOL GoLast() {
+ if(!IsOpened())
+ return FALSE;
+ ASSERT(m_BTCrap->m_bRootSet);
+ m_btStack.RemoveAll();
+ m_btStack.Add(CBTRecordRef(m_BTCrap->m_Root,-1));
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ if(!m_stackTop.GetSize()){
+ ASSERT(m_btStack.GetSize()==1);
+ return FALSE;
+ }
+ rr.m_Offset = m_stackTop.GetUpperBound();
+ if(m_stackTop[rr.m_Offset].m_ptrRight<0)
+ return TRUE;
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset++].m_ptrRight,-1));
+ }
+ }
+ BOOL GoNext() {
+ if(!IsOpened())
+ return FALSE;
+ if(!(m_btStack.GetSize() && m_btStack[m_btStack.GetUpperBound()].m_Offset>=0))
+ return FALSE;
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ ASSERT(rr.m_Offset<m_stackTop.GetSize());
+ if(m_stackTop[rr.m_Offset].m_ptrRight>=0){
+ // Advance pointer in this page and dive into subtree
+ // going left and left until we have nowhere to go.
+// TRACE1("Dive into page %lu",m_stackTop[rr.m_Offset].m_ptrRight);
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset++].m_ptrRight,0));
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ ASSERT(rr.m_Offset==0);
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ if(m_stackTop[rr.m_Offset].m_ptrLeft<0)
+ break;
+// TRACE1(", %lu",m_stackTop[rr.m_Offset].m_ptrLeft);
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,0));
+ }
+// TRACE0("\n");
+ return TRUE;
+ }else if(rr.m_Offset<m_stackTop.GetUpperBound()){
+ rr.m_Offset++;
+ return TRUE;
+ }
+ // We're at the end of page go up until we're done or we have data.
+ m_btStack.RemoveAt(m_btStack.GetUpperBound());
+// TRACE0("Go up");
+ while(m_btStack.GetSize()){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ if(rr.m_Offset<m_stackTop.GetSize()){
+// TRACE0("\n");
+ return TRUE;
+ }
+// TRACE0(", up");
+ m_btStack.RemoveAt(m_btStack.GetUpperBound());
+ }
+// TRACE0("\nBtree is done\n");
+ return FALSE;
+ }
+ BOOL GoPrev() {
+ if(!IsOpened())
+ return FALSE;
+ if(!(m_btStack.GetSize() && m_btStack[m_btStack.GetUpperBound()].m_Offset>=0))
+ return FALSE;
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ ASSERT(rr.m_Offset<m_stackTop.GetSize());
+ if(m_stackTop[rr.m_Offset].m_ptrLeft>=0){
+ // Dive in and go right and right from the rightmost until
+ // we have nowhere to go.
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,-1));
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ rr.m_Offset = m_stackTop.GetUpperBound();
+ if(m_stackTop[rr.m_Offset].m_ptrRight<0)
+ return TRUE;
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset++].m_ptrRight,-1));
+ }
+ return TRUE;
+ }else if(rr.m_Offset>0){
+ rr.m_Offset--;
+ return TRUE;
+ }
+ // We're at the leftmost element in page - go up and left until we're
+ // done or we have data.
+ m_btStack.RemoveAt(m_btStack.GetUpperBound());
+ while(m_btStack.GetSize()){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ rr.m_Offset--;
+ if(rr.m_Offset>=0)
+ return TRUE;
+ m_btStack.RemoveAt(m_btStack.GetUpperBound());
+ }
+ // No more data - we were at the first element in tree.
+ return FALSE;
+ }
+ BOOL GetThis(key& _key,value& _value) {
+ if(!IsOpened())
+ return FALSE;
+ // *** MORE CHECKING
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ _key = m_stackTop[rr.m_Offset].m_Key;
+ _value = m_stackTop[rr.m_Offset].m_Value;
+ return TRUE;
+ }
+
+ BOOL SeekToPage(const key& _key) {
+ ASSERT(IsOpened());
+ ASSERT(m_BTCrap->m_bRootSet);
+ m_btStack.RemoveAll();
+ m_btStack.Add(CBTRecordRef(m_BTCrap->m_Root,-1));
+ for(;;){
+ CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()];
+ if(!LoadPage(rr.m_Page,m_stackTop))
+ return FALSE;
+ ASSERT(m_stackTop.GetSize() || !m_btStack.GetUpperBound());
+ if(!m_stackTop.GetSize()){
+ rr.m_Offset=-1;
+ return TRUE;
+ }
+ for(rr.m_Offset=0;rr.m_Offset<m_stackTop.GetSize();rr.m_Offset++){
+ if(_key == m_stackTop[rr.m_Offset].m_Key)
+ return TRUE;
+ if(_key < m_stackTop[rr.m_Offset].m_Key){
+ ASSERT(rr.m_Offset==0 || m_stackTop[rr.m_Offset].m_ptrLeft==m_stackTop[rr.m_Offset-1].m_ptrRight);
+ if(m_stackTop[rr.m_Offset].m_ptrLeft<0)
+ return TRUE;
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,-1));
+ break;
+ }
+ if(rr.m_Offset==m_stackTop.GetUpperBound()){
+ if(m_stackTop[rr.m_Offset].m_ptrRight<0){
+ rr.m_Offset=-1;
+ return TRUE;
+ }
+ m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrRight,-1));
+ break;
+ }
+ }
+ }
+ }
+
+ BOOL LoadPage(CBTPageRef ref,CBTPage& page) {
+ CFile* pageFile = m_BT.OpenFile(ref);
+ if(!pageFile)
+ return FALSE;
+ BOOL rv = TRUE;
+ try{
+ CArchive ar(pageFile,CArchive::load);
+ page.Serialize(ar);
+ if(m_bRO)
+ page.FreeExtra(); // ** ???
+ ar.Close();
+ }catch(CException* e){
+ e->Delete();
+ rv = FALSE;
+ }
+ delete pageFile;
+ return rv;
+ }
+ BOOL SavePage(CBTPageRef ref,CBTPage& page) {
+ CFile* pageFile = m_BT.OpenFile(ref);
+ if(!pageFile)
+ return FALSE;
+ BOOL rv = TRUE;
+ try{
+ CArchive ar(pageFile,CArchive::store);
+ page.Serialize(ar);
+ ar.Close();
+ }catch(CException* e){
+ e->Delete();
+ rv = FALSE;
+ }
+ delete pageFile;
+ return rv;
+ }
+ CBTPageRef AllocatePage() {
+ CBTDynaFile* pageFile = m_BT.CreateFile();
+ if(!pageFile)
+ return -1;
+ CBTPage nothing;
+ CBTPageRef rv = pageFile->GetFile();
+ try{
+ CArchive ar(pageFile,CArchive::store);
+ nothing.Serialize(ar);
+ ar.Close();
+ }catch(CException* e){
+ e->Delete();
+ rv = -1;
+ }
+ delete pageFile;
+ return rv;
+ }
+ BOOL DeallocatePage(CBTPageRef ref) {
+ return m_BT.DeleteFile(ref);
+ }
+
+};
+
+};
+
+#endif // __BTREENDEX_H
diff --git a/shared-code/BellsNWhistles.h b/shared-code/BellsNWhistles.h
new file mode 100644
index 0000000..1de77ae
--- a/dev/null
+++ b/shared-code/BellsNWhistles.h
@@ -0,0 +1,146 @@
+#ifndef __BELLSNWHISTLES_H
+#define __BELLSNWHISTLES_H
+
+class CBellsNWhistles {
+public:
+ class CBang {
+ public:
+ CString m_codeName;
+ enum _bangType {
+ bangNone, bangSpeaker, bangSystem, bangResource,
+ bangWaveform
+ } m_type;
+ BOOL m_bLoop;
+ union {
+ UINT system;
+ LPCTSTR resource;
+ LPCTSTR wave;
+
+ LPCTSTR str;
+ UINT id;
+ };
+ CString m_strWave;
+ CBang() : m_type(bangNone), m_bLoop(FALSE) {}
+ };
+ typedef CTypedPtrMap<CMapStringToPtr,CString,CBang*> CBangs;
+ struct CBelling {
+ LPCSTR snd;
+ HMODULE hm;
+ DWORD flags;
+ CBelling(LPCSTR snd,HMODULE hm,DWORD flags) : snd(snd), hm(hm),
+ flags(flags) {}
+ CBelling(CBelling& s) : snd(s.snd), hm(s.hm), flags(s.flags) {}
+ CBelling& operator=(CBelling& s) {
+ snd=s.snd; hm=s.hm; flags=s.flags;
+ return *this;
+ }
+ };
+ typedef CBelling* Whistling;
+
+ CBangs m_bangs;
+
+ ~CBellsNWhistles() {
+ POSITION p = m_bangs.GetStartPosition();
+ while(p){
+ CString s; CBang* b;
+ m_bangs.GetNextAssoc(p,s,b);
+ delete b;
+ }
+ m_bangs.RemoveAll();
+ }
+
+ BOOL AssignSound(LPCTSTR codeName,LPCTSTR id,CBang::_bangType type=CBang::bangWaveform) {
+ CString cn = codeName;
+ cn.MakeLower();
+ CBang* b;
+ if(!m_bangs.Lookup(cn,b)) {
+ b = new CBang;
+ b->m_codeName=cn;
+ m_bangs[cn]=b;
+ }
+ b->m_type=type;
+ b->str = id;
+ if(type==CBang::bangWaveform){
+ b->m_strWave=id; b->str = b->m_strWave;
+ }
+ return TRUE;
+ }
+ BOOL AssignSound(LPCTSTR codeName,UINT nID,CBang::_bangType type=CBang::bangResource) {
+ CString cn = codeName;
+ cn.MakeLower();
+ CBang* b;
+ if(!m_bangs.Lookup(cn,b)) {
+ b = new CBang;
+ b->m_codeName=cn;
+ m_bangs[cn]=b;
+ }
+ b->m_type=type;
+ b->id = nID;
+ ASSERT(type!=CBang::bangWaveform);
+ return TRUE;
+ }
+ BOOL UnassignSound(LPCTSTR codeName) {
+ CString cn = codeName;
+ cn.MakeLower();
+ CBang* b;
+ if(m_bangs.Lookup(cn,b)) {
+ m_bangs.RemoveKey(cn);
+ delete b;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ Whistling StartSound(LPCTSTR codeName) {
+ Whistling* rv = NULL;
+ CString cn = codeName;
+ CBang* b;
+ if(!m_bangs.Lookup(cn,b)){
+ ::PlaySound(cn,AfxGetInstanceHandle(),SND_ASYNC|SND_NODEFAULT|SND_NOWAIT|SND_FILENAME);
+ return NULL;
+ }
+ UINT flags = SND_ASYNC|SND_NODEFAULT|SND_NOWAIT;
+ LPCSTR snd = NULL;
+ switch(b->m_type){
+ case CBang::bangNone: return NULL;
+ case CBang::bangSpeaker: MessageBeep(0xFFFFFFFF); return NULL;
+ case CBang::bangSystem: MessageBeep(b->system); return NULL;
+ case CBang::bangResource:
+ snd = b->resource;
+ flags|=SND_RESOURCE; break;
+ case CBang::bangWaveform:
+ snd = b->wave;
+ flags|=SND_FILENAME; break;
+#ifdef _DEBUG
+ default:
+ ASSERT(FALSE); return NULL;
+#endif
+ }
+ if(b->m_bLoop)
+ flags|=SND_LOOP;
+ HMODULE hm = AfxGetInstanceHandle();
+ if(!::PlaySound(snd,hm,flags))
+ return NULL;
+ return b->m_bLoop?new CBelling(snd,hm,flags):NULL;
+ }
+ BOOL StopSound(Whistling whistle) {
+ if(!whistle)
+ return FALSE;
+ ::PlaySound(whistle->snd,whistle->hm,whistle->flags|SND_PURGE);
+ delete whistle;
+ return TRUE;
+ }
+ UINT FillInCombo(CComboBox* combo) {
+ POSITION p = m_bangs.GetStartPosition();
+ UINT rv = 0;
+ while(p) {
+ CString s;
+ CBang* b;
+ m_bangs.GetNextAssoc(p,s,b);
+ combo->AddString(s);
+ }
+ return rv;
+ }
+};
+
+#endif // _BELLSNWHISTLES_H \ No newline at end of file
diff --git a/shared-code/BitSet.h b/shared-code/BitSet.h
new file mode 100644
index 0000000..cf36e3b
--- a/dev/null
+++ b/shared-code/BitSet.h
@@ -0,0 +1,105 @@
+#ifndef __BITSET_H
+#define __BITSET_H
+
+namespace Klever {
+
+class CBitSet : public CObject {
+public:
+ CWordArray m_Bits;
+ ULONG m_BitsInSet;
+ enum {
+ bitsPerWord = sizeof(WORD)*8
+ };
+
+ CBitSet(ULONG size = 0) : m_BitsInSet(0) { SetSize(size); }
+ CBitSet(CBitSet& o) : m_BitsInSet(0) { CopyFrom(o); }
+
+ void SetSize(ULONG size,BOOL bFillOnes=FALSE) {
+ UINT os = m_Bits.GetSize();
+ UINT ns = (size+bitsPerWord-1)/bitsPerWord;
+ if(os==ns){
+ if(os){
+ if(bFillOnes)
+ m_Bits[m_BitsInSet/bitsPerWord]|=(~(WORD)0)<<(m_BitsInSet%bitsPerWord);
+ else
+ m_Bits[m_BitsInSet/bitsPerWord]&=~((~(WORD)0)<<(m_BitsInSet%bitsPerWord));
+ }
+ m_BitsInSet=size;
+ }else{
+ // *?* ASSERT((!os) || (((os-1)*bitsPerWord)<=m_BitsInSet && m_BitsInSet<(os*bitsPerWord)));
+ if(os<ns){
+ m_Bits.SetSize(ns);
+ if(bFillOnes)
+ m_Bits[m_BitsInSet/bitsPerWord]|=(~(WORD)0)<<(m_BitsInSet%bitsPerWord);
+ else
+ m_Bits[m_BitsInSet/bitsPerWord]&=~((~(WORD)0)<<(m_BitsInSet%bitsPerWord));
+ WORD* ws = m_Bits.GetData();
+ ASSERT(ws);
+ memset(&ws[os],bFillOnes?0xFF:0,(ns-os)*sizeof(WORD));
+ m_BitsInSet=size;
+ }else{
+ m_Bits.SetSize(ns);
+ m_BitsInSet=size;
+ }
+ }
+ }
+ BOOL BitSet(UINT bit,BOOL bGrow=TRUE) { return SetBit(bit,TRUE,bGrow); }
+ BOOL BitClear(UINT bit,BOOL bGrow=TRUE) { return SetBit(bit,FALSE,bGrow); }
+ BOOL SetBit(UINT bit,BOOL state,BOOL bGrow=TRUE) {
+ if(m_BitsInSet<=bit){
+ if(!bGrow)
+ return FALSE;
+ SetSize(bit+1);
+ }
+ WORD mask = ((WORD)1)<<(bit%bitsPerWord);
+ if(state)
+ m_Bits[bit/bitsPerWord]|=mask;
+ else
+ m_Bits[bit/bitsPerWord]&=~mask;
+ return TRUE;
+ }
+ BOOL IsSet(UINT bit) {
+ if(m_BitsInSet<=bit)
+ return FALSE;
+ return (m_Bits[bit/bitsPerWord]&(((WORD)1)<<(bit%bitsPerWord)))!=0;
+ }
+ void Invert() {
+ for(int i=m_Bits.GetUpperBound();i>=0;i--)
+ m_Bits[i]=~m_Bits[i];
+ }
+ CBitSet& operator&=(CBitSet& o) {
+ if(o.m_BitsInSet<m_BitsInSet)
+ SetSize(o.m_BitsInSet);
+ for(int i=m_Bits.GetUpperBound();i>=0;i--)
+ m_Bits[i]&=o.m_Bits[i];
+ return *this;
+ }
+ CBitSet& operator|=(CBitSet& o) {
+ if(o.m_BitsInSet>m_BitsInSet)
+ SetSize(o.m_BitsInSet);
+ for(int i=o.m_Bits.GetUpperBound();i>=0;i--)
+ m_Bits[i]|=o.m_Bits[i];
+ return *this;
+ }
+ CBitSet& operator=(CBitSet& o) {
+ CopyFrom(o);
+ return *this;
+ }
+ void CopyFrom(CBitSet& o) {
+ m_BitsInSet=o.m_BitsInSet;
+ m_Bits.Copy(o.m_Bits);
+ }
+ void Serialize(CArchive& ar) {
+ if(ar.IsStoring()){
+ ar << m_BitsInSet;
+ m_Bits.Serialize(ar);
+ }else{
+ ar >> m_BitsInSet;
+ m_Bits.Serialize(ar);
+ }
+ }
+};
+
+};
+
+#endif // __BITSET_H
diff --git a/shared-code/Dynamide.h b/shared-code/Dynamide.h
new file mode 100644
index 0000000..32c93f7
--- a/dev/null
+++ b/shared-code/Dynamide.h
@@ -0,0 +1,443 @@
+#ifndef __DYNAMIDE_H
+#define __DYNAMIDE_H
+
+#include "LRUCache.h"
+
+namespace Klever {
+
+template<int fbSize,int bSize>
+class CDynamide : public CObject {
+ struct firstBlock {
+ LONG freeFile;
+ BYTE crap[fbSize-sizeof(LONG)];
+ };
+ struct theBlock {
+ LONG next;
+ BYTE data[bSize-sizeof(LONG)];
+ };
+public:
+ static firstBlock FirstBlock;
+ static theBlock TheBlock;
+private:
+ class CDynaCache : public CLRUCache<DWORD,DWORD,theBlock> {
+ public:
+ CFile* m_File;
+ BOOL m_bAutodelete;
+ CDynaCache(CFile* file,BOOL bAutodelete=TRUE) : CLRUCache<DWORD,DWORD,theBlock>(64) {
+ m_File=file;
+ m_bAutodelete=bAutodelete;
+ }
+ virtual ~CDynaCache() {
+ Flush();
+ if(m_bAutodelete){
+ m_File->Close();
+ delete m_File;
+ }
+ }
+ virtual BOOL _ReadIn(DWORD idx,theBlock* data) {
+ LONG p = sizeof(firstBlock)+idx*sizeof(theBlock);
+ LONG s = m_File->Seek(p,CFile::begin);
+ if(p==s){
+ UINT rb = m_File->Read(data,sizeof(*data));
+ if(rb==sizeof(*data))
+ return TRUE;
+ if(rb)
+ return FALSE;
+ memset(data,0,sizeof(*data));
+ data->next=-1;
+ try{
+ m_File->Write(data,sizeof(*data));
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ }else{
+ LONG togo = p-s;
+ ASSERT(togo>0);
+ ASSERT(!(togo%sizeof(theBlock)));
+ memset(data,0,sizeof(*data));
+ data->next=-1;
+ while(togo>=0){
+ try{
+ m_File->Write(data,sizeof(*data));
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ }
+ virtual BOOL _WriteOut(DWORD idx,theBlock* data) {
+ LONG p = sizeof(firstBlock)+idx*sizeof(theBlock);
+ LONG s = m_File->Seek(p,CFile::begin);
+ if(p!=s)
+ return FALSE;
+ try{
+ m_File->Write(data,sizeof(*data));
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ return TRUE;
+ }
+ DWORD AllocateNode() {
+ LONG l = m_File->GetLength();
+ ASSERT(!((l-sizeof(firstBlock))%sizeof(theBlock)));
+ m_File->SetLength(l+sizeof(theBlock));
+ return (l-sizeof(firstBlock))/sizeof(theBlock);
+ }
+ BOOL Read1stBlock(firstBlock* fb) {
+ m_File->SeekToBegin();
+ UINT rb = m_File->Read(fb,sizeof(*fb));
+ if(rb==sizeof(*fb))
+ return TRUE;
+ if(rb)
+ return FALSE;
+ memset(fb,0,sizeof(*fb));
+ fb->freeFile = -1;
+ try{
+ m_File->Write(fb,sizeof(*fb));
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ return TRUE;
+ }
+ BOOL Write1stBlock(firstBlock* fb) {
+ m_File->SeekToBegin();
+ try{
+ m_File->Write(fb,sizeof(*fb));
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ return TRUE;
+ }
+ };
+public:
+ class CDynaFile : public CFile {
+ public:
+ CDynamide<fbSize,bSize>* m_Daddy;
+ CArray<LONG,LONG> m_Blocks;
+ LONG m_Position;
+
+ CDynaFile(CDynamide<fbSize,bSize>* daddy) : m_Daddy(NULL) { AttachToDaddy(daddy); }
+ virtual ~CDynaFile() { Close(); DetachFromDaddy(); }
+
+ void AttachToDaddy(CDynamide<fbSize,bSize>* daddy) {
+ ASSERT(!m_Daddy);
+ ASSERT(daddy);
+ m_Daddy=daddy;
+ m_Daddy->AttachDynaFile(this);
+ }
+ void DetachFromDaddy() {
+ ASSERT(m_Daddy);
+ ASSERT(!IsOpened());
+ m_Daddy->DetachDynaFile(this);
+ m_Daddy=NULL;
+ }
+
+ BOOL Create() {
+ if(IsOpened())
+ return FALSE;
+ m_Blocks.SetAtGrow(0,m_Daddy->Allocate());
+ ASSERT(m_Blocks[0]>=0);
+ m_Position=0;
+ return TRUE;
+ }
+ BOOL Open(LONG fb) {
+ if(IsOpened())
+ return FALSE;
+ ASSERT(fb>=0);
+ theBlock* b;
+ do{
+ m_Blocks.Add(fb);
+ b = m_Daddy->m_File->GetCached(fb);
+ ASSERT(b);
+ fb=b->next;
+ if(m_Blocks[m_Blocks.GetUpperBound()]==fb)
+ return FALSE;
+ }while(fb>=0);
+ m_Position=0;
+ return TRUE;
+ }
+
+ LONG GetFile() {
+ if(!IsOpened())
+ return -1;
+ return m_Blocks[0];
+ }
+ virtual DWORD GetPosition() const {
+ if(!IsOpened())
+ return 0;
+ if(m_Position<0)
+ return 0;
+ if(m_Position>GetLength())
+ return GetLength();
+ return m_Position;
+ }
+ virtual CString GetFileName() {
+ CString rv;
+ if(IsOpened())
+ rv.Format("0x%08lX",m_Blocks[0]);
+ else
+ rv.Format("None");
+ return rv;
+ }
+ virtual CString GetFileTitle() { return GetFileName(); }
+ virtual CString GetFilePath() { return GetFileName(); }
+ virtual void SetFilePath(LPCTSTR lpszNewName) { ASSERT(FALSE); }
+
+ virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL) { ASSERT(FALSE); return FALSE; }
+ virtual CFile* Duplicate() { ASSERT(FALSE); return NULL; }
+
+ virtual LONG Seek(LONG lOff, UINT nFrom) {
+ if(!IsOpened())
+ return -1;
+ switch(nFrom){
+ case CFile::begin:
+ m_Position=lOff;
+ break;
+ case CFile::current:
+ m_Position+=lOff;
+ break;
+ case CFile::end:
+ m_Position=GetLength()+lOff;
+ break;
+ default:
+ ASSERT(FALSE);
+ return -1;
+ }
+ if(m_Position<0)
+ m_Position=0;
+ if(m_Position>GetLength())
+ m_Position=GetLength();
+ return m_Position;
+ }
+ virtual void SetLength(DWORD dwNewLen) {
+ if(!IsOpened())
+ return;
+ if(dwNewLen<GetLength()){
+ dwNewLen=dwNewLen+sizeof(TheBlock.data);
+ dwNewLen-=dwNewLen%sizeof(TheBlock.data);
+ while(dwNewLen<GetLength() && m_Blocks.GetSize()>1){
+ LONG mb = m_Blocks[m_Blocks.GetUpperBound()];
+ LONG mb1 = m_Blocks[m_Blocks.GetUpperBound()-1];
+ theBlock* b = m_Daddy->m_File->GetCached(mb1);
+ ASSERT(b);
+ ASSERT(b->next==mb);
+ b->next=-1;
+ m_Daddy->m_File->MakeDirty(mb1);
+ m_Daddy->Deallocate(mb);
+ m_Blocks.SetSize(m_Blocks.GetSize()-1);
+ }
+ }else{
+ while(dwNewLen>GetLength()){
+ LONG mb = m_Blocks[m_Blocks.GetUpperBound()];
+ LONG newBlock = m_Daddy->Allocate();
+ ASSERT(newBlock>=0);
+ theBlock* b = m_Daddy->m_File->GetCached(mb);
+ ASSERT(b);
+ ASSERT(b->next<0);
+ b->next=newBlock;
+ m_Daddy->m_File->MakeDirty(mb);
+ m_Blocks.Add(newBlock);
+ }
+ }
+ }
+ virtual DWORD GetLength() const {
+ return ((long)m_Blocks.GetSize())*((long)sizeof(TheBlock.data));
+ }
+
+ virtual UINT Read(void* lpBuf, UINT nCount) {
+ UINT rv = 0;
+ ASSERT(m_Position>=0 && m_Position<=GetLength());
+ LPBYTE data = (LPBYTE)lpBuf;
+ while(nCount && m_Position<GetLength()){
+ UINT bn = m_Position/sizeof(TheBlock.data);
+ UINT bo = m_Position%sizeof(TheBlock.data);
+ theBlock* b = m_Daddy->m_File->GetCached(m_Blocks[bn]);
+ ASSERT(b);
+ UINT bc = min(nCount,sizeof(TheBlock.data)-bo);
+ memmove(data,&b->data[bo],bc);
+ nCount-=bc;
+ data=&data[bc];
+ rv+=bc;
+ m_Position+=bc;
+ }
+ return rv;
+ }
+ virtual void Write(const void* lpBuf, UINT nCount) {
+ ASSERT(m_Position>=0 && m_Position<=GetLength());
+ LPBYTE data = (LPBYTE)lpBuf;
+ while(nCount){
+ UINT bn = m_Position/sizeof(TheBlock.data);
+ UINT bo = m_Position%sizeof(TheBlock.data);
+ while(bn>=m_Blocks.GetSize()){
+ LONG mb = m_Blocks[m_Blocks.GetUpperBound()];
+ LONG newBlock = m_Daddy->Allocate();
+ ASSERT(newBlock>=0);
+ theBlock* b = m_Daddy->m_File->GetCached(mb);
+ ASSERT(b);
+ ASSERT(b->next<0);
+ b->next=newBlock;
+ m_Daddy->m_File->MakeDirty(mb);
+ m_Blocks.Add(newBlock);
+ }
+ theBlock* b = m_Daddy->m_File->GetCached(m_Blocks[bn]);
+ ASSERT(b);
+ UINT bc = min(nCount,sizeof(TheBlock.data)-bo);
+ memmove(&b->data[bo],data,bc);
+ m_Daddy->m_File->MakeDirty(m_Blocks[bn]);
+ nCount-=bc;
+ data=&data[bc];
+ m_Position+=bc;
+ }
+ }
+
+ virtual void LockRange(DWORD dwPos, DWORD dwCount) { ASSERT(FALSE); }
+ virtual void UnlockRange(DWORD dwPos, DWORD dwCount) { ASSERT(FALSE); }
+
+ virtual void Abort() { ASSERT(FALSE); }
+ virtual void Flush() {
+ m_Daddy->m_File->Flush();
+ }
+ virtual void Close() {
+ m_Blocks.RemoveAll();
+ }
+
+ BOOL IsOpened() const { return m_Blocks.GetSize()!=0; }
+ };
+
+ CDynaCache* m_File;
+ firstBlock m_FB;
+
+ CDynamide() : m_File(NULL) {}
+ ~CDynamide() { Close(); }
+
+ BOOL AttachDynaFile(CDynaFile* f) {
+ // ASSERT(!m_Files.Find(f));
+ // m_Files.AddHead(f);
+ return TRUE;
+ }
+ BOOL DetachDynaFile(CDynaFile* f) {
+ //POSITION p = m_Files.Find(f);
+ // ASSERT(p);
+ // m_Files.RemoveAt(p);
+ return TRUE;
+ }
+
+ BOOL Open(LPCTSTR file,BOOL bRO=FALSE) {
+ Close();
+ try{
+ CFile* f = new CFile(file,CFile::typeBinary|(bRO?CFile::modeRead|CFile::shareDenyWrite:CFile::modeReadWrite|CFile::shareDenyRead));
+ return Attach(f,TRUE);
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ }
+ BOOL Create(LPCTSTR file) {
+ Close();
+ try{
+ CFile* f = new CFile(file,CFile::typeBinary|CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyRead);
+ return Attach(f,TRUE);
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ }
+ BOOL Attach(CFile* file,BOOL bAutodelete=TRUE) {
+ if(IsOpened())
+ return FALSE;
+ m_File = new CDynaCache(file,bAutodelete);
+ if(!m_File->Read1stBlock(&m_FB)){
+ memset(&m_FB,0,sizeof(m_FB));
+ m_FB.freeFile=-1;
+ VERIFY(m_File->Write1stBlock(&m_FB));
+ }
+ return IsOpened();
+ }
+ // CFile* Detach();
+ BOOL Close() {
+ if(!IsOpened())
+ return FALSE;
+ m_File->Write1stBlock(&m_FB);
+ delete m_File;
+ m_File=NULL;
+ return TRUE;
+ }
+ BOOL IsOpened() {
+ return m_File != NULL;
+ }
+ BOOL Write1stBlock(void) {
+ if(!IsOpened())
+ return FALSE;
+ VERIFY(m_File->Write1stBlock(&m_FB));
+ return TRUE;
+ }
+
+ CDynaFile* CreateFile() {
+ CDynaFile* rv = new CDynaFile(this);
+ if(rv->Create())
+ return rv;
+ delete rv;
+ return NULL;
+ }
+ CDynaFile* OpenFile(LONG fb) {
+ CDynaFile* rv = new CDynaFile(this);
+ if(rv->Open(fb))
+ return rv;
+ delete rv;
+ return NULL;
+ }
+ BOOL DeleteFile(LONG fb) {
+ while(fb>=0){
+ theBlock* b = m_File->GetCached(fb);
+ LONG nb = b->next;
+ Deallocate(fb);
+ fb=nb;
+ }
+ return TRUE;
+ }
+
+ LONG Allocate() {
+ if(!IsOpened())
+ return -1;
+ if(m_FB.freeFile<0){
+ LONG rv = m_File->AllocateNode();
+ theBlock *b = m_File->GetCached(rv);
+ b->next=-1;
+ m_File->MakeDirty(rv);
+ return rv;
+ }
+ LONG rv = m_FB.freeFile;
+ theBlock *b = m_File->GetCached(rv);
+ m_FB.freeFile=b->next;
+ b->next=-1;
+ m_File->MakeDirty(rv);
+ m_File->Write1stBlock(&m_FB);
+ return rv;
+ }
+ BOOL Deallocate(LONG bk) {
+ if(!IsOpened())
+ return FALSE;
+ theBlock* b = m_File->GetCached(bk);
+ ASSERT(b);
+ if(m_FB.freeFile<0){
+ b->next=-1;
+ m_FB.freeFile=bk;
+ }else{
+ b->next=m_FB.freeFile;
+ m_FB.freeFile=bk;
+ }
+ m_File->MakeDirty(bk);
+ m_File->Write1stBlock(&m_FB);
+ return TRUE;
+ }
+};
+
+};
+
+#endif // __DYNAMIDE_H
diff --git a/shared-code/FindIFace.h b/shared-code/FindIFace.h
new file mode 100644
index 0000000..8dec8c4
--- a/dev/null
+++ b/shared-code/FindIFace.h
@@ -0,0 +1,125 @@
+#ifndef __FINDIFACE_H
+#define __FINDIFACE_H
+
+#include "SNMPeer.h"
+#include "SNMPExtDLL.h"
+#include "SNMPOIDs.h"
+
+namespace Klever {
+
+inline BOOL FindIFace(in_addr& target,in_addr& source)
+{
+DEFINE_OID(ipRouteDest, OIDipRouteDest);
+DEFINE_OID(ipRouteMask, OIDipRouteMask);
+DEFINE_OID(ipRouteIfIndex, OIDipRouteIfIndex);
+DEFINE_OID(ipRouteMetric1, OIDipRouteMetric1);
+DEFINE_OID(ipAdEntIfIndex, OIDipAdEntIfIndex);
+DEFINE_OID(ipAdEntAddr, OIDipAdEntAddr);
+struct _route {
+ int iface;
+ int metric;
+ DWORD nm;
+} routes[16];
+int nRoutes = 0;
+CSNMPVarBindList vbl;
+ vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteDest,sizeof(ipRouteDest))));
+ vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteMask,sizeof(ipRouteMask))));
+ vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteIfIndex,sizeof(ipRouteIfIndex))));
+ vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteMetric1,sizeof(ipRouteMetric1))));
+CSNMPExtDLL snmp("INETMIB1");
+ while(nRoutes<(sizeof(routes)/sizeof(routes[0]))){
+ if(
+ snmp.Request(CASNAny::typeASNGetNextRequest,vbl,vbl)
+ && vbl.GetCount() == 4
+ ){
+ POSITION p = vbl.GetHeadPosition();
+ _route r = {-1,-1};
+ in_addr d, m;
+ BOOL bD = FALSE, bM = FALSE;
+ while(p){
+ CSNMPVarBind& vb = vbl.GetNext(p);
+ if(
+ vb.IsName(ipRouteDest,sizeof(ipRouteDest))
+ && vb.value.type==CASNAny::typeASNIP
+ ){
+ d.s_addr=vb.value.value.ip.s_addr; bD = TRUE;
+ }else if(
+ vb.IsName(ipRouteMask,sizeof(ipRouteMask))
+ && vb.value.type==CASNAny::typeASNIP
+ ){
+ m.s_addr=vb.value.value.ip.s_addr; bM = TRUE;
+ }else if(
+ vb.IsName(ipRouteIfIndex,sizeof(ipRouteIfIndex))
+ && vb.value.type==CASNAny::typeASNInteger
+ ){
+ r.iface=vb.value.value.number;
+ }else if(
+ vb.IsName(ipRouteMetric1,sizeof(ipRouteMetric1))
+ && vb.value.type==CASNAny::typeASNInteger
+ ){
+ r.metric=vb.value.value.number;
+ }else
+ break;
+ }
+ if(r.iface<0 || r.metric<0 || (!bD) || (!bM))
+ break;
+ if((target.s_addr&m.s_addr)==(d.s_addr&m.s_addr)){
+ r.nm=htonl(m.s_addr);
+ memmove(&routes[nRoutes++],&r,sizeof(routes[0]));
+ }
+ }else
+ break;
+ }
+ if(!nRoutes)
+ return FALSE;
+int rn = 0;
+ if(nRoutes>1){
+ for(int tmp=1;tmp<nRoutes;tmp++)
+ if(
+ routes[tmp].metric<routes[rn].metric
+ || routes[tmp].nm>routes[rn].nm
+ )
+ rn = tmp;
+ }
+int iface = routes[rn].iface;
+ vbl.RemoveAll();
+ vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipAdEntAddr,sizeof(ipAdEntAddr))));
+ vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipAdEntIfIndex,sizeof(ipAdEntIfIndex))));
+ for(;;){
+ if(
+ snmp.Request(CASNAny::typeASNGetNextRequest,vbl,vbl)
+ && vbl.GetCount()==2
+ ){
+ in_addr a; a.s_addr = INADDR_NONE;
+ int ifn = -1;
+ POSITION p = vbl.GetHeadPosition();
+ while(p){
+ CSNMPVarBind& vb = vbl.GetNext(p);
+ if(
+ vb.IsName(ipAdEntAddr,sizeof(ipAdEntAddr))
+ && vb.value.type==CASNAny::typeASNIP
+ ){
+ a.s_addr=vb.value.value.ip.s_addr;
+ }else if(
+ vb.IsName(ipAdEntIfIndex,sizeof(ipAdEntIfIndex))
+ && vb.value.type==CASNAny::typeASNInteger
+ ){
+ ifn = vb.value.value.number;
+ }else
+ break;
+ }
+ if(ifn<0)
+ break;
+ if(ifn==iface){
+ source.s_addr=a.s_addr;
+ return TRUE;
+ }
+ }else
+ break;
+ }
+ return FALSE;
+}
+
+};
+
+#endif // __FINDIFACE_H
diff --git a/shared-code/LRUCache.h b/shared-code/LRUCache.h
new file mode 100644
index 0000000..569e829
--- a/dev/null
+++ b/shared-code/LRUCache.h
@@ -0,0 +1,113 @@
+#ifndef __LRUCACHE_H
+#define __LRUCACHE_H
+
+namespace Klever {
+
+template<class IDX,class ARGIDX,class DATA>
+class CLRUCache : public CObject {
+public:
+ struct CacheEntry {
+ enum cacheState {
+ cacheClean, cacheDirty, cacheEmpty
+ };
+ cacheState m_State;
+ UINT m_hits;
+
+ IDX m_idx;
+ DATA* m_pData;
+
+ CacheEntry() { m_State=cacheEmpty; VERIFY(m_pData=new DATA); m_hits=0; }
+ virtual ~CacheEntry() { delete m_pData; }
+ };
+ typedef CMap<IDX,ARGIDX,CacheEntry*,CacheEntry*> CCacheMap;
+ typedef CList<CacheEntry*,CacheEntry*> CCacheList;
+
+ CCacheList m_Cache;
+ CCacheMap m_Map;
+
+ CLRUCache(UINT cacheSize) {
+ for(int tmp=0;tmp<cacheSize;tmp++){
+ CacheEntry* p = new CacheEntry;
+ m_Cache.AddTail(p);
+ }
+ }
+ virtual ~CLRUCache() {
+ Flush();
+ POSITION p = m_Cache.GetHeadPosition();
+ while(p){
+ CacheEntry* c = m_Cache.GetNext(p);
+ delete c;
+ }
+ }
+
+ DATA* GetCached(ARGIDX idx,BOOL bLoad=TRUE) {
+ CacheEntry* rv;
+ if(m_Map.Lookup(idx,rv)){
+ rv->m_hits++;
+ PopUp(rv);
+ return rv->m_pData;
+ }
+ if(!bLoad)
+ return NULL;
+ rv = m_Cache.GetTail();
+ ASSERT(rv);
+ switch(rv->m_State){
+ case CacheEntry::cacheDirty:
+ FlushEntry(rv);
+ case CacheEntry::cacheClean:
+ m_Map.RemoveKey(rv->m_idx);
+ rv->m_State=CacheEntry::cacheEmpty;
+ case CacheEntry::cacheEmpty:
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+ if(!_ReadIn(idx,rv->m_pData))
+ return NULL;
+ rv->m_hits=1;
+ rv->m_State=CacheEntry::cacheClean;
+ rv->m_idx=idx;
+ m_Map[idx]=rv;
+ PopUp(rv);
+ return rv->m_pData;
+ }
+ BOOL MakeDirty(ARGIDX idx) {
+ CacheEntry* pEntry;
+ if(m_Map.Lookup(idx,pEntry)){
+ ASSERT(pEntry->m_State==CacheEntry::cacheClean || pEntry->m_State==CacheEntry::cacheDirty);
+ pEntry->m_State=CacheEntry::cacheDirty;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ BOOL Flush() {
+ POSITION p = m_Cache.GetHeadPosition();
+ while(p){
+ CacheEntry* pEntry = m_Cache.GetNext(p);
+ ASSERT(pEntry);
+ FlushEntry(pEntry);
+ }
+ return TRUE;
+ }
+ BOOL FlushEntry(CacheEntry* pEntry) {
+ if(pEntry->m_State==CacheEntry::cacheDirty){
+ BOOL rv = _WriteOut(pEntry->m_idx,pEntry->m_pData);
+ if(rv)
+ pEntry->m_State=CacheEntry::cacheClean;
+ }
+ return FALSE;
+ }
+ void PopUp(CacheEntry* pEntry) {
+ POSITION p = m_Cache.Find(pEntry);
+ ASSERT(p);
+ m_Cache.RemoveAt(p);
+ VERIFY(m_Cache.AddHead(pEntry));
+ }
+
+ virtual BOOL _ReadIn(ARGIDX idx,DATA* data) = 0;
+ virtual BOOL _WriteOut(ARGIDX idx,DATA* data) = 0;
+};
+
+};
+
+#endif // __LRUCACHE_H
diff --git a/shared-code/RegEx.cpp b/shared-code/RegEx.cpp
new file mode 100644
index 0000000..b7bab62
--- a/dev/null
+++ b/shared-code/RegEx.cpp
@@ -0,0 +1,1697 @@
+#include "../stdafx.h"
+#include "RegEx.h"
+
+#define isWordableChar(c) (isalnum(c) || (c)=='_')
+
+BOOL CRegEx::Compile(LPCTSTR regex,int flags)
+{
+ ASSERT(!((flags&regExtended) && (flags&regLiteral)));
+ m_Matches.RemoveAll();
+ m_Strip.RemoveAll();
+ m_Strip.SetSize(0,15);
+ m_Pattern=regex;
+ m_ParsePointer=0;
+ m_Error=0;
+ m_Sets.RemoveAll();
+ m_Flags=flags;
+ m_iFlags=0;
+ m_BOLs=m_EOLs=0;
+ m_Subexps = 0;
+ m_Categories=1; // 0 is 'everything else'
+ m_bBackRefs=FALSE;
+ memset(m_Category,0,sizeof(m_Category));
+
+ // Go ahead.
+ m_Error || m_Strip.Add(CSop(CSop::opEnd));
+ if(flags&regExtended){
+ ParseERE();
+ }else if(flags&regLiteral){
+ ParseLiteral();
+ }else{
+ ParseBRE();
+ }
+ m_Error || m_Strip.Add(CSop(CSop::opEnd));
+ Categorize();
+ m_Strip.FreeExtra();
+ FigureMust();
+ m_Pluses=CountPluses();
+ if(m_iFlags&iflagsBad){
+ m_Error || (m_Error=regeAssert);
+ // ??? point to nuls? ;-)
+ }
+ // We may wish to free some memory here if we're erroneous (ie. m_Error..)
+ m_ParseParens.RemoveAll();
+#ifdef _DEBUG
+ if(m_Error){
+ CString tmp;
+ tmp.Format("RE: ParseError: %d\n",m_Error);
+ TRACE0(tmp);
+ }
+// DumpStrip(afxDump);
+#endif
+ return (m_bCompiled=(!m_Error));
+}
+
+BOOL CRegEx::Match(LPCTSTR src,int flags)
+{
+ if(!m_bCompiled)
+ return FALSE;
+ if(m_iFlags&iflagsBad)
+ return FALSE;
+ m_Input=src;
+ m_mFlags=flags;
+ m_mPointer=m_Input;
+ m_mBegin=m_Input;
+ m_mEnd=&m_mBegin[m_Input.GetLength()];
+ ASSERT(m_mPointer<=m_mEnd);
+ m_Matches.RemoveAll();
+ if(!m_Must.IsEmpty()){
+ if(m_Input.Find(m_Must)<0)
+ return FALSE;
+ }
+ // Go ahead..
+int stripLen = m_Strip.GetSize();
+ m_mLastPos.SetSize(0);
+ for(int tmp=0;tmp<stripLen;tmp++)
+ m_Strip[tmp].m_MatchData=0;
+LPCTSTR beginp = m_mBegin;
+LPCTSTR endp;
+ for(;;){
+ endp = MatchFast(beginp);
+ if(!endp)
+ return FALSE;
+ if((m_mFlags&regNoSubExpressions) && !m_bBackRefs)
+ break;
+ ASSERT(m_cOldP);
+ for(;;){
+ endp = MatchSlow(m_cOldP,m_mEnd,1,stripLen-1);
+ if(endp)
+ break;
+ ASSERT(m_cOldP<m_mEnd);
+ m_cOldP++;
+ }
+ if((m_mFlags&regOneMatch) && !m_bBackRefs)
+ break;
+ // Oh, his, we want the subexpression..
+ m_Matches.SetSize(m_Subexps+1);
+ LPCTSTR dp;
+ if(!m_bBackRefs && !(m_mFlags&regBackRefs)){
+ dp = MatchDissect(m_cOldP,endp,1,stripLen-1);
+ }else{
+ if(m_Pluses>0 && !m_mLastPos.GetSize())
+ m_mLastPos.SetSize(m_Pluses);
+ dp = MatchBackRef(m_cOldP,endp,1,stripLen-1,0);
+ }
+ if(dp)
+ break;
+ // Uh.. oh.. we couldn't find a subexpression-level match
+ ASSERT(m_bBackRefs);
+ ASSERT(m_Pluses==0 || m_mLastPos.GetSize());
+ for(;;){
+ if(dp || endp <= m_cOldP)
+ break; // defeat.. ?
+ endp = MatchSlow(m_cOldP,endp-1,1,stripLen-1);
+ if(!endp)
+ break; // defeat.. ?
+ // Try it on a shorter possibility..
+#ifdef _DEBUG
+ for(tmp=1;tmp<=m_Subexps;tmp++)
+ ASSERT(m_Matches[tmp].m_Begin<0 && m_Matches[tmp].m_End<0);
+#endif
+ dp = MatchBackRef(m_cOldP,endp,1,stripLen-1,0);
+ }
+ ASSERT((!dp) || dp==endp);
+ if(dp) // Found a shorter one..
+ break;
+ // Despite initial appearances, there is no match here
+ beginp = m_cOldP+1;
+ ASSERT(beginp<=m_mEnd);
+ }
+ // Fill in the detail if so requested..
+ if(!(m_mFlags&regNoSubExpressions)){
+ if(!m_Matches.GetSize())
+ m_Matches.SetSize(1);
+ m_Matches[0].m_Begin=m_cOldP-m_mBegin;
+ m_Matches[0].m_End=endp-m_mBegin;
+ }
+ m_mLastPos.RemoveAll();
+ return TRUE;
+}
+
+CString CRegEx::Replace(LPCTSTR src,LPCTSTR rep,int flags)
+{
+ // ***
+ return CString();
+}
+
+void CRegEx::ParseERE(int stop)
+{
+UCHAR c;
+BOOL first=TRUE;
+int prevF, prevB;
+ for(;;){
+ int co = m_Strip.GetSize();
+ while(m_ParsePointer < m_Pattern.GetLength() && ((c=m_Pattern[m_ParsePointer])!='|') && c!=stop)
+ ParseEREexp();
+ if(m_Strip.GetSize()==co){
+ m_Error || (m_Error=regeEmpty);
+ // ??? point to nuls?
+ }
+ if(m_ParsePointer>=m_Pattern.GetLength() || m_Pattern[m_ParsePointer]!='|')
+ break;
+ else
+ m_ParsePointer++;
+ if(first){
+ StripInsert(co,CSop(CSop::opChoice0,m_Strip.GetSize()-co+1));
+ prevF = prevB = co;
+ first=FALSE;
+ }
+ m_Error || m_Strip.Add(CSop(CSop::opOr0,m_Strip.GetSize()-prevB));
+ prevB = m_Strip.GetSize()-1;
+ m_Error || (m_Strip[prevF].m_Operand=m_Strip.GetSize()-prevF);
+ prevF = m_Strip.GetSize();
+ m_Error || m_Strip.Add(CSop(CSop::opOr1,0)); // offset isn't really right.. very so..
+ }
+ if(!first){
+ m_Error || (m_Strip[prevF].m_Operand=m_Strip.GetSize()-prevF);
+ m_Error || m_Strip.Add(CSop(CSop::opChoice1,m_Strip.GetSize()-prevB));
+ }
+ ASSERT(m_ParsePointer >= m_Pattern.GetLength() || m_Pattern[m_ParsePointer]==stop);
+}
+
+void CRegEx::ParseEREexp()
+{
+ ASSERT(m_ParsePointer < m_Pattern.GetLength());
+UCHAR c = m_Pattern[m_ParsePointer++];
+int pos = m_Strip.GetSize();
+int subno;
+int count, count2;
+BOOL wascaret=FALSE;
+ switch(c){
+ case '(':
+ if(!(m_ParsePointer<m_Pattern.GetLength())){
+ TRACE0("RE: '(' at the end of the pattern\n");
+ if(!m_Error)
+ m_Error = regeParen;
+ // ??? point to nuls?
+ }
+ m_Subexps++;
+ subno=m_Subexps;
+ m_ParseParens.SetAtGrow(m_Subexps,CParenthesis(m_Strip.GetSize()));
+ m_Error || m_Strip.Add(CSop(CSop::opLeftParen,subno));
+ if(m_ParsePointer>=m_Pattern.GetLength() || m_Pattern[m_ParsePointer]!=')')
+ ParseERE(')');
+ VERIFY(m_ParseParens[m_Subexps].m_End = m_Strip.GetSize());
+ m_Error || m_Strip.Add(CSop(CSop::opRightParen,subno));
+ if(m_ParsePointer >= m_Pattern.GetLength() || m_Pattern[m_ParsePointer++]!=')'){
+ TRACE0("RE: No matching ')'\n");
+ if(!m_Error)
+ m_Error = regeParen;
+ // ??? point to nuls?
+ }
+ break;
+ case '^':
+ m_Error || m_Strip.Add(CSop(CSop::opBOL));
+ m_iFlags|=iflagsUseBOL;
+ m_BOLs++;
+ wascaret=TRUE;
+ break;
+ case '$':
+ m_Error || m_Strip.Add(CSop(CSop::opEOL));
+ m_iFlags|=iflagsUseEOL;
+ m_EOLs++;
+ break;
+ case '|':
+ TRACE0("RE: '|' outside of expression\n");
+ if(!m_Error)
+ m_Error = regeEmpty;
+ // ??? point to nuls?
+ break;
+ case '*':
+ case '+':
+ case '?':
+ TRACE0("RE: '*'/'+'/'?' with no previous expression\n");
+ if(!m_Error)
+ m_Error = regeBadRepeat;
+ // ??? point to nuls?
+ break;
+ case '.':
+ if(m_Flags&regNewLine)
+ EmitNonNewLineAny();
+ else
+ m_Error || m_Strip.Add(CSop(CSop::opAny));
+ break;
+ case '[':
+ ParseBracket();
+ break;
+ case '\\':
+ if(m_ParsePointer >= m_Pattern.GetLength()){
+ TRACE0("RE: '\\' at the end of the pattern\n");
+ if(!m_Error)
+ m_Error = regeEscape;
+ // ??? point to nuls?
+ }else{
+ c = m_Pattern[m_ParsePointer++];
+ EmitOrdinary(c);
+ }
+ break;
+ case '{':
+ if(m_ParsePointer >= m_Pattern.GetLength() || !isdigit(m_Pattern[m_ParsePointer])){
+ TRACE0("RE: '{' with no repeat count\n");
+ if(!m_Error)
+ m_Error = regeBadRepeat;
+ // ??? point to nuls?
+ }
+ // Fallthrough..
+ default:
+ EmitOrdinary(c);
+ break;
+ }
+ if(m_ParsePointer >= m_Pattern.GetLength())
+ return;
+ c = m_Pattern[m_ParsePointer];
+ // Call a '{' repetition if followed by a digit
+ if (!(c=='*' || c=='+' || c=='?' || ( c=='{' && (m_ParsePointer+1) < m_Pattern.GetLength() && isdigit(m_Pattern[m_ParsePointer+1])) ))
+ return; // No repetitor - done.
+ m_ParsePointer++;
+ if(wascaret){
+ TRACE0("RE: repetitive '^' detected\n");
+ if(!m_Error)
+ m_Error = regeBadRepeat;
+ // ??? point to nuls?
+ }
+ switch(c){
+ case '*': // Implemeted as +?
+ // + expression
+ StripInsert(pos,CSop(CSop::opPlus0,m_Strip.GetSize()-pos+1));
+ m_Error || m_Strip.Add(CSop(CSop::opPlus1,m_Strip.GetSize()-pos));
+ // ? expression
+ StripInsert(pos,CSop(CSop::opQuest0,m_Strip.GetSize()-pos+1));
+ m_Error || m_Strip.Add(CSop(CSop::opQuest1,m_Strip.GetSize()-pos));
+ break;
+ case '+':
+ // + expression
+ StripInsert(pos,CSop(CSop::opPlus0,m_Strip.GetSize()-pos+1));
+ m_Error || m_Strip.Add(CSop(CSop::opPlus1,m_Strip.GetSize()-pos));
+ break;
+ case '?':
+ // Kludge - emit y? as (y|) until subtle bug gets fixed :-)
+ StripInsert(pos,CSop(CSop::opChoice0,m_Strip.GetSize()-pos+1));
+ m_Error || m_Strip.Add(CSop(CSop::opOr0,m_Strip.GetSize()-pos));
+ m_Error || (m_Strip[pos].m_Operand=m_Strip.GetSize()-pos);
+ m_Error || m_Strip.Add(CSop(CSop::opOr1,1));
+ m_Error || m_Strip.Add(CSop(CSop::opChoice1,2));
+ break;
+ case '{':
+ count = ParseCount();
+ if(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]==','){
+ m_ParsePointer++;
+ if(isdigit(m_Pattern[m_ParsePointer])){ // HHH Personally, I doubt it is always available
+ count2=ParseCount();
+ if(!(count<=count2)){
+ TRACE0("RE: Disbalanced counts in '{}' repeater\n");
+ m_Error || (m_Error=regeBadBrace);
+ // ??? point to nuls?
+ }
+ }else // Single number with comma
+ count2=256; // Infinity
+ }else // Single number
+ count2=count;
+ EmitRepeat(pos,count,count2);
+ if(m_ParsePointer >= m_Pattern.GetLength() || m_Pattern[m_ParsePointer]!='}'){
+ // No '}'..
+ TRACE0("RE: No immediately following '}' of '{' expression\n");
+ while(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]!='}')
+ m_ParsePointer++;
+ if(m_ParsePointer >= m_Pattern.GetLength()){
+ TRACE0("RE: No closing '}' found\n");
+ m_Error || (m_Error=regeBrace);
+ }else
+ m_Error || (m_Error=regeBadBrace);
+ // ??? point to nuls?
+ }else
+ m_ParsePointer++;
+ break;
+ }
+ if(m_ParsePointer >= m_Pattern.GetLength())
+ return;
+ c = m_Pattern[m_ParsePointer];
+ if(!(c=='*' || c=='+' || c=='?' || (c=='{' && (m_ParsePointer+1)<m_Pattern.GetLength() && isdigit(m_Pattern[m_ParsePointer+1]))))
+ return;
+ TRACE0("RE: Double repeater\n");
+ m_Error || (m_Error=regeBadRepeat);
+ // ??? point to nuls?
+}
+
+void CRegEx::StripInsert(int pos,CSop& sop)
+{
+ if(m_Error)
+ return;
+int sn = m_Strip.GetSize();
+ m_Strip.InsertAt(pos,sop);
+ for(int tmp=1;tmp<m_ParseParens.GetSize();tmp++){
+ if(m_ParseParens[tmp].m_Begin>=pos)
+ m_ParseParens[tmp].m_Begin++;
+ if(m_ParseParens[tmp].m_End>=pos)
+ m_ParseParens[tmp].m_End++;
+ }
+}
+
+void CRegEx::EmitOrdinary(UCHAR c)
+{
+ if(m_Flags&regIgnoreCase && isalpha(c) && (tolower(c) !=toupper(c))){
+ // Emit both cases
+ CString savePattern = m_Pattern;
+ int savePointer = m_ParsePointer;
+ m_Pattern=c;
+ m_Pattern+=']';
+ m_ParsePointer=0;
+ ParseBracket();
+ m_Pattern=savePattern;
+ m_ParsePointer=savePointer;
+ }else{
+ m_Error || m_Strip.Add(CSop(CSop::opChar,c));
+ if(!m_Category[(BYTE)c])
+ m_Category[(BYTE)c]=m_Categories++;
+ }
+}
+
+void CRegEx::EmitNonNewLineAny()
+{
+ // Kludges're going on and on..
+CString savePattern = m_Pattern;
+int savePointer = m_ParsePointer;
+ m_Pattern="^\n]";
+ m_ParsePointer=0;
+ ParseBracket();
+ m_Pattern=savePattern;
+ m_ParsePointer=savePointer;
+}
+
+int CRegEx::ParseCount()
+{
+BOOL nonEmpty=FALSE;
+int rv = 0;
+UCHAR c;
+ while(m_ParsePointer < m_Pattern.GetLength() && isdigit(c=m_Pattern[m_ParsePointer]) && rv <=255){
+ rv = rv*10 + c-'0';
+ nonEmpty=TRUE;
+ m_ParsePointer++;
+ }
+ if(rv>255 || !nonEmpty){
+ m_Error || (m_Error=regeBadBrace);
+ // ??? point to nuls?
+ }
+ return rv;
+}
+
+void CRegEx::ParseBracket()
+{
+ // Dept. of truly sickening special case kludges
+ if((m_ParsePointer+5) < m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,6).Compare("[:<]]")){
+ m_Error || m_Strip.Add(CSop(CSop::opBOW));
+ m_ParsePointer+=6;
+ return;
+ }
+ if((m_ParsePointer+5) < m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,6).Compare("[:>]]")){
+ m_Error || m_Strip.Add(CSop(CSop::opEOW));
+ m_ParsePointer+=6;
+ return;
+ }
+BOOL invert=TRUE;
+ if(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='^')
+ m_ParsePointer++;
+ else
+ invert=FALSE;
+CSet cset;
+ if(m_ParsePointer < m_Pattern.GetLength()){
+ switch(m_Pattern[m_ParsePointer]){
+ case ']':
+ case '-':
+ cset.Add(m_Pattern[m_ParsePointer]);
+ m_ParsePointer++;
+ break;
+ }
+ }
+ while(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]!=']' && !((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("-]")))
+ ParseBracketTerm(cset);
+ if(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='-'){
+ m_ParsePointer++;
+ cset.Add('-');
+ }
+ if(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]==']')
+ m_ParsePointer++;
+ else{
+ m_Error || (m_Error=regeBracket);
+ // ??? point to nuls?
+ return;
+ }
+ if(m_Flags&regIgnoreCase){
+ for(int tmp=CSet::size-1;tmp>=0;tmp--){
+ if(cset.IsIn(tmp) && isalpha(tmp) && (toupper(tmp)!=tolower(tmp)))
+ cset.Add(isupper(tmp)?tolower(tmp):toupper(tmp));
+ }
+ /*
+ if(!cset->m_Multis.IsEmpty())
+ cset.CollatingCase();
+ */
+ }
+ if(invert){
+ for(int tmp=CSet::size-1;tmp>=0;tmp--)
+ if(cset.IsIn(tmp))
+ cset.Sub(tmp);
+ else
+ cset.Add(tmp);
+ if(m_Flags&regNewLine)
+ cset.Sub('\n');
+ /*
+ if(!cset.m_Multis.IsEmpty())
+ cset.CollatingInvert();
+ */
+ }
+UCHAR c = cset.GetOnly();
+ if(c){
+ EmitOrdinary(c);
+ }else
+ m_Error || m_Strip.Add(CSop(CSop::opAnyOf,StoreSet(cset)));
+}
+
+void CRegEx::CSet::Add(UCHAR c)
+{
+ m_Set[(BYTE)c]=TRUE;
+ m_Hash+=c;
+}
+
+BOOL CRegEx::CSet::IsIn(UCHAR c)
+{
+ return m_Set[(BYTE)c];
+}
+
+void CRegEx::CSet::Sub(UCHAR c)
+{
+ m_Set[(BYTE)c]=FALSE;
+ m_Hash-=c;
+}
+
+UCHAR CRegEx::CSet::GetOnly()
+{
+int rv = 0;
+UCHAR only = 0;
+ for(int tmp=0;tmp<size;tmp++){
+ rv+=m_Set[tmp]?(only=tmp,1):0;
+ }
+ return (rv==1)?only:0;
+}
+
+int CRegEx::StoreSet(CSet& cset)
+{
+ for(int tmp=0;tmp<m_Sets.GetSize();tmp++)
+ if(m_Sets[tmp]==cset)
+ return tmp;
+ return m_Sets.Add(cset);
+}
+
+void CRegEx::ParseBracketTerm(CSet& cset)
+{
+UCHAR c;
+ switch((m_ParsePointer<m_Pattern.GetLength())?m_Pattern[m_ParsePointer]:0){
+ case '[':
+ c = ((m_ParsePointer+1)<m_Pattern.GetLength())?m_Pattern[m_ParsePointer+1]:0;
+ break;
+ case '-':
+ m_Error || (m_Error=regeRange);
+ // ??? point to nuls?
+ return;
+ default:
+ c = 0;
+ break;
+ }
+ switch(c){
+ case ':': // Character class
+ m_ParsePointer+=2;
+ if(m_ParsePointer>=m_Pattern.GetLength()){
+ m_Error || (m_Error=regeBracket);
+ // ??? point to nuls?
+ }
+ c = m_Pattern[m_ParsePointer];
+ if(c== '-' || c==']'){
+ m_Error || (m_Error=regeCType);
+ // ??? point to nuls?
+ }
+ ParseBracketCClass(cset);
+ if(m_ParsePointer>=m_Pattern.GetLength()){
+ m_Error || (m_Error=regeBracket);
+ // ??? point to nuls?
+ }
+ if((m_ParsePointer+1)>=m_Pattern.GetLength() || (m_Pattern.Mid(m_ParsePointer,2).Compare(":]"))){
+ m_Error || (m_Error=regeCType);
+ // ??? point to nuls?
+ }else
+ m_ParsePointer+=2;
+ break;
+ case '=': // Equivalence class
+ m_ParsePointer+=2;
+ if(m_ParsePointer >= m_Pattern.GetLength()){
+ m_Error || (m_Error=regeBracket);
+ // ??? point to nuls?
+ }
+ c = m_Pattern[m_ParsePointer];
+ if(c== '-' || c==']'){
+ m_Error || (m_Error=regeCollate);
+ // ??? point to nuls?
+ }
+ ParseBracketEClass(cset);
+ if((m_ParsePointer+1)>=m_Pattern.GetLength() || (m_Pattern.Mid(m_ParsePointer,2).Compare("=]"))){
+ m_Error || (m_Error=regeCollate);
+ // ??? point to nuls?
+ }else
+ m_ParsePointer+=2;
+ break;
+ default: // Symbol, character or range
+ {
+ UCHAR start, finish;
+ start = ParseBracketSymbol();
+ if((m_ParsePointer<m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='-') /*&& (m_ParsePointer+1)<m_Pattern.GetLength() && m_Pattern[m_ParsePointer+1]==']'*/){
+ // I believe the expression above is seetwo..
+ // range.
+ m_ParsePointer++;
+ if(m_ParsePointer<m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='-'){
+ m_ParsePointer++;
+ finish='-';
+ }else
+ finish=ParseBracketSymbol();
+ }else
+ finish=start;
+ if(((BYTE)start)>((BYTE)finish)){
+ m_Error || (m_Error=regeRange);
+ // ??? point to nuls?
+ }
+ for(int tmp=start;tmp<=(BYTE)finish;tmp++)
+ cset.Add(tmp);
+ }
+ break;
+ }
+}
+
+void CRegEx::ParseBracketCClass(CSet& cset)
+{
+static struct {
+ char *className;
+ char *classChars;
+} cc[] = {
+ {"alnum","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
+ {"alpha","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"},
+ {"blank"," \t"},
+ {"cntrl","\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"},
+ {"digit","0123456789"},
+ {"graph","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"},
+ {"lower","abcdefghijklmnopqrstuvwxyz"},
+ {"print","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ "},
+ {"punct","!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"},
+ {"space","\t\n\v\f\r "},
+ {"upper","ABCDEFGHIJKLMNOPQRSTUVWXYZ"},
+ {"xdigit","0123456789ABCDEFabcdef"}
+};
+CString cclass;
+UCHAR c;
+ while(m_ParsePointer < m_Pattern.GetLength() && isalpha(c=m_Pattern[m_ParsePointer])){
+ cclass+=c;
+ m_ParsePointer++;
+ }
+char *classChars = NULL;
+ for(int tmp=0;tmp<(sizeof(cc)/sizeof(cc[0]));tmp++){
+ if(!cclass.CompareNoCase(cc[tmp].className)){
+ classChars=cc[tmp].classChars;
+ break;
+ }
+ }
+ if(!classChars){
+ m_Error || (m_Error=regeCType);
+ // ??? point to nuls?
+ return;
+ }
+ while(*classChars)
+ cset.Add(*(classChars++));
+ // --- multis
+}
+
+void CRegEx::ParseBracketEClass(CSet& cset)
+{
+ cset.Add(ParseBracketCollatingElement('='));;
+}
+
+UCHAR CRegEx::ParseBracketCollatingElement(UCHAR term)
+{
+static struct {
+ char *entityName;
+ char entity;
+} cc[] = { {"NUL",'\0'},{"SOH",'\001'},{"STX",'\002'},{"ETX",'\003'},{"EOT",'\004'},{"ENQ",'\005'},{"ACK",'\006'},{"BEL",'\007'},{"alert",'\007'},{"BS",'\010'},{"backspace",'\b'},{"HT",'\011'},{"tab",'\t'},{"LF",'\012'},{"newline",'\n'},{"VT",'\013'},{"vertical-tab",'\v'},{"FF",'\014'},{"form-feed",'\f'},{"CR",'\015'},{"carriage-return",'\r'},{"SO",'\016'},{"SI",'\017'},{"DLE",'\020'},{"DC1",'\021'},{"DC2",'\022'},{"DC3",'\023'},{"DC4",'\024'},{"NAK",'\025'},{"SYN",'\026'},{"ETB",'\027'},{"CAN",'\030'},{"EM",'\031'},{"SUB",'\032'},{"ESC",'\033'},{"IS4",'\034'},{"FS",'\034'},{"IS3",'\035'},{"GS",'\035'},{"IS2",'\036'},{"RS",'\036'},{"IS1",'\037'},{"US",'\037'},{"space",' '},{"exclamation-mark",'!'},{"quotation-mark",'"'},{"number-sign",'#'},{"dollar-sign",'$'},{"percent-sign",'%'},{"ampersand",'&'},{"apostrophe",'\''},{"left-parenthesis",'('},{"right-parenthesis",')'},{"asterisk",'*'},{"plus-sign",'+'},{"comma",','},{"hyphen",'-'},{"hyphen-minus",'-'},{"period",'.'},{"full-stop",'.'},{"slash",'/'},{"solidus",'/'},{"zero",'0'},{"one",'1'},{"two",'2'},{"three",'3'},{"four",'4'},{"five",'5'},{"six",'6'},{"seven",'7'},{"eight",'8'},{"nine",'9'},{"colon",':'},{"semicolon",';'},{"less-than-sign",'<'},{"equals-sign",'='},{"greater-than-sign",'>'},{"question-mark",'?'},{"commercial-at",'@'},{"left-square-bracket",'['},{"backslash",'\\'},{"reverse-solidus",'\\'},{"right-square-bracket",']'},{"circumflex",'^'},{"circumflex-accent",'^'},{"underscore",'_'},{"low-line",'_'},{"grave-accent",'`'},{"left-brace",'{'},{"left-curly-bracket",'{'},{"vertical-line",'|'},{"right-brace",'}'},{"right-curly-bracket",'}'},{"tilde",'~'},{"DEL",'\177'} };
+CString seeTwo;
+ seeTwo=term;
+ seeTwo+=']';
+CString entityName;
+ while(m_ParsePointer<m_Pattern.GetLength() && !((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare(seeTwo)))
+ entityName+=m_Pattern[m_ParsePointer++];
+ if(m_ParsePointer>=m_Pattern.GetLength()){
+ m_Error || (m_Error=regeBracket);
+ // ??? point to nuls?
+ return 0;
+ }
+ for(int tmp=0;tmp<(sizeof(cc)/sizeof(cc[0]));tmp++)
+ if(!entityName.CompareNoCase(cc[tmp].entityName))
+ return cc[tmp].entity;
+ if(entityName.GetLength()==1)
+ return entityName[0];
+ m_Error || (m_Error=regeCollate);
+ // ??? point to nuls?
+ return 0;
+}
+
+UCHAR CRegEx::ParseBracketSymbol()
+{
+ if(m_ParsePointer>=m_Pattern.GetLength()){
+ m_Error || (m_Error=regeBracket);
+ // ??? point to nuls?
+ }
+ if((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("[."))
+ m_ParsePointer+=2;
+ else
+ return m_Pattern[m_ParsePointer++];
+ // Collating symbol
+UCHAR rv = ParseBracketCollatingElement('.');
+ if((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("[."))
+ m_ParsePointer+=2;
+ else{
+ m_Error || (m_Error=regeCollate);
+ // ??? point to nuls?
+ }
+ return rv;
+}
+
+void CRegEx::EmitRepeat(int pos,int from,int to)
+{
+ if(m_Error)
+ return;
+ ASSERT(from<=to);
+int finish = m_Strip.GetSize();
+int copy;
+#define N 2
+#define INF 3
+#define REP(f,t) ((f)*8+(t))
+#define MAP(n) (((n)<=1)?(n):((n)==256)?INF:N)
+ switch(REP(MAP(from),MAP(to))){
+ case REP(0,0): // must be user doing ths??
+ m_Strip.SetSize(pos);
+ break;
+ case REP(0,1): // as in '?'
+ case REP(0,N): // as in '{1,n}?'
+ case REP(0,INF): // as in '{1,}?'
+ // Kludge - emit y? as (y|) until something gets fixed..
+ StripInsert(pos,CSop(CSop::opChoice0,pos));
+ EmitRepeat(pos+1,1,to);
+ m_Error || m_Strip.Add(CSop(CSop::opOr0,m_Strip.GetSize()-pos));
+ m_Error || (m_Strip[pos].m_Operand=m_Strip.GetSize()-pos);
+ m_Error || m_Strip.Add(CSop(CSop::opOr1,1));
+ m_Error || m_Strip.Add(CSop(CSop::opChoice1,2));
+ break;
+ case REP(1,1):
+ break;
+ case REP(1,N): // as in 'x?x{1,n-1}'
+ // Kludge again..
+ StripInsert(pos,CSop(CSop::opChoice0,pos));
+ m_Error || m_Strip.Add(CSop(CSop::opOr0,m_Strip.GetSize()-pos));
+ m_Error || (m_Strip[pos].m_Operand=m_Strip.GetSize()-pos);
+ m_Error || m_Strip.Add(CSop(CSop::opOr1,1));
+ m_Error || m_Strip.Add(CSop(CSop::opChoice1,2));
+ copy = StripDuplicate(pos+1,finish+1);
+ ASSERT(copy==(finish+4));
+ EmitRepeat(copy,1,to-1);
+ break;
+ case REP(1,INF): // as in '+'
+ StripInsert(pos,CSop(CSop::opPlus0,pos));
+ m_Error || m_Strip.Add(CSop(CSop::opPlus1,m_Strip.GetSize()-pos));
+ break;
+ case REP(N,N): // as in 'xx{from-1,to-1}'
+ copy = StripDuplicate(pos,finish);
+ EmitRepeat(copy,from-1,to-1);
+ break;
+ case REP(N,INF): // as in 'xx{n-1,}'
+ copy = StripDuplicate(pos,finish);
+ EmitRepeat(copy,from-1,to);
+ break;
+#ifndef NDEBUG
+ default:
+ ASSERT(FALSE);
+ break;
+#endif
+ }
+#undef MAP
+#undef REP
+#undef INF
+#undef N
+}
+
+int CRegEx::StripDuplicate(int from,int to)
+{
+int rv = m_Strip.GetSize();
+ ASSERT(from<=to);
+ if(from==to)
+ return rv;
+ // Maybe should be optimized for copying the whole thing.
+ for(int tmp=from;tmp<to;tmp++)
+ m_Strip.Add(m_Strip[tmp]);
+ return rv;
+}
+
+void CRegEx::Categorize()
+{
+ if(m_Error)
+ return;
+ for(int tmp=0;tmp<(sizeof(m_Category)/sizeof(m_Category[0]));tmp++)
+ if((!m_Category[tmp]) && IsInSets(tmp)){
+ int cat = m_Categories++;
+ m_Category[tmp]=cat;
+ for(int c=tmp+1;c<(sizeof(m_Category)/sizeof(m_Category[0]));c++)
+ if((!m_Category[c]) && IsInSameSets(tmp,c))
+ m_Category[c]=cat;
+ }
+}
+
+BOOL CRegEx::IsInSets(UCHAR c)
+{
+ for(int tmp=0;tmp<m_Sets.GetSize();tmp++)
+ if(m_Sets[tmp].IsIn(c))
+ return TRUE;
+ return FALSE;
+}
+
+BOOL CRegEx::IsInSameSets(UCHAR c1,UCHAR c2)
+{
+ for(int tmp=0;tmp<m_Sets.GetSize();tmp++)
+ if(m_Sets[tmp].IsIn(c1)!=m_Sets[tmp].IsIn(c2))
+ return FALSE;
+ return TRUE;
+}
+
+void CRegEx::FigureMust()
+{
+ if(m_Error)
+ return;
+ m_Must.Empty();
+int stripLen = m_Strip.GetSize();
+int seqStart, seqLength = 0;
+int mustStart, mustLength = 0;
+ for(int tmp=1;tmp<stripLen;tmp++){
+ switch(m_Strip[tmp].m_Operator){
+ case CSop::opChar:
+ if(!seqLength)
+ seqStart=tmp;
+ seqLength++;
+ break;
+ case CSop::opPlus0:
+ case CSop::opLeftParen:
+ case CSop::opRightParen:
+ break; // Break, since they don't break the sequence
+ case CSop::opQuest0:
+ case CSop::opChoice0:
+ // These ones we skip.
+ do{
+ tmp+=m_Strip[tmp].m_Operand;
+ // I still think it could be ASSERTed..
+ if(m_Strip[tmp].m_Operator!=CSop::opQuest1 && m_Strip[tmp].m_Operator!=CSop::opChoice1 && m_Strip[tmp].m_Operator!=CSop::opOr1){
+ m_iFlags|=iflagsBad;
+ return;
+ }
+ }while(m_Strip[tmp].m_Operator!=CSop::opQuest1 && m_Strip[tmp].m_Operator!=CSop::opChoice1);
+ // Fallthrough..
+ default:
+ // End of sequence
+ if(seqLength>mustLength){
+ mustStart=seqStart;
+ mustLength=seqLength;
+ }
+ seqLength=0;
+ break;
+ }
+ } // Hmm.. originally it's meant to be do while not opEnd..
+ if(!mustLength)
+ return;
+ // Turn into string, but, wait, personally I'm sure it could be put in the main loop.. or maybe not..
+ for(tmp=0;tmp<seqLength;tmp++){
+ while(m_Strip[seqStart+tmp].m_Operator!=CSop::opChar)
+ ASSERT(tmp<seqLength);
+ m_Must+=m_Strip[tmp].m_Operand;
+ }
+}
+
+int CRegEx::CountPluses()
+{
+ if(m_Error)
+ return 0;
+int stripLen = m_Strip.GetSize();
+int rv = 0;
+int nest = 0;
+ for(int tmp=0;tmp<stripLen;tmp++){
+ switch(m_Strip[tmp].m_Operator){
+ case CSop::opPlus0:
+ nest++;
+ break;
+ case CSop::opPlus1:
+ if(nest>rv)
+ rv = nest;
+ nest--;
+ break;
+ }
+ } // Again, originally we were supposed to scan till opEnd..
+ if(nest)
+ m_iFlags|=iflagsBad; // Could this be an ASSERTion?
+ return rv;
+}
+
+void CRegEx::ParseLiteral()
+{
+ if(!m_Pattern.GetLength()){
+ m_Error || (m_Error=regeEmpty);
+ // ??? point to nuls?
+ }
+ while(m_ParsePointer < m_Pattern.GetLength())
+ EmitOrdinary(m_Pattern[m_ParsePointer++]);
+}
+
+void CRegEx::ParseBRE(int stopa,int stopb)
+{
+int start = m_Strip.GetSize();
+BOOL first=TRUE;
+BOOL wasDollar=FALSE;
+ if(m_ParsePointer<m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='^'){
+ m_ParsePointer++;
+ m_Error || m_Strip.Add(CSop(CSop::opBOL,0));
+ m_iFlags|=iflagsUseBOL;
+ m_BOLs++;
+ }
+CString stopstr;
+ if(stopa){
+ stopstr+=stopa;
+ if(stopb)
+ stopstr+=stopb;
+ }
+ while(m_ParsePointer < m_Pattern.GetLength() && !((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare(stopstr))){
+ wasDollar = ParseBREexp(first);
+ first=FALSE;
+ }
+ if(wasDollar){ // Trailing anchor that was..
+ m_Strip.SetSize(m_Strip.GetSize()-1);
+ m_Error || m_Strip.Add(CSop(CSop::opEOL,0));
+ m_iFlags|=iflagsUseEOL;
+ m_EOLs++;
+ }
+ if(m_Strip.GetSize()==start){
+ m_Error || (m_Error=regeEmpty);
+ // ??? point to nuls?
+ }
+}
+
+BOOL CRegEx::ParseBREexp(BOOL ordinaryStar)
+{
+int subno;
+int pos = m_Strip.GetSize();
+ ASSERT(m_ParsePointer<m_Pattern.GetLength());
+int c = m_Pattern[m_ParsePointer++];
+ if(c=='\\'){
+ if(m_ParsePointer>=m_Pattern.GetLength()){
+ m_Error || (m_Error=regeEscape);
+ // ??? point to nuls
+ }else
+ c = 0x100|m_Pattern[m_ParsePointer++];
+ }
+ switch(c){
+ case '.':
+ if(m_Flags&regNewLine)
+ EmitNonNewLineAny();
+ else
+ m_Error || m_Strip.Add(CSop(CSop::opAny,0));
+ break;
+ case '[':
+ ParseBracket();
+ break;
+ case 0x100|'{':
+ m_Error || (m_Error=regeBadRepeat);
+ // ??? point to nuls?
+ break;
+ case 0x100|'(':
+ m_Subexps++;
+ subno=m_Subexps;
+ m_ParseParens.SetAtGrow(m_Subexps,CParenthesis(m_Strip.GetSize()));
+ m_Error || m_Strip.Add(CSop(CSop::opLeftParen,subno));
+ if(m_ParsePointer<m_Pattern.GetLength() && !((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("\\)")))
+ ParseBRE('\\',')');
+ VERIFY(m_ParseParens[m_Subexps].m_End = m_Strip.GetSize());
+ m_Error || m_Strip.Add(CSop(CSop::opRightParen,subno));
+ if((m_ParsePointer+1) < m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("\\)"))
+ m_ParsePointer+=2;
+ else{
+ m_Error || (m_Error=regeParen);
+ // ??? point to nuls?
+ }
+ break;
+ case 0x100|')':
+ case 0x100|'}':
+ // Can this possibly happen?!
+ m_Error || (m_Error=regeParen);
+ // ??? point to nuls?
+ break;
+ case 0x100|'1':
+ case 0x100|'2':
+ case 0x100|'3':
+ case 0x100|'4':
+ case 0x100|'5':
+ case 0x100|'6':
+ case 0x100|'7':
+ case 0x100|'8':
+ case 0x100|'9':
+ {
+ int i = (c&0xFF)-'0';
+ if(i < m_ParseParens.GetSize() && m_ParseParens[i].m_End){
+ m_Error || m_Strip.Add(CSop(CSop::opBackRef0,i));
+ ASSERT(m_ParseParens[i].m_Begin);
+ ASSERT(m_Strip[m_ParseParens[i].m_Begin].m_Operator==CSop::opLeftParen);
+ ASSERT(m_Strip[m_ParseParens[i].m_End].m_Operator==CSop::opRightParen);
+ StripDuplicate(m_ParseParens[i].m_Begin+1,m_ParseParens[i].m_End);
+ m_Error || m_Strip.Add(CSop(CSop::opBackRef1,i));
+ }else{
+ m_Error || (m_Error=regeSubReg);
+ // ??? point to nuls?
+ }
+ m_bBackRefs=TRUE;
+ }
+ break;
+ case '*':
+ if(!ordinaryStar){
+ m_Error || (m_Error=regeBadRepeat);
+ // ??? point to nuls?
+ }
+ // Fallthrough..
+ default:
+ EmitOrdinary(c&0xFF);
+ break;
+ }
+ if(m_ParsePointer<m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='*'){
+ m_ParsePointer++;
+ // as in '+?'
+ StripInsert(pos,CSop(CSop::opPlus0,m_Strip.GetSize()-pos+1));
+ m_Error || m_Strip.Add(CSop(CSop::opPlus1,m_Strip.GetSize()-pos));
+ StripInsert(pos,CSop(CSop::opQuest0,m_Strip.GetSize()-pos+1));
+ m_Error || m_Strip.Add(CSop(CSop::opQuest1,m_Strip.GetSize()-pos));
+ }else if ((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("\\{")){
+ m_ParsePointer+=2;
+ int count = ParseCount();
+ int count2;
+ if(m_ParsePointer<m_Pattern.GetLength() && m_Pattern[m_ParsePointer]==','){
+ m_ParsePointer++;
+ if(m_ParsePointer<m_Pattern.GetLength() && isdigit(m_Pattern[m_ParsePointer])){
+ count2=ParseCount();
+ if(count>count2){
+ m_Error || (m_Error=regeBadBrace);
+ // ??? poin to nuls?
+ }
+ }else // Single number with comma
+ count2=256;
+ }else // Single number
+ count2=count;
+ EmitRepeat(pos,count,count2);
+ if((m_ParsePointer+1)>=m_Pattern.GetLength() || m_Pattern.Mid(m_ParsePointer,2).Compare("\\}")){
+ while(m_ParsePointer<m_Pattern.GetLength() && !((m_ParsePointer+1)<m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,2).Compare("\\}")))
+ m_ParsePointer++;
+ if(m_ParsePointer>=m_Pattern.GetLength()){
+ m_Error || (m_Error=regeBrace);
+ // ??? point to nuls?
+ }
+ m_Error || (m_Error=regeBadBrace);
+ }else
+ m_ParsePointer+=2;
+ }else if(c=='$')
+ return TRUE;
+ return FALSE;
+}
+
+CRegEx::CRegEx()
+{
+ m_bCompiled=FALSE;
+}
+
+LPCTSTR CRegEx::MatchFast(LPCTSTR begin)
+{
+ MatchStatesClear(CSop::stCurrent);
+ m_Strip[1].m_MatchData|=CSop::stCurrent;
+int stripLen = m_Strip.GetSize();
+ MatchStep(1,stripLen-1,CSop::stCurrent,charNothing,CSop::stCurrent);
+ MatchStatesCopy(CSop::stFresh,CSop::stCurrent);
+LPCTSTR coldp = NULL;
+LPCTSTR p = begin;
+int c = (begin==m_mBegin)?charOut:((int)(BYTE)m_mPointer[-1]);
+ for(;;){
+ // next character..
+ int lastc = c;
+ c = (p==m_mEnd)?charOut:(int)*(BYTE*)p;
+ if(MatchStatesEqual(CSop::stCurrent,CSop::stFresh))
+ coldp=p;
+ // Is there an EOL and/or BOL between lastc and c? - they ask..
+ int flagc=0;
+ int i = 0;
+ if((lastc=='\n' && m_Flags&regNewLine) || (lastc==charOut && !(m_mFlags&regNotBOL))){
+ flagc=charBOL;
+ i=m_BOLs;
+ }
+ if((c=='\n' && m_Flags&regNewLine) || (c==charOut && !(m_mFlags&regNotEOL))){
+ flagc=(flagc==charBOL)?charBOLEOL:charEOL;
+ i+=m_EOLs;
+ }
+ if(i){
+ for(;i>0;i--)
+ MatchStep(1,stripLen-1,CSop::stCurrent,flagc,CSop::stCurrent);
+ }
+ // What about a word boundary? - they wonder..
+ if((flagc==charBOL || (lastc!=charOut && !isWordableChar(c))) && (c!=charOut && isWordableChar(c)))
+ flagc = charBOW;
+ if((lastc!=charOut && isWordableChar(lastc)) && (flagc==charEOL || (c!=charOut && !isWordableChar(c))))
+ flagc = charEOW;
+ if(flagc==charBOW || flagc==charEOW){
+ MatchStep(1,stripLen-1,CSop::stCurrent,flagc,CSop::stCurrent);
+ }
+ // Are we done? Now WE wonder..
+ if((m_Strip[stripLen-1].m_MatchData&CSop::stCurrent) || p==m_mEnd)
+ break; // They insist I need to note break out.. Okay, I do..
+ // Nope, we're not done. We have to face this character..
+ MatchStatesCopy(CSop::stTemp,CSop::stCurrent);
+ MatchStatesCopy(CSop::stCurrent,CSop::stFresh);
+ ASSERT(c!=charOut);
+ MatchStep(1,stripLen-1,CSop::stTemp,c,CSop::stCurrent);
+ p++;
+ }
+ ASSERT(coldp);
+ m_cOldP=coldp; // *** I believe this variable can be changed 'in-place'
+ if(m_Strip[stripLen-1].m_MatchData&CSop::stCurrent)
+ return &p[1];
+ else
+ return NULL;
+}
+
+void CRegEx::MatchStatesClear(BYTE mask)
+{
+int stripLen = m_Strip.GetSize();
+ for(int tmp=0;tmp<stripLen;tmp++)
+ m_Strip[tmp].m_MatchData&=~mask;
+}
+
+void CRegEx::MatchStep(int from,int to,BYTE maskBefore,int charCode,BYTE maskAfter)
+{
+BOOL i;
+int look;
+int here = from;
+ for(int pc=from;pc!=to;pc++,here++){
+ CSop s=m_Strip[pc];
+ switch(s.m_Operator){
+ case CSop::opEnd:
+ ASSERT(pc==(to-1));
+ break;
+ case CSop::opChar:
+ // Only characters can match..
+ ASSERT((charCode<charOut) || charCode!=s.m_Operand);
+ if(charCode==s.m_Operand)
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opBOL:
+ if(charCode==charBOL || charCode==charBOLEOL)
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opEOL:
+ if(charCode==charEOL || charCode==charBOLEOL)
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opBOW:
+ if(charCode==charBOW)
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opEOW:
+ if(charCode==charEOW)
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opAny:
+ if(charCode<charOut)
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opAnyOf:
+ if(charCode<charOut && m_Sets[s.m_Operand].m_Set[charCode])
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskBefore)?maskAfter:0;
+ break;
+ case CSop::opBackRef0: // Ignored here..
+ case CSop::opBackRef1:
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+ case CSop::opPlus0:
+ // Forward, this is just an empty, comment says..
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+ case CSop::opPlus1:
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ i =(m_Strip[here-s.m_Operand].m_MatchData&maskAfter)!=0;
+ m_Strip[here-s.m_Operand].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ if(!i && (m_Strip[here-s.m_Operand].m_MatchData&maskAfter)){
+ // oho, must reconsider loop body, comment says.. what's so 'oho' about it?
+ pc-=s.m_Operand+1;
+ here=pc;
+ }
+ break;
+ case CSop::opQuest0:
+ // two branches, both forward..
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ m_Strip[here+s.m_Operand].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+ case CSop::opQuest1:
+ // just an empty.. aren't we tired of justanempties?
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+ case CSop::opLeftParen: // they say it's not significan there..
+ case CSop::opRightParen:
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+ case CSop::opChoice0: // mark the first two branches..
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ ASSERT(m_Strip[pc+s.m_Operand].m_Operator==CSop::opOr1);
+ m_Strip[here+s.m_Operand].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+ case CSop::opOr0: // done a branch, find the end of choice..
+ if(m_Strip[here].m_MatchData&maskAfter){
+ for(look=1;(s=m_Strip[pc+look]).m_Operator!=CSop::opChoice1;look+=s.m_Operand)
+ ASSERT(s.m_Operator==CSop::opOr1);
+ m_Strip[here+look].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ }
+ break;
+ case CSop::opOr1: // Propagate Choice's marking..
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ if(m_Strip[pc+s.m_Operand].m_Operator!=CSop::opChoice1){
+ ASSERT(m_Strip[pc+s.m_Operand].m_Operator==CSop::opOr1);
+ m_Strip[here+s.m_Operand].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ }
+ break;
+ case CSop::opChoice1: // Just empty.. :-)..
+ m_Strip[here+1].m_MatchData|=(m_Strip[here].m_MatchData&maskAfter)?maskAfter:0;
+ break;
+#ifdef _DEBUG
+ default:
+ ASSERT(FALSE);
+ break;
+#endif
+ }
+ }
+}
+
+void CRegEx::MatchStatesCopy(BYTE dst,BYTE src)
+{
+int stripLen = m_Strip.GetSize();
+ for(int tmp=0;tmp<stripLen;tmp++){
+ // I believe this can be optimized, easily..
+ m_Strip[tmp].m_MatchData&=~dst;
+ m_Strip[tmp].m_MatchData|=(m_Strip[tmp].m_MatchData&src)?dst:0;
+ }
+}
+
+BOOL CRegEx::MatchStatesEqual(BYTE m1,BYTE m2)
+{
+int stripLen = m_Strip.GetSize();
+ for(int tmp=0;tmp<stripLen;tmp++){
+ BYTE mm = m_Strip[tmp].m_MatchData;
+ if(((mm&m1) && (mm&m2)) || !(mm&(m1|m2)))
+ continue;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+LPCTSTR CRegEx::MatchSlow(LPCTSTR begin,LPCTSTR end,int from,int to)
+{
+ MatchStatesClear(CSop::stCurrent);
+ m_Strip[from].m_MatchData|=CSop::stCurrent;
+ MatchStep(from,to,CSop::stCurrent,charNothing,CSop::stCurrent);
+LPCTSTR mp = NULL;
+int c = (m_mBegin==m_mPointer)?charOut:(int)(BYTE)begin[-1];
+LPCTSTR p = begin;
+ for(;;){
+ // next character..
+ int lastc = c;
+ c = (p==m_mEnd)?charOut:(int)*(BYTE*)p;
+ // Now we start to wonder if there is an EOL and/or BOL between lastc and c
+ int flagc = 0;
+ int i = 0;
+ if((lastc=='\n' && m_Flags&regNewLine) || (lastc==charOut && !(m_mFlags&regNotBOL))){
+ flagc = charBOL;
+ i = m_BOLs;
+ }
+ if((c=='\n' && m_Flags&regNewLine) || (c==charOut && !(m_mFlags&regNotEOL))){
+ flagc = (flagc==charBOL)?charBOLEOL:charEOL;
+ i+=m_EOLs;
+ }
+ if(i){
+ for(;i>0;i--)
+ MatchStep(from,to,CSop::stCurrent,flagc,CSop::stCurrent);
+ }
+ // Now we wonder about word boundaries..
+ if((flagc==charBOL || (lastc!=charOut && !isWordableChar(lastc))) && (c!=charOut && isWordableChar(c)))
+ flagc=charBOW;
+ if((lastc!=charOut && isWordableChar(lastc)) && (flagc==charEOL || (c!=charOut && !isWordableChar(c))))
+ flagc=charEOW;
+ if(flagc==charBOW || flagc==charEOW){
+ MatchStep(from,to,CSop::stCurrent,flagc,CSop::stCurrent);
+ }
+ // Are we done we all wonder??
+ if(m_Strip[to].m_MatchData&CSop::stCurrent)
+ mp=p;
+ if(MatchStatesEqual(CSop::stCurrent,CSop::stEmpty) || p==end)
+ break; // Again, we're obliged to note break out. We do.
+ // Sucks.. we have to face this character..
+ MatchStatesCopy(CSop::stTemp,CSop::stCurrent);
+ MatchStatesCopy(CSop::stCurrent,CSop::stEmpty);
+ ASSERT(c!=charOut);
+ MatchStep(from,to,CSop::stTemp,c,CSop::stCurrent);
+ MatchStep(from,to,CSop::stCurrent,charNothing,CSop::stCurrent);
+ p++;
+ }
+ return mp;
+}
+
+LPCTSTR CRegEx::MatchDissect(LPCTSTR begin,LPCTSTR end,int from,int to)
+{
+LPCTSTR sp = begin, dp;
+LPCTSTR stp, rest, tail, ssp, oldssp, sep;
+int ssub, esub;
+int es;
+int i;
+ for(int ss=from;ss<to;ss = es){
+ // Identify end of SubRE
+ es = ss;
+ switch(m_Strip[es].m_Operator){
+ case CSop::opPlus0:
+ case CSop::opQuest0:
+ es+=m_Strip[es].m_Operand;
+ break;
+ case CSop::opChoice0:
+ while(m_Strip[es].m_Operator!=CSop::opChoice1)
+ es+=m_Strip[es].m_Operand;
+ break;
+ }
+ es++;
+ // Figure out what it matched
+ switch(m_Strip[ss].m_Operator){
+ case CSop::opEnd:
+ ASSERT(FALSE);
+ break;
+ case CSop::opChar:
+ sp++;
+ break;
+ case CSop::opBOL:
+ case CSop::opEOL:
+ case CSop::opBOW:
+ case CSop::opEOW:
+ break;
+ case CSop::opAny:
+ case CSop::opAnyOf:
+ sp++;
+ break;
+ case CSop::opBackRef0:
+ case CSop::opBackRef1:
+ ASSERT(FALSE);
+ break;
+ // Cases where lenght of match is hard to find..
+ case CSop::opQuest0:
+ stp=end;
+ for(;;){
+ // How long could this one be??
+ rest = MatchSlow(sp,stp,ss,es);
+ ASSERT(rest); // It did match.. It should've..
+ // Could the rest match the rest? (good question)
+ tail = MatchSlow(rest,end,es,to);
+ if(tail==end)
+ break; // yup.
+ // nope, try a shorter match for this one..
+ stp=rest-1;
+ ASSERT(stp>=sp); // It did work.. It should've..
+ }
+ ssub=ss+1;
+ esub=es-1;
+ // Did innards match?
+ if(MatchSlow(sp,rest,ssub,esub)){
+ dp = MatchDissect(sp,rest,ssub,esub);
+ ASSERT(dp==rest);
+ }else // nope..
+ ASSERT(sp==rest);
+ sp = rest;
+ break;
+ case CSop::opPlus0:
+ stp=end;
+ for(;;){
+ // How long could this one be??
+ rest = MatchSlow(sp,stp,ss,es);
+ ASSERT(rest); // It did.. It should've..
+ // Could the rest match the rest?
+ tail = MatchSlow(rest,end,es,to);
+ if(tail==end)
+ break; // yup.
+ // nope..
+ stp=rest-1;
+ ASSERT(stp>=sp); // It should've worked, we believe..
+ }
+ ssub=ss+1;
+ esub=es-1;
+ ssp=sp;
+ oldssp=ssp;
+ for(;;){ // Find last match of innards..
+ sep = MatchSlow(ssp,rest,ssub,esub);
+ if((!sep) || sep==ssp)
+ break; // Failed or matched nothin'
+ oldssp=ssp;
+ ssp=sep;
+ }
+ if(!sep){
+ // Last successfull..
+ sep=ssp;
+ ssp=oldssp;
+ }
+ ASSERT(sep=rest); // Must exhaust substring they say..
+ VERIFY(MatchSlow(ssp,sep,ssub,esub)==rest); // Assert or verify - that is the question..
+ dp = MatchDissect(ssp,sep,ssub,esub);
+ ASSERT(dp==sep);
+ sp=rest;
+ break;
+ case CSop::opChoice0:
+ stp = end;
+ for(;;){
+ // how long..
+ rest = MatchSlow(sp,stp,ss,es);
+ ASSERT(rest);
+ // Could it..
+ tail = MatchSlow(rest,end,es,to);
+ if(tail==end)
+ break; // y
+ // n
+ stp = rest-1;
+ ASSERT(stp>=sp);
+ }
+ ssub=ss+1;
+ esub=ss+m_Strip[ss].m_Operand-1;
+ ASSERT(m_Strip[esub].m_Operator==CSop::opOr0);
+ for(;;){ // Find first matching branch..
+ if(MatchSlow(sp,rest,ssub,esub)==rest)
+ break;
+ // this one missed, try next..
+ ASSERT(m_Strip[esub].m_Operator==CSop::opOr0);
+ esub++;
+ ASSERT(m_Strip[esub].m_Operator==CSop::opOr1);
+ ssub=esub+1;
+ esub+=m_Strip[esub].m_Operand;
+ if(m_Strip[esub].m_Operator==CSop::opOr1)
+ esub--;
+ else
+ ASSERT(m_Strip[esub].m_Operator==CSop::opChoice1);
+ }
+ dp = MatchDissect(sp,rest,ssub,esub);
+ ASSERT(dp==rest);
+ sp=rest;
+ break;
+ case CSop::opPlus1:
+ case CSop::opQuest1:
+ case CSop::opOr0:
+ case CSop::opOr1:
+ case CSop::opChoice1:
+ ASSERT(FALSE);
+ break;
+ case CSop::opLeftParen:
+ i = m_Strip[ss].m_Operand;
+ ASSERT(0<i && i<=m_Subexps);
+ m_Matches[i].m_Begin=sp-m_mBegin;
+ break;
+ case CSop::opRightParen:
+ i = m_Strip[ss].m_Operand;
+ ASSERT(0<i && i<=m_Subexps);
+ m_Matches[i].m_End=sp-m_mBegin;
+ break;
+#ifdef _DEBUG
+ default: // Uh.. oh..
+ ASSERT(FALSE);
+ break;
+#endif
+ }
+ }
+ ASSERT(sp==end);
+ return sp;
+}
+
+LPCTSTR CRegEx::MatchBackRef(LPCTSTR begin,LPCTSTR end,int from,int to,int level)
+{
+LPCTSTR sp = begin;
+BOOL hard = FALSE;
+ // Get as far as we can as long as it's easy
+ for(int ss=from;!hard && ss<to;ss++){
+ CSop s = m_Strip[ss];
+ switch(s.m_Operator){
+ case CSop::opChar:
+ if(sp==end || *sp++ != s.m_Operand)
+ return NULL;
+ break;
+ case CSop::opAny:
+ if(sp==end)
+ return NULL;
+ sp++; // I'm sure this ++ could be embedded in previous expression..
+ break;
+ case CSop::opAnyOf:
+ if(sp==end || !m_Sets[s.m_Operand].IsIn(*sp++))
+ return NULL;
+ break;
+ case CSop::opBOL:
+ if(!((sp==m_mBegin && !(m_mFlags&regNotBOL)) || (sp<m_mEnd && *(sp-1)=='\n' && (m_Flags&regNewLine))))
+ return NULL;
+ break;
+ case CSop::opEOL:
+ if(!((sp==m_mEnd && !(m_mFlags&regNotEOL)) || (sp<m_mEnd && *sp=='\n' && (m_Flags&regNewLine))))
+ return NULL;
+ break;
+ case CSop::opBOW:
+ if(!(((sp==m_mBegin && !(m_mFlags&regNotBOL)) || (sp<m_mEnd && *(sp-1)=='\n' && (m_Flags&regNewLine)) || (sp>m_mBegin && !isWordableChar(*(sp-1)))) && (sp<m_mEnd && isWordableChar(*sp))))
+ return NULL;
+ break;
+ case CSop::opEOW:
+ if(!(((sp==m_mEnd && !(m_mFlags&regNotEOL)) || (sp<m_mEnd && *sp=='\n' && (m_Flags&regNewLine)) || (sp<m_mEnd && !isWordableChar(*sp))) && (sp>m_mBegin && isWordableChar(*(sp-1)))))
+ return NULL;
+ break;
+ case CSop::opQuest1:
+ break;
+ case CSop::opOr0: // Matches null, but needs to skip
+ ss++;
+ s = m_Strip[ss];
+ do{
+ ASSERT(s.m_Operator==CSop::opOr1);
+ ss+=s.m_Operand;
+ }while((s=m_Strip[ss]).m_Operator!=CSop::opChoice1);
+ // Now we should note that ss++ gets us past the Choice1..
+ break;
+ default:
+ // Have to make a choice..
+ hard=TRUE;
+ break;
+ }
+ }
+ if(!hard){ // That was it..
+ if(sp!=end)
+ return NULL;
+ return sp;
+ }
+ ss--; // Adjust for ther for's final increment..
+ // Hard stuff.. is going on and on..
+CSop s = m_Strip[ss];
+int i, len, offsave;
+int ssub,esub;
+LPCTSTR ssp, dp;
+ switch(s.m_Operator){
+ case CSop::opBackRef0: // The vilest depths they say.. If I only knew what the 'viles' stands for..
+ i = s.m_Operand;
+ ASSERT(0<i && i<=m_Subexps);
+ if(m_Matches[i].m_End<0)
+ return NULL;
+ ASSERT(m_Matches[i].m_Begin>=0);
+ len = m_Matches[i].GetLength();
+ ASSERT((end-m_mBegin)>=len);
+ if(sp>end-len)
+ return NULL; // Not enough left to match..
+ ssp = m_mBegin+m_Matches[i].m_Begin;
+ if(memcmp(sp,ssp,len))
+ return NULL;
+ while(m_Strip[ss]!=CSop(CSop::opBackRef1,i))
+ ss++;
+ return MatchBackRef(sp+len,end,ss+1,to,level-1);
+ break;
+ case CSop::opQuest0: // to null or not they wonder..
+ dp = MatchBackRef(sp,end,ss+1,to,level);
+ if(dp)
+ return dp; // not..
+ return MatchBackRef(sp,end,ss+s.m_Operand+1,to,level-1);
+ break;
+ case CSop::opPlus0:
+ ASSERT(m_mLastPos.GetSize());
+ ASSERT(level+1 <= m_Pluses);
+ m_mLastPos[level+1]=sp;
+ return MatchBackRef(sp,end,ss+1,to,level+1);
+ break;
+ case CSop::opPlus1:
+ if(sp == m_mLastPos[level]) // Last pass matched null
+ return MatchBackRef(sp,end,ss+1,to,level-1);
+ // Try another pass..
+ m_mLastPos[level]=sp;
+ dp = MatchBackRef(sp,end,ss-s.m_Operand+1,to,level);
+ if(dp)
+ return dp;
+ return MatchBackRef(sp,end,ss+1,to,level-1);
+ break;
+ case CSop::opChoice0: // find the right one, ifany
+ ssub = ss+1;
+ esub = ss+s.m_Operand-1;
+ ASSERT(m_Strip[esub].m_Operator==CSop::opOr0);
+ for(;;){ // Find first matching branch.
+ dp = MatchBackRef(sp,end,ssub,esub,level);
+ if(dp)
+ return dp;
+ // This one missed, try next one..
+ if(m_Strip[esub].m_Operator==CSop::opChoice1)
+ return NULL; // There is none..
+ esub++;
+ ASSERT(m_Strip[esub].m_Operator==CSop::opOr1);
+ ssub=esub+1;
+ esub+=m_Strip[esub].m_Operand;
+ if(m_Strip[esub].m_Operator==CSop::opOr1)
+ esub--;
+ else
+ ASSERT(m_Strip[esub].m_Operator==CSop::opChoice1);
+ }
+ break;
+ case CSop::opLeftParen: // Must undo assignment if rest fails..
+ i = s.m_Operand;
+ ASSERT(0<i && i<=m_Subexps);
+ offsave = m_Matches[i].m_Begin;
+ m_Matches[i].m_Begin = sp-m_mBegin;
+ dp = MatchBackRef(sp,end,ss+1,to,level);
+ if(dp)
+ return dp;
+ m_Matches[i].m_Begin=offsave;
+ return NULL;
+ break;
+ case CSop::opRightParen: // Must undo assignment if rest fails..
+ i = s.m_Operand;
+ ASSERT(0<i && i<=m_Subexps);
+ offsave = m_Matches[i].m_End;
+ m_Matches[i].m_End = sp-m_mBegin;
+ dp = MatchBackRef(sp,end,ss+1,to,level);
+ if(dp)
+ return dp;
+ m_Matches[i].m_End = offsave;
+ return NULL;
+ break;
+#ifdef _DEBUG
+ default:
+ ASSERT(FALSE);
+ break;
+#endif
+ }
+ ASSERT(FALSE);
+ return NULL; // Anyway - we can never get here..
+}
+
+#ifdef _DEBUG
+void CRegEx::CSop::Dump(CDumpContext& dc)
+{
+ switch(m_Operator){
+ case opEnd:
+ dc << "end";
+ break;
+ case opChar:
+ dc << "char('" << (char)m_Operand << "')";
+ break;
+ case opBOL:
+ dc << "BOL";
+ break;
+ case opEOL:
+ dc << "EOL";
+ break;
+ case opAny:
+ dc << "any";
+ break;
+ case opAnyOf:
+ dc << "anyOf(" << m_Operand << ")";
+ break;
+ case opBackRef0:
+ dc << "[ backref(" << m_Operand << ")";
+ break;
+ case opBackRef1:
+ dc << "] backref(" << m_Operand << ")";
+ break;
+ case opPlus0:
+ dc << "[ + (" << m_Operand << ")";
+ break;
+ case opPlus1:
+ dc << "] + (" << m_Operand << ")";
+ break;
+ case opQuest0:
+ dc << "[ ? (" << m_Operand << ")";
+ break;
+ case opQuest1:
+ dc << "] ? (" << m_Operand << ")";
+ break;
+ case opLeftParen:
+ dc << "[ ( (" << m_Operand << ")";
+ break;
+ case opRightParen:
+ dc << "] ) (" << m_Operand << ")";
+ break;
+ case opChoice0:
+ dc << "[ choice (" << m_Operand << ")";
+ break;
+ case opOr0:
+ dc << "[ | (" << m_Operand << ")";
+ break;
+ case opOr1:
+ dc << "] | (" << m_Operand << ")";
+ break;
+ case opChoice1:
+ dc << "] choice (" << m_Operand << ")";
+ break;
+ case opBOW:
+ dc << "BOW";
+ break;
+ case opEOW:
+ dc << "EOW";
+ break;
+ }
+}
+void CRegEx::DumpStrip(CDumpContext& dc)
+{
+ for(int tmp=0;tmp<m_Strip.GetSize();tmp++)
+ dc << tmp << ": " << m_Strip[tmp] << ";\n";
+}
+#endif
+
+
+CString CRegEx::GetMatch(int match)
+{
+CString rv;
+ if(!m_Matches.GetSize())
+ return rv;
+ ASSERT(m_Matches[0].m_Begin<m_Input.GetLength() && m_Matches[0].m_End<=m_Input.GetLength());
+ if(match==matchPreMatch)
+ return m_Input.Left(m_Matches[0].m_Begin);
+ if(match==matchPostMatch)
+ return m_Input.Mid(m_Matches[0].m_End);
+ if(match<0 || match >= m_Matches.GetSize())
+ return rv;
+ if(m_Matches[match].m_Begin<0 || m_Matches[match].m_End<0)
+ return rv;
+ ASSERT(m_Matches[match].m_Begin<m_Input.GetLength() && m_Matches[match].m_End<=m_Input.GetLength());
+ rv = m_Input.Mid(m_Matches[match].m_Begin,m_Matches[match].m_End-m_Matches[match].m_Begin);
+ return rv;
+}
diff --git a/shared-code/RegEx.h b/shared-code/RegEx.h
new file mode 100644
index 0000000..2534768
--- a/dev/null
+++ b/shared-code/RegEx.h
@@ -0,0 +1,158 @@
+#ifndef __REGEX_H
+#define __REGEX_H
+
+class CRegEx {
+public:
+ CString GetMatch(int match=0);
+ CString m_Input;
+ struct CMatch {
+ CMatch() : m_Begin(-1), m_End(-1) {}
+ int GetLength() { return m_End-m_Begin; }
+ int m_Begin;
+ int m_End;
+ };
+ typedef CArray<CMatch,CMatch&> CMatchBox;
+ enum {
+ matchMatch = 0,
+ matchPreMatch = -1,
+ matchPostMatch = -2
+ };
+ CMatchBox m_Matches;
+ enum {
+ charOut = 256,
+ charBOL, charEOL, charBOLEOL, charNothing, charBOW, charEOW,
+ charMaxCode = charEOW,
+ charNNChars = (charMaxCode-255)
+ };
+ int m_mFlags;
+ enum {
+ regeSuccess = 0,
+ regeNoMatch = 1, regeBadPattern, regeCollate, regeCType, regeEscape, regeSubReg, regeBracket,
+ regeParen, regeBrace, regeBadBrace, regeRange, regeSpace, regeBadRepeat, regeEmpty, regeAssert,
+ regeInvArg
+ };
+ int m_Error;
+ CRegEx();
+ BOOL m_bCompiled;
+ CString m_Pattern;
+ BOOL m_bBackRefs;
+ int m_Pluses;
+ CString m_Must;
+ BYTE m_Category[CHAR_MAX-CHAR_MIN+1];
+ int m_Categories;
+ int m_EOLs;
+ int m_BOLs;
+ int m_iFlags;
+ int m_Subexps;
+ struct CSop {
+ void Dump(CDumpContext& dc);
+ CSop() {}
+ CSop(BYTE op,DWORD opnd=0) : m_Operator(op), m_Operand(opnd) {}
+ BOOL operator==(CSop& other) {return m_Operator==other.m_Operator && m_Operand==other.m_Operand;}
+ BOOL operator!=(CSop& other) { return !((*this)==other);}
+ enum {
+ opEnd = 1, opChar, opBOL, opEOL, opAny, opAnyOf, opBackRef0, opBackRef1,
+ opPlus0, opPlus1, opQuest0, opQuest1, opLeftParen, opRightParen, opChoice0,
+ opOr0, opOr1, opChoice1, opBOW, opEOW
+ };
+ BYTE m_Operator;
+ DWORD m_Operand;
+ enum {
+ stCurrent = 1, stFresh = 2, stTemp = 4, stEmpty = 8
+ };
+ BYTE m_MatchData;
+ };
+ typedef CArray<CSop,CSop&> CStrip;
+ CStrip m_Strip;
+ int m_Flags;
+ struct CSet {
+ CSet() : m_Hash(0) { memset(m_Set,0,sizeof(m_Set)); }
+ CSet(CSet& src) { (*this)=src; }
+ CSet& operator=(CSet& src) { memmove(this,&src,sizeof(*this)); return *this; }
+ BOOL operator==(CSet& other) { if(m_Hash!=other.m_Hash)return FALSE;return !memcmp(m_Set,other.m_Set,sizeof(m_Set)); }
+ enum {
+ size = (CHAR_MAX-CHAR_MIN+1)
+ };
+ BOOL m_Set[size];
+ BYTE m_Hash;
+ public:
+ UCHAR GetOnly();
+ void Sub(UCHAR c);
+ BOOL IsIn(UCHAR c);
+ void Add(UCHAR c);
+ };
+ typedef CArray<CSet,CSet&> CSets;
+ CSets m_Sets;
+ enum {
+ // Compile flags
+ regBasic = 0, regExtended = 1,
+ regIgnoreCase = 2,
+ regNoSubExpressions = 4, // Also works for matching.
+ regNewLine = 16,
+ regLiteral = 32,
+ // Match Flags
+ regNotBOL = 1,
+ regNotEOL = 2,
+ regOneMatch=64,
+ regBackRefs=128,
+ // iFlags
+ iflagsUseBOL=1, iflagsUseEOL=2, iflagsBad=4
+ };
+ CString Replace(LPCTSTR src,LPCTSTR rep,int flags=0);
+ BOOL Match(LPCTSTR src,int flags=0);
+ BOOL Compile(LPCTSTR regex,int flags=0);
+private:
+#ifdef _DEBUG
+ void DumpStrip(CDumpContext& dc);
+#endif
+ LPCTSTR MatchBackRef(LPCTSTR begin,LPCTSTR end,int from,int to,int level);
+ typedef CArray<LPCTSTR,LPCTSTR> CStrPtrArray;
+ CStrPtrArray m_mLastPos;
+ LPCTSTR MatchDissect(LPCTSTR begin,LPCTSTR end,int from,int to);
+ LPCTSTR MatchSlow(LPCTSTR begin,LPCTSTR end,int from,int to);
+ LPCTSTR m_cOldP;
+ BOOL MatchStatesEqual(BYTE m1,BYTE m2);
+ LPCTSTR m_mBegin;
+ void MatchStatesCopy(BYTE dst,BYTE src);
+ void MatchStep(int from,int to,BYTE maskBefore,int charCode,BYTE maskAfter);
+ void MatchStatesClear(BYTE mask);
+ LPCTSTR MatchFast(LPCTSTR begin);
+ LPCTSTR m_mEnd;
+ LPCTSTR m_mPointer;
+ BOOL ParseBREexp(BOOL ordinaryStar);
+ void ParseBRE(int stopa=0,int stopb=0);
+ void ParseLiteral();
+ int CountPluses();
+ void FigureMust();
+ BOOL IsInSameSets(UCHAR c1,UCHAR c2);
+ BOOL IsInSets(UCHAR c);
+ void Categorize();
+ int StripDuplicate(int from,int to);
+ void EmitRepeat(int pos,int from,int to);
+ UCHAR ParseBracketSymbol();
+ UCHAR ParseBracketCollatingElement(UCHAR term);
+ void ParseBracketEClass(CSet& cset);
+ void ParseBracketCClass(CSet& cset);
+ void ParseBracketTerm(CSet& cset);
+ int StoreSet(CSet& cset);
+ void ParseBracket();
+ int ParseCount();
+ void EmitNonNewLineAny();
+ void EmitOrdinary(UCHAR c);
+ void StripInsert(int pos,CSop& sop);
+ void ParseEREexp();
+ void ParseERE(int stop=0);
+ struct CParenthesis {
+ long m_Begin;
+ long m_End;
+ CParenthesis(long b=0,long e=0) : m_Begin(b), m_End(e) {}
+ };
+ typedef CArray<CParenthesis,CParenthesis&> CParens;
+ CParens m_ParseParens;
+ int m_ParsePointer;
+};
+#ifdef _DEBUG
+inline CDumpContext& operator<<(CDumpContext& dc, CRegEx::CSop& sop) { sop.Dump(dc); return dc; }
+#endif
+
+#endif // __REGEX_H \ No newline at end of file
diff --git a/shared-code/SNMPExtDll.h b/shared-code/SNMPExtDll.h
new file mode 100644
index 0000000..14c920d
--- a/dev/null
+++ b/shared-code/SNMPExtDll.h
@@ -0,0 +1,252 @@
+#ifndef __SNMPEXTDLL_H
+#define __SNMPEXTDLL_H
+
+#include "snmpeer.h"
+
+#include <snmp.h>
+
+namespace Klever {
+
+class CSNMPExtDLL : public CSNMPeer {
+public:
+ HINSTANCE m_hInstance;
+ HANDLE m_hEvent;
+ AsnObjectIdentifier m_OID;
+ BOOL (SNMP_FUNC_TYPE *m_extInit)(DWORD dw,HANDLE h,AsnObjectIdentifier* aoid);
+ BOOL (SNMP_FUNC_TYPE *m_extQuery)(BYTE b,RFC1157VarBindList* rvbl,AsnInteger* ai1,AsnInteger* ai2);
+ BOOL (SNMP_FUNC_TYPE *m_extTrap)(AsnObjectIdentifier*,AsnNetworkAddress*,AsnInteger*,AsnInteger*,AsnTimeticks*,RFC1157VarBindList*);
+
+ HINSTANCE m_hSNMPAPI;
+ void (SNMP_FUNC_TYPE *m_snmpOIDFree)(AsnObjectIdentifier*);
+ LPVOID (SNMP_FUNC_TYPE *m_snmpAlloc)(UINT);
+ void (SNMP_FUNC_TYPE *m_snmpFree)(LPVOID);
+ void (SNMP_FUNC_TYPE *m_snmpVBLFree)(RFC1157VarBindList* vbl);
+ void InitSNMP() {
+ m_hSNMPAPI = ::LoadLibraryEx("SNMPAPI",NULL,0);
+ if(!m_hSNMPAPI)
+ return;
+ *(FARPROC*)&m_snmpOIDFree = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilOidFree");
+ *(FARPROC*)&m_snmpAlloc = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilMemAlloc");
+ *(FARPROC*)&m_snmpFree = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilMemFree");
+ *(FARPROC*)&m_snmpVBLFree = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilVarBindListFree");
+ if(
+ (m_snmpFree && !m_snmpAlloc) ||
+ (m_snmpAlloc && !m_snmpFree)
+ )
+ DeinitSNMP();
+ }
+ void DeinitSNMP() {
+ if(!m_hSNMPAPI)
+ return;
+ ::FreeLibrary(m_hSNMPAPI);
+ m_hSNMPAPI=NULL;
+ }
+ void SNMPFreeOID(AsnObjectIdentifier* oid) {
+ if(m_hSNMPAPI && m_snmpOIDFree)
+ (*m_snmpOIDFree)(oid);
+ else
+ ::GlobalFree((HGLOBAL)oid->ids);
+ }
+ LPVOID SNMPAlloc(UINT size) {
+ if(m_hSNMPAPI && m_snmpAlloc)
+ return (*m_snmpAlloc)(size);
+ else
+ return ::GlobalAlloc(GMEM_FIXED,size);
+ }
+ void SNMPFree(LPVOID addr) {
+ if(m_hSNMPAPI && m_snmpFree)
+ (*m_snmpFree)(addr);
+ else
+ :: GlobalFree((HGLOBAL)addr);
+ }
+ void SNMPFreeVBL(RFC1157VarBindList& vbl) {
+ if(m_hSNMPAPI && m_snmpVBLFree)
+ (*m_snmpVBLFree)(&vbl);
+ else{
+ for(UINT tmp=0;tmp<vbl.len;tmp++) {
+ SNMPFree(vbl.list[tmp].name.ids);
+ switch(vbl.list[tmp].value.asnType){
+ case ASN_OCTETSTRING:
+ case ASN_SEQUENCE:
+ case ASN_RFC1155_IPADDRESS:
+ case ASN_RFC1155_OPAQUE:
+// case ASN_RFC1213_DISPSTRING:
+ if(vbl.list[tmp].value.asnValue.arbitrary.dynamic)
+ SNMPFree(vbl.list[tmp].value.asnValue.arbitrary.stream);
+ break;
+ case ASN_OBJECTIDENTIFIER:
+ SNMPFree(vbl.list[tmp].value.asnValue.object.ids);
+ break;
+ default:
+ break;
+ }
+ }
+ SNMPFree(vbl.list);
+ }
+ }
+
+ BOOL SNMPBuildVBL(RFC1157VarBindList& vbl,CSNMPVarBindList& in) {
+ vbl.len = in.GetCount();
+ vbl.list = (RFC1157VarBind*)SNMPAlloc(sizeof(RFC1157VarBind)*vbl.len);
+ POSITION p = in.GetHeadPosition();
+ UINT ptr = 0;
+ while(p){
+ CSNMPVarBind& vb = in.GetNext(p);
+ ASSERT(ptr<vbl.len);
+ SNMPBuildVB(vbl.list[ptr++],vb);
+ }
+ return TRUE;
+ }
+ BOOL SNMPBuildVB(RFC1157VarBind& vb,CSNMPVarBind& in) {
+ ASSERT(in.name.type==CASNAny::typeASNOID);
+ return SNMPBuildOID(vb.name,in.name.value.oid) && SNMPBuildAA(vb.value,in.value);
+ }
+ BOOL SNMPBuildAA(AsnAny& aa,CASNAny& in) {
+ aa.asnType=in.type;
+ switch(in.type) {
+ case CASNAny::typeASNInteger:
+ aa.asnValue.number=in.value.number; break;
+ case CASNAny::typeASNOctetString:
+// case CASNAny::typeASNDispString:
+ SNMPBuildOS(aa.asnValue.string,in.value.string); break;
+ case CASNAny::typeASNNull:
+ break;
+ case CASNAny::typeASNOID:
+ SNMPBuildOID(aa.asnValue.object,in.value.oid); break;
+ case CASNAny::typeASNSequence:
+// case CASNAny::typeASNSequenceOf:
+ SNMPBuildOS(aa.asnValue.sequence,in.value.sequence); break;
+ case CASNAny::typeASNIP:
+ SNMPBuildFLOS(aa.asnValue.address,(LPBYTE)&in.value.ip,sizeof(in.value.ip)); break;
+ case CASNAny::typeASNCounter:
+ aa.asnValue.counter = in.value.counter; break;
+ case CASNAny::typeASNGauge:
+ aa.asnValue.gauge = in.value.gauge; break;
+ case CASNAny::typeASNTicks:
+ aa.asnValue.ticks = in.value.ticks; break;
+ case CASNAny::typeASNOpaque:
+ ASSERT(in.storeType==CASNAny::storeDynamic);
+ SNMPBuildOS(aa.asnValue.arbitrary,in.value.data); break;
+ break;
+ default:
+ ASSERT(FALSE);
+ return FALSE;
+ }
+ return TRUE;
+ }
+ BOOL SNMPBuildOS(AsnOctetString& os,CASNAny::asnOctetString& in) {
+ return SNMPBuildFLOS(os,in.data,in.size);
+ }
+ BOOL SNMPBuildOID(AsnObjectIdentifier& oid,CASNAny::asnOID& in) {
+ oid.idLength = in.size/sizeof(UINT);
+ ASSERT(!(in.size%sizeof(UINT)));
+ VERIFY(oid.ids = (UINT*)SNMPAlloc(in.size));
+ memmove(oid.ids,in.data,in.size);
+ return TRUE;
+ }
+ BOOL SNMPBuildFLOS(AsnOctetString& os,LPBYTE data,UINT size) {
+ os.length = size;
+ VERIFY(os.stream = (BYTE*)SNMPAlloc(os.length));
+ os.dynamic=TRUE;
+ memmove(os.stream,data,size);
+ return TRUE;
+ }
+ BOOL SNMPParseVBL(RFC1157VarBindList& vbl,CSNMPVarBindList& ou) {
+ for(UINT tmp=0;tmp<vbl.len;tmp++){
+ CSNMPVarBind vb;
+ SNMPParseVB(vbl.list[tmp],vb);
+ ou.AddTail(vb);
+ }
+ return TRUE;
+ }
+ BOOL SNMPParseVB(RFC1157VarBind& vb,CSNMPVarBind& ou) {
+ ou.name.Set(CASNAny::typeASNOID,(LPBYTE)vb.name.ids,vb.name.idLength*sizeof(UINT));
+ return SNMPParseAA(vb.value,ou.value);
+ }
+ BOOL SNMPParseAA(AsnAny& aa,CASNAny& ou) {
+ switch(aa.asnType){
+ case ASN_INTEGER:
+ ou.Set(CASNAny::typeASNInteger,aa.asnValue.number); break;
+ case ASN_OCTETSTRING:
+// case ASN_RFC1213_DISPSTRING:
+ ou.Set(CASNAny::typeASNOctetString,aa.asnValue.string.stream,aa.asnValue.string.length); break;
+ case ASN_OBJECTIDENTIFIER:
+ ou.Set(CASNAny::typeASNOID,(LPBYTE)aa.asnValue.object.ids,aa.asnValue.object.idLength);
+ SNMPParseOID(aa.asnValue.object,ou.value.oid); break;
+ case ASN_SEQUENCE:
+ ou.Set(CASNAny::typeASNSequence,aa.asnValue.sequence.stream,aa.asnValue.sequence.length); break;
+ case ASN_RFC1155_IPADDRESS:
+ SNMPParseIP(aa.asnValue.address,ou); break;
+ case ASN_RFC1155_COUNTER:
+ ou.Set(CASNAny::typeASNCounter,(LONG)aa.asnValue.counter); break;
+ case ASN_RFC1155_GAUGE:
+ ou.Set(CASNAny::typeASNGauge,(LONG)aa.asnValue.gauge); break;
+ case ASN_RFC1155_TIMETICKS:
+ ou.Set(CASNAny::typeASNTicks,(LONG)aa.asnValue.ticks); break;
+ case ASN_RFC1155_OPAQUE:
+ ou.Set(CASNAny::typeASNOpaque,aa.asnValue.arbitrary.stream,aa.asnValue.arbitrary.length); break;
+ case ASN_NULL:
+ ou.Free(); break;
+ default:
+ ASSERT(FALSE);
+ return FALSE;
+ }
+ return TRUE;
+ }
+ BOOL SNMPParseOID(AsnObjectIdentifier& oid,CASNAny::asnOID& ou) {
+ ASSERT(ou.size==(oid.idLength*sizeof(UINT)));
+ memmove(ou.data,oid.ids,ou.size);
+ return TRUE;
+ }
+ BOOL SNMPParseIP(AsnIPAddress& ip,CASNAny& ou) {
+ in_addr i;
+ if(ip.length>sizeof(i))
+ return FALSE;
+ i.s_addr=0;
+ memmove(&i,ip.stream,ip.length);
+ ou.Set(i);
+ return TRUE;
+ }
+
+
+ CSNMPExtDLL(LPCTSTR dllName) : m_hInstance(NULL) { InitSNMP(); Init(dllName); }
+ ~CSNMPExtDLL() { Deinit(); DeinitSNMP(); }
+
+ BOOL Init(LPCTSTR dllName) {
+ Deinit();
+ m_hInstance = ::LoadLibraryEx(dllName,NULL,0);
+ if(!m_hInstance)
+ return FALSE;
+ *(FARPROC*)&m_extInit = ::GetProcAddress(m_hInstance,"SnmpExtensionInit");
+ *(FARPROC*)&m_extQuery = ::GetProcAddress(m_hInstance,"SnmpExtensionQuery");
+ *(FARPROC*)&m_extTrap = ::GetProcAddress(m_hInstance,"SnmpExtensionTrap");
+ if(!(m_extInit && m_extQuery && m_extTrap)){
+ Deinit();
+ return FALSE;
+ }
+ if(!((*m_extInit)(GetCurrentTime(),&m_hEvent,&m_OID))){
+ Deinit();
+ return FALSE;
+ }
+ return TRUE;
+ }
+ void Deinit() {
+ if(!m_hInstance)
+ return;
+ ::FreeLibrary(m_hInstance);
+ }
+ virtual BOOL Request(BYTE type,CSNMPVarBindList& in,CSNMPVarBindList& ou) {
+ RFC1157VarBindList vbl;
+ SNMPBuildVBL(vbl,in);
+ AsnInteger errorStatus, errorIndex;
+ (*m_extQuery)(type,&vbl,&errorStatus,&errorIndex);
+ ou.RemoveAll();
+ SNMPParseVBL(vbl,ou);
+ SNMPFreeVBL(vbl);
+ return TRUE;
+ }
+};
+
+};
+
+#endif // __SNMPEXTDLL_H
diff --git a/shared-code/SNMPOIDs.h b/shared-code/SNMPOIDs.h
new file mode 100644
index 0000000..68ee659
--- a/dev/null
+++ b/shared-code/SNMPOIDs.h
@@ -0,0 +1,221 @@
+#ifndef __SNMPOIDS_H
+#define __SNMPOIDS_H
+
+#define DEFINE_OID(name,oid) static UINT name[] = oid
+
+// MIB-II OIDs
+
+#define OIDccitt {0}
+#define OIDnull {0,0}
+#define OIDiso {1}
+#define OIDorg {1,3}
+#define OIDdod {1,3,6}
+#define OIDinternet {1,3,6,1}
+#define OIDdirectory {1,3,6,1,1}
+#define OIDmgmt {1,3,6,1,2}
+#define OIDmib_2 {1,3,6,1,2,1}
+#define OIDsystem {1,3,6,1,2,1,1}
+#define OIDsysDescr {1,3,6,1,2,1,1,1}
+#define OIDsysObjectID {1,3,6,1,2,1,1,2}
+#define OIDsysUpTime {1,3,6,1,2,1,1,3}
+#define OIDsysContact {1,3,6,1,2,1,1,4}
+#define OIDsysName {1,3,6,1,2,1,1,5}
+#define OIDsysLocation {1,3,6,1,2,1,1,6}
+#define OIDsysServices {1,3,6,1,2,1,1,7}
+#define OIDtransmission {1,3,6,1,2,1,10}
+#define OIDsnmp {1,3,6,1,2,1,11}
+#define OIDsnmpInPkts {1,3,6,1,2,1,11,1}
+#define OIDsnmpInBadValues {1,3,6,1,2,1,11,10}
+#define OIDsnmpInReadOnlys {1,3,6,1,2,1,11,11}
+#define OIDsnmpInGenErrs {1,3,6,1,2,1,11,12}
+#define OIDsnmpInTotalReqVars {1,3,6,1,2,1,11,13}
+#define OIDsnmpInTotalSetVars {1,3,6,1,2,1,11,14}
+#define OIDsnmpInGetRequests {1,3,6,1,2,1,11,15}
+#define OIDsnmpInGetNexts {1,3,6,1,2,1,11,16}
+#define OIDsnmpInSetRequests {1,3,6,1,2,1,11,17}
+#define OIDsnmpInGetResponses {1,3,6,1,2,1,11,18}
+#define OIDsnmpInTraps {1,3,6,1,2,1,11,19}
+#define OIDsnmpOutPkts {1,3,6,1,2,1,11,2}
+#define OIDsnmpOutTooBigs {1,3,6,1,2,1,11,20}
+#define OIDsnmpOutNoSuchNames {1,3,6,1,2,1,11,21}
+#define OIDsnmpOutBadValues {1,3,6,1,2,1,11,22}
+#define OIDsnmpOutGenErrs {1,3,6,1,2,1,11,24}
+#define OIDsnmpOutGetRequests {1,3,6,1,2,1,11,25}
+#define OIDsnmpOutGetNexts {1,3,6,1,2,1,11,26}
+#define OIDsnmpOutSetRequests {1,3,6,1,2,1,11,27}
+#define OIDsnmpOutGetResponses {1,3,6,1,2,1,11,28}
+#define OIDsnmpOutTraps {1,3,6,1,2,1,11,29}
+#define OIDsnmpInBadVersions {1,3,6,1,2,1,11,3}
+#define OIDsnmpEnableAuthenTraps {1,3,6,1,2,1,11,30}
+#define OIDsnmpInBadCommunityNames {1,3,6,1,2,1,11,4}
+#define OIDsnmpInBadCommunityUses {1,3,6,1,2,1,11,5}
+#define OIDsnmpInASNParseErrs {1,3,6,1,2,1,11,6}
+#define OIDsnmpInTooBigs {1,3,6,1,2,1,11,8}
+#define OIDsnmpInNoSuchNames {1,3,6,1,2,1,11,9}
+#define OIDinterfaces {1,3,6,1,2,1,2}
+#define OIDifNumber {1,3,6,1,2,1,2,1}
+#define OIDifTable {1,3,6,1,2,1,2,2}
+#define OIDifEntry {1,3,6,1,2,1,2,2,1}
+#define OIDifIndex {1,3,6,1,2,1,2,2,1,1}
+#define OIDifInOctets {1,3,6,1,2,1,2,2,1,10}
+#define OIDifInUcastPkts {1,3,6,1,2,1,2,2,1,11}
+#define OIDifInNUcastPkts {1,3,6,1,2,1,2,2,1,12}
+#define OIDifInDiscards {1,3,6,1,2,1,2,2,1,13}
+#define OIDifInErrors {1,3,6,1,2,1,2,2,1,14}
+#define OIDifInUnknownProtos {1,3,6,1,2,1,2,2,1,15}
+#define OIDifOutOctets {1,3,6,1,2,1,2,2,1,16}
+#define OIDifOutUcastPkts {1,3,6,1,2,1,2,2,1,17}
+#define OIDifOutNUcastPkts {1,3,6,1,2,1,2,2,1,18}
+#define OIDifOutDiscards {1,3,6,1,2,1,2,2,1,19}
+#define OIDifDescr {1,3,6,1,2,1,2,2,1,2}
+#define OIDifOutErrors {1,3,6,1,2,1,2,2,1,20}
+#define OIDifOutQLen {1,3,6,1,2,1,2,2,1,21}
+#define OIDifSpecific {1,3,6,1,2,1,2,2,1,22}
+#define OIDifType {1,3,6,1,2,1,2,2,1,3}
+#define OIDifMtu {1,3,6,1,2,1,2,2,1,4}
+#define OIDifSpeed {1,3,6,1,2,1,2,2,1,5}
+#define OIDifPhysAddress {1,3,6,1,2,1,2,2,1,6}
+#define OIDifAdminStatus {1,3,6,1,2,1,2,2,1,7}
+#define OIDifOperStatus {1,3,6,1,2,1,2,2,1,8}
+#define OIDifLastChange {1,3,6,1,2,1,2,2,1,9}
+#define OIDat {1,3,6,1,2,1,3}
+#define OIDatTable {1,3,6,1,2,1,3,1}
+#define OIDatEntry {1,3,6,1,2,1,3,1,1}
+#define OIDatIfIndex {1,3,6,1,2,1,3,1,1,1}
+#define OIDatPhysAddress {1,3,6,1,2,1,3,1,1,2}
+#define OIDatNetAddress {1,3,6,1,2,1,3,1,1,3}
+#define OIDip {1,3,6,1,2,1,4}
+#define OIDipForwarding {1,3,6,1,2,1,4,1}
+#define OIDipOutRequests {1,3,6,1,2,1,4,10}
+#define OIDipOutDiscards {1,3,6,1,2,1,4,11}
+#define OIDipOutNoRoutes {1,3,6,1,2,1,4,12}
+#define OIDipReasmTimeout {1,3,6,1,2,1,4,13}
+#define OIDipReasmReqds {1,3,6,1,2,1,4,14}
+#define OIDipReasmOKs {1,3,6,1,2,1,4,15}
+#define OIDipReasmFails {1,3,6,1,2,1,4,16}
+#define OIDipFragOKs {1,3,6,1,2,1,4,17}
+#define OIDipFragFails {1,3,6,1,2,1,4,18}
+#define OIDipFragCreates {1,3,6,1,2,1,4,19}
+#define OIDipDefaultTTL {1,3,6,1,2,1,4,2}
+#define OIDipAddrTable {1,3,6,1,2,1,4,20}
+#define OIDipAddrEntry {1,3,6,1,2,1,4,20,1}
+#define OIDipAdEntAddr {1,3,6,1,2,1,4,20,1,1}
+#define OIDipAdEntIfIndex {1,3,6,1,2,1,4,20,1,2}
+#define OIDipAdEntNetMask {1,3,6,1,2,1,4,20,1,3}
+#define OIDipAdEntBcastAddr {1,3,6,1,2,1,4,20,1,4}
+#define OIDipAdEntReasmMaxSize {1,3,6,1,2,1,4,20,1,5}
+#define OIDipRouteTable {1,3,6,1,2,1,4,21}
+#define OIDipRouteEntry {1,3,6,1,2,1,4,21,1}
+#define OIDipRouteDest {1,3,6,1,2,1,4,21,1,1}
+#define OIDipRouteAge {1,3,6,1,2,1,4,21,1,10}
+#define OIDipRouteMask {1,3,6,1,2,1,4,21,1,11}
+#define OIDipRouteMetric5 {1,3,6,1,2,1,4,21,1,12}
+#define OIDipRouteInfo {1,3,6,1,2,1,4,21,1,13}
+#define OIDipRouteIfIndex {1,3,6,1,2,1,4,21,1,2}
+#define OIDipRouteMetric1 {1,3,6,1,2,1,4,21,1,3}
+#define OIDipRouteMetric2 {1,3,6,1,2,1,4,21,1,4}
+#define OIDipRouteMetric3 {1,3,6,1,2,1,4,21,1,5}
+#define OIDipRouteMetric4 {1,3,6,1,2,1,4,21,1,6}
+#define OIDipRouteNextHop {1,3,6,1,2,1,4,21,1,7}
+#define OIDipRouteType {1,3,6,1,2,1,4,21,1,8}
+#define OIDipRouteProto {1,3,6,1,2,1,4,21,1,9}
+#define OIDipNetToMediaTable {1,3,6,1,2,1,4,22}
+#define OIDipNetToMediaEntry {1,3,6,1,2,1,4,22,1}
+#define OIDipNetToMediaIfIndex {1,3,6,1,2,1,4,22,1,1}
+#define OIDipNetToMediaPhysAddress {1,3,6,1,2,1,4,22,1,2}
+#define OIDipNetToMediaNetAddress {1,3,6,1,2,1,4,22,1,3}
+#define OIDipNetToMediaType {1,3,6,1,2,1,4,22,1,4}
+#define OIDipRoutingDiscards {1,3,6,1,2,1,4,23}
+#define OIDipInReceives {1,3,6,1,2,1,4,3}
+#define OIDipInHdrErrors {1,3,6,1,2,1,4,4}
+#define OIDipInAddrErrors {1,3,6,1,2,1,4,5}
+#define OIDipForwDatagrams {1,3,6,1,2,1,4,6}
+#define OIDipInUnknownProtos {1,3,6,1,2,1,4,7}
+#define OIDipInDiscards {1,3,6,1,2,1,4,8}
+#define OIDipInDelivers {1,3,6,1,2,1,4,9}
+#define OIDicmp {1,3,6,1,2,1,5}
+#define OIDicmpInMsgs {1,3,6,1,2,1,5,1}
+#define OIDicmpInTimestamps {1,3,6,1,2,1,5,10}
+#define OIDicmpInTimestampReps {1,3,6,1,2,1,5,11}
+#define OIDicmpInAddrMasks {1,3,6,1,2,1,5,12}
+#define OIDicmpInAddrMaskReps {1,3,6,1,2,1,5,13}
+#define OIDicmpOutMsgs {1,3,6,1,2,1,5,14}
+#define OIDicmpOutErrors {1,3,6,1,2,1,5,15}
+#define OIDicmpOutDestUnreachs {1,3,6,1,2,1,5,16}
+#define OIDicmpOutTimeExcds {1,3,6,1,2,1,5,17}
+#define OIDicmpOutParmProbs {1,3,6,1,2,1,5,18}
+#define OIDicmpOutSrcQuenchs {1,3,6,1,2,1,5,19}
+#define OIDicmpInErrors {1,3,6,1,2,1,5,2}
+#define OIDicmpOutRedirects {1,3,6,1,2,1,5,20}
+#define OIDicmpOutEchos {1,3,6,1,2,1,5,21}
+#define OIDicmpOutEchoReps {1,3,6,1,2,1,5,22}
+#define OIDicmpOutTimestamps {1,3,6,1,2,1,5,23}
+#define OIDicmpOutTimestampReps {1,3,6,1,2,1,5,24}
+#define OIDicmpOutAddrMasks {1,3,6,1,2,1,5,25}
+#define OIDicmpOutAddrMaskReps {1,3,6,1,2,1,5,26}
+#define OIDicmpInDestUnreachs {1,3,6,1,2,1,5,3}
+#define OIDicmpInTimeExcds {1,3,6,1,2,1,5,4}
+#define OIDicmpInParmProbs {1,3,6,1,2,1,5,5}
+#define OIDicmpInSrcQuenchs {1,3,6,1,2,1,5,6}
+#define OIDicmpInRedirects {1,3,6,1,2,1,5,7}
+#define OIDicmpInEchos {1,3,6,1,2,1,5,8}
+#define OIDicmpInEchoReps {1,3,6,1,2,1,5,9}
+#define OIDtcp {1,3,6,1,2,1,6}
+#define OIDtcpRtoAlgorithm {1,3,6,1,2,1,6,1}
+#define OIDtcpInSegs {1,3,6,1,2,1,6,10}
+#define OIDtcpOutSegs {1,3,6,1,2,1,6,11}
+#define OIDtcpRetransSegs {1,3,6,1,2,1,6,12}
+#define OIDtcpConnTable {1,3,6,1,2,1,6,13}
+#define OIDtcpConnEntry {1,3,6,1,2,1,6,13,1}
+#define OIDtcpConnState {1,3,6,1,2,1,6,13,1,1}
+#define OIDtcpConnLocalAddress {1,3,6,1,2,1,6,13,1,2}
+#define OIDtcpConnLocalPort {1,3,6,1,2,1,6,13,1,3}
+#define OIDtcpConnRemAddress {1,3,6,1,2,1,6,13,1,4}
+#define OIDtcpConnRemPort {1,3,6,1,2,1,6,13,1,5}
+#define OIDtcpInErrs {1,3,6,1,2,1,6,14}
+#define OIDtcpOutRsts {1,3,6,1,2,1,6,15}
+#define OIDtcpRtoMin {1,3,6,1,2,1,6,2}
+#define OIDtcpRtoMax {1,3,6,1,2,1,6,3}
+#define OIDtcpMaxConn {1,3,6,1,2,1,6,4}
+#define OIDtcpActiveOpens {1,3,6,1,2,1,6,5}
+#define OIDtcpPassiveOpens {1,3,6,1,2,1,6,6}
+#define OIDtcpAttemptFails {1,3,6,1,2,1,6,7}
+#define OIDtcpEstabResets {1,3,6,1,2,1,6,8}
+#define OIDtcpCurrEstab {1,3,6,1,2,1,6,9}
+#define OIDudp {1,3,6,1,2,1,7}
+#define OIDudpInDatagrams {1,3,6,1,2,1,7,1}
+#define OIDudpNoPorts {1,3,6,1,2,1,7,2}
+#define OIDudpInErrors {1,3,6,1,2,1,7,3}
+#define OIDudpOutDatagrams {1,3,6,1,2,1,7,4}
+#define OIDudpTable {1,3,6,1,2,1,7,5}
+#define OIDudpEntry {1,3,6,1,2,1,7,5,1}
+#define OIDudpLocalAddress {1,3,6,1,2,1,7,5,1,1}
+#define OIDudpLocalPort {1,3,6,1,2,1,7,5,1,2}
+#define OIDegp {1,3,6,1,2,1,8}
+#define OIDegpInMsgs {1,3,6,1,2,1,8,1}
+#define OIDegpInErrors {1,3,6,1,2,1,8,2}
+#define OIDegpOutMsgs {1,3,6,1,2,1,8,3}
+#define OIDegpOutErrors {1,3,6,1,2,1,8,4}
+#define OIDegpNeighTable {1,3,6,1,2,1,8,5}
+#define OIDegpNeighEntry {1,3,6,1,2,1,8,5,1}
+#define OIDegpNeighState {1,3,6,1,2,1,8,5,1,1}
+#define OIDegpNeighStateUps {1,3,6,1,2,1,8,5,1,10}
+#define OIDegpNeighStateDowns {1,3,6,1,2,1,8,5,1,11}
+#define OIDegpNeighIntervalHello {1,3,6,1,2,1,8,5,1,12}
+#define OIDegpNeighIntervalPoll {1,3,6,1,2,1,8,5,1,13}
+#define OIDegpNeighMode {1,3,6,1,2,1,8,5,1,14}
+#define OIDegpNeighEventTrigger {1,3,6,1,2,1,8,5,1,15}
+#define OIDegpNeighAddr {1,3,6,1,2,1,8,5,1,2}
+#define OIDegpNeighAs {1,3,6,1,2,1,8,5,1,3}
+#define OIDegpNeighInMsgs {1,3,6,1,2,1,8,5,1,4}
+#define OIDegpNeighInErrs {1,3,6,1,2,1,8,5,1,5}
+#define OIDegpNeighOutMsgs {1,3,6,1,2,1,8,5,1,6}
+#define OIDegpNeighOutErrs {1,3,6,1,2,1,8,5,1,7}
+#define OIDegpNeighInErrMsgs {1,3,6,1,2,1,8,5,1,8}
+#define OIDegpNeighOutErrMsgs {1,3,6,1,2,1,8,5,1,9}
+#define OIDegpAs {1,3,6,1,2,1,8,6}
+#define OIDexperimental {1,3,6,1,3}
+#define OIDprivate {1,3,6,1,4}
+#define OIDenterprises {1,3,6,1,4,1}
+
+#endif // __SNMPOIDS_H \ No newline at end of file
diff --git a/shared-code/SNMPeer.h b/shared-code/SNMPeer.h
new file mode 100644
index 0000000..68f2efe
--- a/dev/null
+++ b/shared-code/SNMPeer.h
@@ -0,0 +1,286 @@
+#ifndef __SNMPEER_H
+#define __SNMPEER_H
+
+namespace Klever {
+
+class CASNAny {
+public:
+ enum {
+ asnCls = 0xC0,
+ asnClsUniversal = 0x00,
+ asnClsApplication = 0x40,
+ asnClsContextSpecific = 0x80,
+ asnClsPrivate = 0xC0,
+ asnConstructed = 0x20,
+ asnPrimitive = 0x00,
+ asnTag = 0x1F,
+ // ASN.1 Primitive Tags
+ asnTagInteger = 0x02,
+ asnTagOctetString = 0x04,
+ asnTagNull = 0x05,
+ asnTagOID = 0x06,
+ // ASN.1 Constructed Tags
+ asnTagSequence = 0x10,
+ // RFC1155 Primitive Tags
+ asnTagIP = 0x00,
+ asnTagCounter = 0x01,
+ asnTagGauge = 0x02,
+ asnTagTicks = 0x03,
+ asnTagOpaque = 0x04,
+ // RFC1213 alias
+ asnTagDispString = 0x04, // (ASN.1 Octet string)
+ // RFC1157 Constructed Tags
+ asnTagGetRequest = 0x00,
+ asnTagGetNextRequest = 0x01,
+ asnTagGetResponse = 0x02,
+ asnTagSetRequest = 0x03,
+ asnTagTrap = 0x04
+ };
+ enum {
+ typeASNInteger = (asnClsUniversal|asnPrimitive|asnTagInteger),
+ typeASNOctetString = (asnClsUniversal|asnPrimitive|asnTagOctetString),
+ typeASNNull = (asnClsUniversal|asnPrimitive|asnTagNull),
+ typeASNOID = (asnClsUniversal|asnPrimitive|asnTagOID),
+
+ typeASNSequence = (asnClsUniversal|asnConstructed|asnTagSequence),
+ typeASNSequenceOf = (asnClsUniversal|asnConstructed|asnTagSequence),
+
+ typeASNIP = (asnClsApplication|asnPrimitive|asnTagIP),
+ typeASNCounter = (asnClsApplication|asnPrimitive|asnTagCounter),
+ typeASNGauge = (asnClsApplication|asnPrimitive|asnTagGauge),
+ typeASNTicks = (asnClsApplication|asnPrimitive|asnTagTicks),
+ typeASNOpaque = (asnClsApplication|asnPrimitive|asnTagOpaque),
+ typeASNDispString = (asnClsUniversal|asnPrimitive|asnTagOctetString),
+
+ typeASNGetRequest = (asnClsContextSpecific|asnConstructed|asnTagGetRequest),
+ typeASNGetNextRequest = (asnClsContextSpecific|asnConstructed|asnTagGetNextRequest),
+ typeASNGetResponse = (asnClsContextSpecific|asnConstructed|asnTagGetResponse),
+ typeASNSetRequest = (asnClsContextSpecific|asnConstructed|asnTagSetRequest),
+ typeASNTrap = (asnClsContextSpecific|asnConstructed|asnTagTrap)
+ };
+
+ typedef LONG asnInteger;
+ typedef LARGE_INTEGER asnInteger64;
+ typedef DWORD asnCounter;
+ typedef ULARGE_INTEGER asnCounter64;
+ typedef DWORD asnGauge;
+ typedef ULARGE_INTEGER asnGauge64;
+ typedef DWORD asnTicks;
+ typedef ULARGE_INTEGER asnTicks64;
+ struct asnDynamic {
+ UINT size;
+ LPBYTE data;
+ BOOL Allocate(UINT size) {
+ BOOL rv = Free();
+ if(size)
+ rv=rv&&(data=new BYTE[size]);
+ if(rv)
+ asnDynamic::size=size;
+ return rv;
+ }
+ BOOL Set(LPBYTE data,UINT size) {
+ BOOL rv = Allocate(size);
+ if(rv && size)
+ memmove(asnDynamic::data,data,size);
+ return rv;
+ }
+ BOOL Free() {
+ if(!size)
+ return TRUE;
+ delete data;
+ size=0;
+ data=0;
+ return TRUE;
+ }
+ void Clean() {
+ size=0;
+ data=0;
+ }
+ BOOL Copy(asnDynamic& src) {
+ BOOL rv = Free();
+ if(rv){
+ if(src.size)
+ rv=rv&&(data = new BYTE[src.size]);
+ if(rv){
+ if(size=src.size)
+ memmove(data,src.data,size);
+ }
+ }
+ return rv;
+ }
+ };
+ typedef asnDynamic asnOctetString;
+ typedef asnDynamic asnOID;
+ typedef in_addr asnIP;
+ typedef asnDynamic asnSequence;
+
+ BYTE type;
+ enum _storeType {
+ storeDynamic,
+ storeStatic
+ } storeType;
+ union {
+ asnInteger number;
+ asnInteger64 number64;
+ asnOctetString string;
+ asnOID oid;
+ asnSequence sequence;
+ asnIP ip;
+ asnCounter counter;
+ asnCounter64 counter64;
+ asnGauge gauge;
+ asnGauge64 gauge64;
+ asnTicks ticks;
+ asnTicks64 ticks64;
+ asnDynamic data;
+ } value;
+
+ CASNAny() : type(typeASNNull), storeType(storeStatic) { value.data.Clean(); }
+ CASNAny(CASNAny& src) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Copy(src); }
+ CASNAny(BYTE type) : type(type), storeType(storeStatic) { value.data.Clean(); }
+ CASNAny(BYTE type,LONG number) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,number); }
+ CASNAny(BYTE type,LONGLONG number) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,number); }
+ CASNAny(BYTE type,LPCTSTR string) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,string); }
+ CASNAny(BYTE type,LPBYTE data,UINT length) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,data,length); }
+ CASNAny(BYTE type,UINT* data,UINT size) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,(LPBYTE)data,size); }
+ CASNAny(in_addr& ip) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(ip); }
+ ~CASNAny() { Free(); }
+
+ BOOL Set(BYTE type) {
+ BOOL rv = Free();
+ CASNAny::type=type;
+ return rv;
+ }
+ BOOL Set(BYTE type,LONG number) {
+ BOOL rv = Free();
+ CASNAny::type=type;
+ value.number=number;
+ storeType=storeStatic;
+ return rv;
+ }
+ BOOL Set(BYTE type,LONGLONG number) {
+ BOOL rv = Free();
+ CASNAny::type=type;
+ value.number64.QuadPart = number;
+ storeType=storeStatic;
+ return rv;
+ }
+ BOOL Set(BYTE type,LPCTSTR string) {
+ BOOL rv = Free();
+ CASNAny::type=type;
+ rv=rv&&value.string.Set((LPBYTE)string,strlen(string)+1);
+ if(rv){
+ value.string.size--;
+ storeType=storeDynamic;
+ }
+ return rv;
+ }
+ BOOL Set(BYTE type,LPBYTE data,UINT length) {
+ BOOL rv = Free();
+ CASNAny::type=type;
+ rv=rv&&value.data.Set(data,length);
+ if(rv)
+ storeType=storeDynamic;
+ return rv;
+ }
+ BOOL Set(in_addr& ip) {
+ BOOL rv = Free();
+ memmove(&value.ip,&ip,sizeof(value.ip));
+ type=typeASNIP;
+ storeType=storeStatic;
+ return rv;
+ }
+ BOOL Free() {
+ if(storeType==storeDynamic)
+ value.data.Free();
+ else{
+ memset(&value,0,sizeof(value));
+ value.data.Clean();
+ }
+ storeType=storeStatic;
+ type=typeASNNull;
+ return TRUE;
+ }
+ BOOL Copy(CASNAny& src) {
+ BOOL rv = Free();
+ if(src.storeType==storeDynamic){
+ rv=rv&&value.data.Copy(src.value.data);
+ if(rv){
+ type=src.type;
+ storeType=src.storeType;
+ }
+ }else{
+ memmove(this,&src,sizeof(*this));
+ }
+ return rv;
+ }
+ CASNAny& operator=(CASNAny& src) {
+ VERIFY(Copy(src));
+ return *this;
+ }
+
+ // High Level
+ CString GetString() {
+ ASSERT(storeType==storeDynamic);
+ CString rv;
+ LPTSTR b = rv.GetBuffer(value.data.size+1);
+ ASSERT(b);
+ b[value.data.size]=0;
+ memmove(b,value.data.data,value.data.size);
+ rv.ReleaseBuffer();
+ return rv;
+ }
+};
+
+
+class CSNMPVarBind {
+public:
+ CASNAny name;
+ CASNAny value;
+
+ CSNMPVarBind() {}
+ CSNMPVarBind(CASNAny& name,CASNAny& value) : name(name), value(value) {}
+ CSNMPVarBind(CASNAny& name) : name(name) {}
+ CSNMPVarBind(CSNMPVarBind& src) { Copy(src); }
+ BOOL Copy(CSNMPVarBind& src) {
+ name.Copy(src.name);
+ value.Copy(src.value);
+ return TRUE;
+ }
+ CSNMPVarBind& operator=(CSNMPVarBind& src) {
+ Copy(src);
+ return *this;
+ }
+ // High level
+ BOOL IsName(UINT* prefix,UINT prefixSize,BOOL bExact=FALSE) {
+ if(name.type!=CASNAny::typeASNOID)
+ return FALSE;
+ if(name.value.oid.size<prefixSize)
+ return FALSE;
+ if(bExact && (name.value.oid.size!=prefixSize))
+ return FALSE;
+ return !memcmp(prefix,name.value.oid.data,prefixSize);
+ }
+};
+
+class CSNMPVarBindList : public CList<CSNMPVarBind,CSNMPVarBind&> {
+public:
+ CSNMPVarBind* GetVarBind(UINT* prefix,UINT prefixSize,BOOL bExact=FALSE) {
+ POSITION p = GetHeadPosition();
+ while(p){
+ CSNMPVarBind& vb = GetNext(p);
+ if(vb.IsName(prefix,prefixSize,bExact))
+ return &vb;
+ }
+ return NULL;
+ }
+};
+
+class CSNMPeer {
+public:
+ virtual BOOL Request(BYTE type,CSNMPVarBindList& in,CSNMPVarBindList& ou) = 0;
+};
+
+};
+
+#endif // __SNMPEER_H
diff --git a/shared-code/install.h b/shared-code/install.h
new file mode 100644
index 0000000..8c55ca9
--- a/dev/null
+++ b/shared-code/install.h
@@ -0,0 +1,370 @@
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+#define WIN32_EXTRALEAN
+#include <windows.h>
+#include <shlobj.h>
+#include <winver.h>
+#include <crtdbg.h>
+#include <string.h>
+#include <stdio.h>
+
+extern "C" WINSHELLAPI void WINAPI SHFree( LPVOID);
+
+template<class T> class Smart {
+public:
+ T *pT;
+
+ Smart() : pT(NULL) {}
+ Smart(int cb) : pT(new T[cb]) {}
+ Smart(T* p) : pT(p) {}
+ ~Smart() { if(pT)delete pT; }
+
+ Smart& operator=(T* p) { if(pT)delete pT; pT=p; return *this; }
+ operator T* () { return pT; }
+
+// T& operator[](int ndx) { return pT[ndx]; }
+
+ T* Detach() { T* rv = pT; pT=NULL; return rv; }
+};
+typedef Smart<char> STRING;
+
+#define APPEND_SLASH(str) if((str)[strlen(str)-1]!='\\')strcat(str,"\\")
+
+HINSTANCE theInstance;
+
+LPSTR strFETCH_REG_KEY(HKEY hRoot,LPCSTR subKey,LPCSTR val)
+{
+HKEY hkey;
+ if(RegOpenKeyEx(hRoot,subKey,0,KEY_QUERY_VALUE,&hkey)!=ERROR_SUCCESS)
+ return NULL;
+DWORD kType,cb=0;
+STRING rv;
+ if(RegQueryValueEx(hkey,val,NULL,&kType,NULL,&cb)==ERROR_SUCCESS && kType==REG_SZ){
+ rv= new char[cb];
+ _ASSERT(rv!=NULL);
+ if(RegQueryValueEx(hkey,val,NULL,&kType,(LPBYTE)(LPSTR)rv,&cb)!=ERROR_SUCCESS)
+ rv=NULL;
+ }
+ RegCloseKey(hkey);
+ return rv.Detach();
+}
+
+BOOL strSET_REG_KEY(HKEY hRoot,LPCSTR subKey,LPCSTR valName,LPCSTR val)
+{
+HKEY hkey;
+DWORD dw;
+ if(RegCreateKeyEx(hRoot,subKey,0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,NULL,&hkey,&dw)!=ERROR_SUCCESS)
+ return FALSE;
+BOOL rv = (RegSetValueEx(hkey,valName,0,REG_SZ,(LPBYTE)val,strlen(val)+1)==ERROR_SUCCESS);
+ RegCloseKey(hkey);
+ return rv;
+}
+
+void MAKE_PATH(LPCSTR path)
+{
+STRING tmp(strlen(path)+1);
+LPCSTR t0=path;
+LPSTR t1=tmp;
+ while(*t0){
+ if((*t0)=='\\'){
+ *t1=0;
+ CreateDirectory(tmp,NULL);
+ }
+ *(t1++)=*(t0++);
+ }
+ *t1=0;
+ CreateDirectory(tmp,NULL);
+}
+
+BOOL ADDMENU(LPCSTR menu,LPCSTR item,LPCSTR path,LPCSTR program)
+{
+STRING stm = strFETCH_REG_KEY(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders","Programs");
+ if(!stm)
+ return FALSE;
+int pil = 1+strlen(path)+1+strlen(program)+1+1;
+STRING pi(pil);
+ strcpy(pi,path);
+ APPEND_SLASH(pi);
+ strcat(pi,program);
+int ipl = strlen(stm)+1+strlen(menu)+1+strlen(item)+4+1;
+STRING ip(ipl);
+ memmove(ip,stm,strlen(stm)+1);
+ APPEND_SLASH(ip);
+ strcat(ip,menu);
+ MAKE_PATH(ip);
+ APPEND_SLASH(ip);
+ strcat(ip,item);
+ strcat(ip,".lnk");
+IShellLink* sl = NULL;
+IPersistFile* pf = NULL;
+BOOL rv = FALSE;
+ do{
+ HRESULT hrv = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(LPVOID*)&sl);
+ if(!SUCCEEDED(hrv))
+ break;
+ sl->SetDescription(item);
+ sl->SetPath(pi);
+ hrv = sl->QueryInterface(IID_IPersistFile,(LPVOID*)&pf);
+ if(!SUCCEEDED(hrv))
+ break;
+ WORD wsz[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,ip,-1,wsz,MAX_PATH);
+ hrv = pf->Save(wsz,TRUE);
+ if(SUCCEEDED(hrv))
+ rv=TRUE;
+ }while(FALSE);
+ if(pf)
+ pf->Release();
+ if(sl)
+ sl->Release();
+ return rv;
+}
+
+FILE* CREATE_INF_FILE(LPCSTR path,LPCSTR file)
+{
+STRING fn(strlen(path)+1+strlen(file)+1);
+ strcpy(fn,path);
+ APPEND_SLASH(fn);
+ strcat(fn,file);
+ return fopen(fn,"wt");
+}
+
+BOOL INSTALLFILE(LPCSTR res,LPCSTR path,LPCSTR file)
+{
+STRING temp(MAX_PATH);
+ if(!GetTempPath(MAX_PATH,temp)) return FALSE;
+STRING tf(MAX_PATH);
+ if(!GetTempFileName(temp,"KGI",0,tf)) return FALSE;
+HRSRC hrsrc = FindResource(NULL,res,MAKEINTRESOURCE(RT_RCDATA));
+ if(!hrsrc) return FALSE;
+DWORD sor = SizeofResource(NULL,hrsrc);
+ if(!sor) return FALSE;
+HGLOBAL hglobal = LoadResource(NULL,hrsrc);
+ if(!hglobal) return FALSE;
+LPVOID lpv = LockResource(hglobal);
+ if(!lpv) return FALSE;
+HANDLE hf = CreateFile(tf,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY,NULL);
+ if(!hf) return FALSE;
+DWORD written = 0;
+ if(!WriteFile(hf,lpv,sor,&written,NULL) || written!=sor){
+ CloseHandle(hf);
+ return FALSE;
+ }
+ CloseHandle(hf);
+STRING toKill(strlen(tf)+1);
+ strcpy(toKill,tf);
+ for(int tmp=strlen(tf)-1;tmp>0 && ((tf[tmp])!='\\');tmp--);
+ if(tf[tmp]=='\\')
+ tf[tmp++]=0;
+STRING nothing(_MAX_PATH);
+UINT nothingLength=_MAX_PATH;
+ if(VerInstallFile(0,&tf[tmp],(LPSTR)file,tf,(LPSTR)path,NULL,nothing,&nothingLength)){
+ DeleteFile(toKill);
+ return FALSE;
+ }
+ DeleteFile(toKill);
+ return TRUE;
+}
+
+LPCSTR pdTitle, pdPrompt;
+char pdPath[_MAX_PATH];
+BOOL CALLBACK pathDlgProc(HWND hwnd,UINT uMsg,WPARAM wP,LPARAM lP)
+{
+ switch(uMsg){
+ case WM_INITDIALOG:
+ SetWindowText(hwnd,pdTitle);
+ SetDlgItemText(hwnd,IDC_PROMPT,pdPrompt);
+ SetDlgItemText(hwnd,IDC_PATH,pdPath);
+ SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
+ return 1;
+ case WM_COMMAND:
+ switch(LOWORD(wP)){ // ID
+ case IDC_BROWSE:
+ switch(HIWORD(wP)){
+ case BN_CLICKED:
+ {
+ BROWSEINFO bi;
+ memset(&bi,0,sizeof(bi));
+ bi.hwndOwner=hwnd;
+ bi.pszDisplayName=pdPath;
+ bi.lpszTitle="Select Folder..";
+ bi.ulFlags=BIF_RETURNONLYFSDIRS;
+ LPITEMIDLIST lpidl=SHBrowseForFolder(&bi);
+ if(lpidl){
+ SHGetPathFromIDList(lpidl,pdPath);
+ SHFree(lpidl);
+ SetDlgItemText(hwnd,IDC_PATH,pdPath);
+ }
+ }
+ return 1;
+ }
+ break;
+ case IDOK:
+ switch(HIWORD(wP)){
+ case BN_CLICKED:
+ if(GetDlgItemText(hwnd,IDC_PATH,pdPath,sizeof(pdPath)))
+ EndDialog(hwnd,IDOK);
+ else
+ // *** Error message
+ EndDialog(hwnd,IDCANCEL);
+ return 1;
+ }
+ break;
+ case IDCANCEL:
+ switch(HIWORD(wP)){
+ case BN_CLICKED:
+ EndDialog(hwnd,IDCANCEL);
+ return 1;
+ }
+ break;
+ };
+ break;
+ }
+ return 0;
+}
+
+LPSTR REQUESTPATH(LPCSTR title,LPCSTR prompt,LPCSTR defPath)
+{
+ pdTitle=title;pdPrompt=prompt;
+ strcpy(pdPath,defPath);
+ if(DialogBox(NULL,MAKEINTRESOURCE(IDD_PATH),NULL/*Parent*/,(DLGPROC)&pathDlgProc)!=IDOK)
+ return NULL;
+STRING rv(strlen(pdPath)+1);
+ strcpy(rv,pdPath);
+ return rv.Detach();
+}
+
+HKEY uninstallKey(LPCSTR regKey) {
+ STRING rk(100+strlen(regKey)+1);
+ sprintf(rk,"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s",regKey);
+ HKEY rv = NULL;
+ DWORD dw;
+ if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,rk,0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,NULL,&rv,&dw)!=ERROR_SUCCESS)
+ return NULL;
+ return rv;
+}
+
+BOOL REG_UNINSTALL_COMMAND(LPCSTR regKey,LPCSTR dName,LPCSTR iPath,LPCSTR iFile,LPCSTR iSection)
+{
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ BOOL rv=FALSE;
+ do{
+ if(RegSetValueEx(hKey,"DisplayName",0,REG_SZ,(LPBYTE)dName,strlen(dName)+1)!=ERROR_SUCCESS)
+ break;
+ STRING us(50+strlen(iPath)+1+strlen(iFile)+strlen(iSection)+1);
+ strcpy(us,"RunDll32 setupapi.dll,InstallHinfSection ");
+ strcat(us,iSection);
+ strcat(us," 132 ");
+ strcat(us,iPath);
+ APPEND_SLASH(us);
+ strcat(us,iFile);
+ if(RegSetValueEx(hKey,"UninstallString",0,REG_SZ,(LPBYTE)(LPCSTR)us,strlen(us)+1)!=ERROR_SUCCESS)
+ break;
+ rv=TRUE;
+ }while(FALSE);
+ RegCloseKey(hKey);
+ return rv;
+}
+BOOL REG_UNINSTALL_ICON(LPCSTR regKey,LPCSTR path,LPCSTR file,int n) {
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ STRING uis(strlen(path)+1+strlen(file)+7);
+ strcpy(uis,path);
+ APPEND_SLASH(uis);
+ strcat(uis,file);
+ char tmp[8];
+ sprintf(tmp,";%d",n);
+ strcat(uis,tmp);
+ BOOL rv = TRUE;
+ if(RegSetValueEx(hKey,"DisplayIcon",0,REG_SZ,(LPBYTE)(LPCSTR)uis,strlen(uis)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ RegCloseKey(hKey);
+ return rv;
+}
+BOOL REG_UNINSTALL_COMMENT(LPCSTR regKey,LPCSTR comment) {
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ BOOL rv = TRUE;
+ if(RegSetValueEx(hKey,"lComment",0,REG_SZ,(LPBYTE)comment,strlen(comment)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ RegCloseKey(hKey);
+ return rv;
+}
+BOOL REG_UNINSTALL_VERSION(LPCSTR regKey,LPCSTR version) {
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ BOOL rv = TRUE;
+ if(RegSetValueEx(hKey,"DisplayVersion",0,REG_SZ,(LPBYTE)version,strlen(version)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ RegCloseKey(hKey);
+ return rv;
+}
+BOOL REG_UNINSTALL_LOCATION(LPCSTR regKey,LPCSTR location) {
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ BOOL rv = TRUE;
+ if(RegSetValueEx(hKey,"InstallLocation",0,REG_SZ,(LPBYTE)location,strlen(location)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ RegCloseKey(hKey);
+ return rv;
+}
+BOOL REG_UNINSTALL_PUBLISHER(LPCSTR regKey,LPCSTR publisher) {
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ BOOL rv = TRUE;
+ if(RegSetValueEx(hKey,"Publisher",0,REG_SZ,(LPBYTE)publisher,strlen(publisher)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ RegCloseKey(hKey);
+ return rv;
+}
+BOOL REG_UNINSTALL_URLS(LPCSTR regKey,LPCSTR about,LPCSTR update) {
+ HKEY hKey = uninstallKey(regKey);
+ if(!hKey)
+ return FALSE;
+ BOOL rv = TRUE;
+ if(RegSetValueEx(hKey,"URLInfoAbout",0,REG_SZ,(LPBYTE)about,strlen(about)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ if(RegSetValueEx(hKey,"URLUpdateInfo",0,REG_SZ,(LPBYTE)update,strlen(update)+1)!=ERROR_SUCCESS)
+ rv = FALSE;
+ RegCloseKey(hKey);
+ return rv;
+}
+
+#define INF_FILE_HEADER(i) fprintf(i,"[Version]\nSignature=\"$CHICAGO$\"\n\n")
+#define INF_FILE_SECTION(i,s) fprintf(i,"\n[%s]\n",s)
+#define INF_UNINSTALL_REG(i,p) fprintf(i,"HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s\nHKLM,Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s,DisplayName\nHKLM,Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s,UninstallString\n",p,p,p)
+#define INF_MENU_GROUP(i,n,m) fprintf(i,"setup.ini, progman.groups,,\"group%d=%s\"\n",n,m)
+#define INF_MENU_ITEM(i,n,m) fprintf(i,"setup.ini, group%d,, \"\"\"%s\"\"\"\n",n,m);
+#define INF_REMOVE_ROOT(i,g,r) fprintf(i,"HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\DeleteFiles\\%s,,,\"%s\"\n",g,r)
+#define INF_REMOVE_FILE(i,g,f) fprintf(i,"HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\DeleteFiles\\%s,%s,,\"%s\"\n",g,f,f)
+#define INF_REMOVE_HELP_FILE(i,g,f) {INF_REMOVE_FILE(i,g,f".hlp");INF_REMOVE_FILE(i,g,f".cnt");INF_REMOVE_FILE(i,g,f".GID");INF_REMOVE_FILE(i,g,f".FTS");}
+
+LPSTR GET_SHORT_PATH(LPCSTR path)
+{
+char tmp;
+DWORD len = GetShortPathName(path,&tmp,1);
+ if(!len)
+ return NULL;
+STRING rv(len+1);
+ if(!GetShortPathName(path,rv,len+1))
+ return NULL;
+ return rv.Detach();
+}
+
+BOOL Install(void);
+
+int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int)
+{
+ theInstance=hInstance;
+ CoInitialize(NULL);
+ Install();
+ CoUninitialize();
+ return 0;
+}
diff --git a/shared-code/ip_icmp.h b/shared-code/ip_icmp.h
new file mode 100644
index 0000000..acaf7e9
--- a/dev/null
+++ b/shared-code/ip_icmp.h
@@ -0,0 +1,91 @@
+#ifndef IP_ICMPHEADER
+
+#define IP_ICMPHEADER
+
+struct icmp {
+ BYTE icmp_type;
+ BYTE icmp_code;
+ WORD icmp_cksum;
+ WORD icmp_id;
+ WORD icmp_seq;
+ char icmp_data[1];
+};
+
+#define SIZE_ICMP_HDR 8
+#define SIZE_TIME_DATA 8
+
+struct ip {
+ BYTE ip_hl:4, /* header length */
+ ip_v:4; /* version */
+ BYTE ip_tos; /* type of service */
+ short ip_len; /* total length */
+ u_short ip_id; /* identification */
+ short ip_off; /* fragment offset field */
+ BYTE ip_ttl; /* time to live */
+ BYTE ip_p; /* protocol */
+ u_short ip_sum; /* checksum */
+ struct in_addr ip_src,ip_dst; /* source and dest address */
+};
+
+#define ICMP_ECHOREPLY 0 /* echo reply */
+#define ICMP_UNREACH 3 /* dest unreachable, codes: */
+#define ICMP_UNREACH_NET 0 /* bad net */
+#define ICMP_UNREACH_HOST 1 /* bad host */
+#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
+#define ICMP_UNREACH_PORT 3 /* bad port */
+#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
+#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
+#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
+#define ICMP_REDIRECT 5 /* shorter route, codes: */
+#define ICMP_REDIRECT_NET 0 /* for network */
+#define ICMP_REDIRECT_HOST 1 /* for host */
+#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
+#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
+#define ICMP_ECHO 8 /* echo service */
+#define ICMP_TIMXCEED 11 /* time exceeded, code: */
+#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
+#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
+#define ICMP_PARAMPROB 12 /* ip header bad */
+#define ICMP_TSTAMP 13 /* timestamp request */
+#define ICMP_TSTAMPREPLY 14 /* timestamp reply */
+#define ICMP_IREQ 15 /* information request */
+#define ICMP_IREQREPLY 16 /* information reply */
+#define ICMP_MASKREQ 17 /* address mask request */
+#define ICMP_MASKREPLY 18 /* address mask reply */
+
+#define ICMP_MAXTYPE 18
+
+#define ICMP_MINLEN 8 /* abs minimum */
+#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */
+#define ICMP_MASKLEN 12 /* address mask */
+#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */
+#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
+
+#define STNORM 0
+
+/* Definition of the lowest telnet byte following an IAC byte */
+#define LOW_TEL_OPT 236
+
+#define TEL_EOF 236
+#define SUSP 237
+#define ABORT 238
+
+#define SE 240
+#define NOP 241
+#define DM 242
+#define BREAK 243
+#define IP 244
+#define AO 245
+#define AYT 246
+#define EC 247
+#define EL 248
+#define GOAHEAD 249
+#define SB 250
+#define WILL 251
+#define WONT 252
+#define DO 253
+#define DONT 254
+#define IAC 255
+
+#endif
+
diff --git a/shared-code/kHelpers.h b/shared-code/kHelpers.h
new file mode 100644
index 0000000..209c6b0
--- a/dev/null
+++ b/shared-code/kHelpers.h
@@ -0,0 +1,159 @@
+#ifndef __KHELPERS_H
+#define __KHELPERS_H
+
+#include <shlobj.h>
+
+extern "C" WINSHELLAPI void WINAPI SHFree( LPVOID);
+
+namespace Klever {
+
+ inline BOOL BrowseForFolder(CString& folder,LPCTSTR title=NULL,CWnd* pParent=NULL) {
+ BROWSEINFO bi;
+ memset(&bi,0,sizeof(bi));
+ if(pParent)
+ bi.hwndOwner=pParent->GetSafeHwnd();
+ CString rv;
+ bi.pszDisplayName=rv.GetBuffer(MAX_PATH);
+ bi.lpszTitle=title;
+ bi.ulFlags=BIF_RETURNONLYFSDIRS;
+ LPITEMIDLIST lpidl = SHBrowseForFolder(&bi);
+ if(lpidl){
+ SHGetPathFromIDList(lpidl,bi.pszDisplayName);
+ SHFree(lpidl);
+ rv.ReleaseBuffer();
+ folder=rv;
+ return TRUE;
+ }
+ rv.ReleaseBuffer();
+ return FALSE;
+ }
+ inline BOOL BrowseForFolder(CString& folder,UINT idTitle,CWnd* pParent=NULL) {
+ CString title;
+ VERIFY(title.LoadString(idTitle));
+ return BrowseForFolder(folder,title,pParent);
+ }
+ inline CString GluePathAndFile(LPCTSTR path,LPCTSTR file) {
+ CString rv = path;
+ while((!rv.IsEmpty()) && rv[rv.GetLength()-1]=='\\')
+ rv=rv.Left(rv.GetLength()-1);
+ rv+='\\';
+ while(*file && *file=='\\')
+ file++;
+ rv+=file;
+ return rv;
+ }
+ inline UINT TokenizeString(CStringList& rv,LPCTSTR string,LPCTSTR delimiter) {
+ CString s = string;
+ int found;
+ int delength = strlen(delimiter);
+ int rvc = 0;
+ while((found=s.Find(delimiter))>=0){
+ rv.AddTail(s.Left(found));
+ rvc++;
+ s=s.Mid(found+delength);
+ }
+ if(!s.IsEmpty()){
+ rv.AddTail(s);
+ rvc++;
+ }
+ return rvc;
+ }
+ inline BOOL LogRecord(LPCTSTR logFile,LPCTSTR logRecord) {
+ try{
+ CFile f(logFile,CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::shareDenyWrite);
+ f.SeekToEnd();
+ CString s = CTime::GetCurrentTime().Format("[%c] ")+logRecord+"\r\n";
+ f.Write((LPCTSTR)s,s.GetLength());
+ }catch(CException* e){
+ e->Delete();
+ return FALSE;
+ }
+ return TRUE;
+ }
+ inline BOOL ReadString(CFile* file,CString& rv) {
+ rv.Empty();
+ int nBuffer = 256;
+ TCHAR* ch = rv.GetBuffer(nBuffer);
+ int nPos = 0;
+ BOOL bRV = FALSE;
+ for(;;){
+ TCHAR c;
+ try{
+ if(file->Read(&c,sizeof(c))!=sizeof(c))
+ break;
+ bRV=TRUE;
+ }catch(CException* e){
+ e->Delete();
+ TRACE0("Exception in ReadString\n");
+ return FALSE;
+ }
+ if(nPos>=(nBuffer-1)){
+ rv.ReleaseBuffer();
+ ch = rv.GetBuffer(nBuffer=nBuffer+256);
+ ASSERT(ch);
+ }
+ if(c=='\n')
+ break;
+ ch[nPos++]=c;
+ }
+ ch[nPos]=0;
+ for(;;){
+ nPos--;
+ if(nPos<0)
+ break;
+ if(ch[nPos]!='\r')
+ break;
+ ch[nPos]=0;
+ }
+ rv.ReleaseBuffer();
+ rv.FreeExtra();
+ return bRV;
+ }
+
+ inline int LoadStringList(CStringList& list,LPCTSTR section) {
+ CString n;
+ list.RemoveAll();
+ CWinApp* app = AfxGetApp();
+ ASSERT(app);
+ for(int tmp=0;;tmp++){
+ n.Format("%d",tmp);
+ CString str = app->GetProfileString(section,n,NULL);
+ if(str.IsEmpty())
+ break;
+ list.AddTail(str);
+ }
+ return tmp;
+ }
+ inline int SaveStringList(CStringList& list,LPCTSTR section) {
+ CString n;
+ CWinApp* app = AfxGetApp();
+ ASSERT(app);
+ POSITION p = list.GetHeadPosition();
+ for(int tmp=0;p;tmp++){
+ n.Format("%d",tmp);
+ app->WriteProfileString(section,n,list.GetNext(p));
+ }
+ n.Format("%d",tmp);
+ app->WriteProfileString(section,n,NULL);
+ return tmp;
+ }
+
+ inline BOOL WriteProfileString(LPCTSTR section,LPCTSTR entry,LPCTSTR str) {
+ CWinApp* app = AfxGetApp();
+ return app->WriteProfileBinary(section,entry,(LPBYTE)str,strlen(str)+1);
+ }
+ inline CString GetProfileString(LPCTSTR section,LPCTSTR entry,LPCTSTR defval) {
+ CWinApp* app = AfxGetApp();
+ LPBYTE pData;
+ UINT nCount;
+ CString rv = defval;
+ if(app->GetProfileBinary(section,entry,&pData,&nCount)){
+ rv = (LPCTSTR)pData;
+ delete pData;
+ }
+ return rv;
+ }
+
+};
+
+#endif // __KHELPERS_H
diff --git a/shared-code/kICMP.cpp b/shared-code/kICMP.cpp
new file mode 100644
index 0000000..09a8f94
--- a/dev/null
+++ b/shared-code/kICMP.cpp
@@ -0,0 +1,300 @@
+#include "../stdafx.h"
+#include "kICMP.h"
+
+CICMP::_mechanismus CICMP::m_mechanismus = CICMP::_icmpUndetermined;
+
+BOOL CICMPDll::Initialize()
+{
+ if(m_hICMP!=INVALID_HANDLE_VALUE || m_hICMPDLL)
+ Deinitialize();
+ m_hICMPDLL = ::LoadLibraryEx("ICMP",NULL,0);
+ if(!m_hICMPDLL)
+ return FALSE;
+ *(FARPROC*)&m_icmpCF = ::GetProcAddress(m_hICMPDLL,"IcmpCreateFile");
+ *(FARPROC*)&m_icmpSE = ::GetProcAddress(m_hICMPDLL,"IcmpSendEcho");
+ *(FARPROC*)&m_icmpCH = ::GetProcAddress(m_hICMPDLL,"IcmpCloseHandle");
+ if(!(m_icmpCF && m_icmpSE && m_icmpCH)){
+ Deinitialize(); return FALSE;
+ }
+ m_hICMP = (*m_icmpCF)();
+ if(m_hICMP==INVALID_HANDLE_VALUE){
+ Deinitialize(); return FALSE;
+ }
+ TRACE0("ICMP-DLL Initialized\n");
+ return TRUE;
+}
+void CICMPDll::Deinitialize()
+{
+ if(m_hICMPDLL){
+ if(m_hICMP!=INVALID_HANDLE_VALUE && m_icmpCH)
+ (*m_icmpCH)(m_hICMP);
+ ::FreeLibrary(m_hICMPDLL); m_hICMPDLL = NULL;
+ m_icmpCF = NULL;
+ m_icmpSE = NULL;
+ m_icmpCH = NULL;
+ }
+ m_hICMP=INVALID_HANDLE_VALUE;
+ if(m_sizeOut && m_bsOut){
+ delete m_bsOut;
+ m_bsOut = NULL; m_sizeOut = 0;
+ }
+ if(m_sizeIn && m_bsIn){
+ delete m_bsIn;
+ m_bsIn = NULL; m_sizeIn = 0;
+ }
+}
+
+LONG CICMPDll::Ping(const in_addr host,const UINT packetSize,
+ const UINT timeOut,LPINT pStatus)
+{
+ if(!(m_hICMP && m_hICMPDLL && m_icmpSE)){
+ if(pStatus)
+ (*pStatus) = icmpNotInitialized;
+ return -1;
+ }
+ VERIFY(AdjustBuffers(packetSize));
+IPINFO ipi;
+ memset(&ipi,0,sizeof(ipi));
+ ipi.Ttl = 30;
+ for(UINT tmp=0;tmp<packetSize;tmp++)
+ m_bsOut[tmp]=tmp&0xFF;
+LPICMPECHO pRep = (LPICMPECHO)m_bsIn;
+ pRep->Status = 0xFFFFFFFFl;
+ if((*m_icmpSE)(m_hICMP,host.s_addr,m_bsOut,packetSize,
+ &ipi,pRep,m_sizeIn,timeOut))
+ TRACE0("ICMP-SendEcho succeeded\n");
+ else
+ TRACE0("ICMP-SendEcho failed\n");
+LONG lrv = -1;
+INT rv = ipUnknown;
+ switch(pRep->Status){
+ case IP_SUCCESS:
+ lrv = pRep->RTTime; rv = ipSuccess;
+ break;
+ case IP_BUF_TOO_SMALL: rv = ipBuffTooSmall; break;
+ case IP_DEST_NET_UNREACHABLE: rv = ipDestNetUnreachable; break;
+ case IP_DEST_HOST_UNREACHABLE: rv = ipDestHostUnreachable; break;
+ case IP_DEST_PROT_UNREACHABLE: rv = ipDestProtUnreachable; break;
+ case IP_DEST_PORT_UNREACHABLE: rv = ipDestPortUnreachable; break;
+ case IP_NO_RESOURCES: rv = ipNoResources; break;
+ case IP_BAD_OPTION: rv = ipBadOption; break;
+ case IP_HW_ERROR: rv = ipHWError; break;
+ case IP_PACKET_TOO_BIG: rv = ipPacketTooBig; break;
+ case IP_REQ_TIMED_OUT: rv = ipTimeOut; break;
+ case IP_BAD_REQ: rv = ipBadRequest; break;
+ case IP_BAD_ROUTE: rv = ipBadRoute; break;
+ case IP_TTL_EXPIRED_TRANSIT: rv = ipTTLExpiredInTransit; break;
+ case IP_TTL_EXPIRED_REASSEM: rv = ipTTLExpiredInReasm; break;
+ case IP_PARAM_PROBLEM: rv = ipParamProblem; break;
+ case IP_SOURCE_QUENCH: rv = ipSourceQuench; break;
+ case IP_OPTION_TOO_BIG: rv = ipOptionTooBig; break;
+ case IP_BAD_DESTINATION: rv = ipBadDest; break;
+ }
+ if(pStatus)
+ (*pStatus)=rv;
+ return lrv;
+}
+
+BOOL CICMPDll::AdjustBuffers(UINT packetSize)
+{
+ if(!packetSize)
+ packetSize=1;
+ if(packetSize>m_sizeOut){
+ if(m_sizeOut && m_bsOut)
+ delete m_bsOut;
+ m_bsOut = new BYTE[m_sizeOut=packetSize];
+ if(!m_bsOut)
+ return FALSE;
+ }
+UINT sin = sizeof(ICMPECHO)+SIZE_ICMP_HDR+packetSize;
+ if(sin>m_sizeIn){
+ if(m_sizeIn && m_bsIn)
+ delete m_bsIn;
+ m_bsIn = new BYTE[m_sizeIn=sin];
+ if(!m_bsIn)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+WORD CICMPWS::m_icmpSeq = 0;
+
+BOOL CICMPWS::Initialize()
+{
+ if(m_socket!=INVALID_SOCKET)
+ Deinitialize();
+ m_socket = socket(AF_INET,SOCK_RAW,1/*ICMP*/);
+ if(m_socket==INVALID_SOCKET)
+ return FALSE;
+ TRACE0("ICMP-WS Initialized\n");
+ return TRUE;
+}
+void CICMPWS::Deinitialize()
+{
+ if(m_socket!=INVALID_SOCKET){
+ closesocket(m_socket);
+ m_socket=INVALID_SOCKET;
+ }
+ if(m_sizeOut && m_bsOut){
+ delete m_bsOut;
+ m_bsOut = NULL; m_sizeOut = 0;
+ }
+ if(m_sizeIn && m_bsIn){
+ delete m_bsIn;
+ m_bsIn = NULL; m_sizeIn = 0;
+ }
+}
+LONG CICMPWS::Ping(const in_addr host,const UINT packetSize,
+ const UINT timeOut,LPINT pStatus)
+{
+ if(m_socket==INVALID_SOCKET){
+ if(pStatus)
+ (*pStatus)=icmpNotInitialized;
+ }
+ VERIFY(AdjustBuffers(packetSize));
+icmp* pPacket = (icmp*)m_bsOut;
+ memset(pPacket,0,m_sizeOut);
+ pPacket->icmp_type = ICMP_ECHO;
+ pPacket->icmp_seq = m_icmpSeq++;
+ pPacket->icmp_id = (WORD)(::GetCurrentThreadId()&0xFFFF);
+ for(UINT tmp=0;tmp<packetSize;tmp++)
+ pPacket->icmp_data[tmp]=tmp&0xFF;
+ pPacket->icmp_cksum = cksum(pPacket,SIZE_ICMP_HDR+packetSize);
+sockaddr_in to;
+ memset(&to,0,sizeof(to));
+ to.sin_addr.s_addr = host.s_addr;
+ to.sin_family = AF_INET;
+ if(sendto(m_socket,(char*)pPacket,SIZE_ICMP_HDR+packetSize,0,
+ (SOCKADDR*)&to,sizeof(to)) != (int)(SIZE_ICMP_HDR+packetSize)){
+ TRACE1("sendto: %lu\n",WSAGetLastError());
+ if(pStatus)
+ (*pStatus)=icmpSocketError;
+ return -1;
+ }
+DWORD sentTime = ::GetTickCount();
+sockaddr_in from;
+ memset(&from,0,sizeof(from));
+ from.sin_family=AF_INET;
+ from.sin_addr.s_addr=INADDR_ANY;
+fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(m_socket,&fds);
+long lrv = -1;
+INT rv = ipTimeOut;
+ for(;;){
+ DWORD ct = ::GetTickCount();
+ if((ct-sentTime)>=timeOut){
+ TRACE0("Timeout\n");
+ break;
+ }
+ timeval tv = {
+ (timeOut-ct+sentTime)/1000,
+ (timeOut-ct+sentTime)%1000
+ }; // tv_sec, tv_usec (secs,microsecs)
+ if(!select(m_socket,&fds,NULL,NULL,&tv)){
+ TRACE1("select: %d\n",WSAGetLastError());
+ break;
+ }
+ DWORD rtime = ::GetTickCount();
+ ASSERT(FD_ISSET(m_socket,&fds));
+ int fl = sizeof(from);
+ int rb = recvfrom(m_socket,(char*)m_bsIn,m_sizeIn,0,(SOCKADDR*)&from,&fl);
+ ip* pIP = (ip*)m_bsIn;
+ icmp* pICMP = (icmp*)&m_bsIn[sizeof(ip)];
+ if(pICMP->icmp_id!=pPacket->icmp_id)
+ continue;
+ if(pICMP->icmp_seq!=pPacket->icmp_seq)
+ continue;
+ if(from.sin_addr.s_addr!=host.s_addr)
+ continue;
+ if(pICMP->icmp_type==ICMP_ECHOREPLY){
+ lrv=rtime-sentTime;
+ rv=ipSuccess;
+ break;
+ }
+ rv = ipUnknown; // ***
+ break;
+ }
+ if(pStatus)
+ (*pStatus)=rv;
+ return lrv;
+}
+
+BOOL CICMPWS::AdjustBuffers(UINT packetSize)
+{
+ if(!packetSize)
+ packetSize=0;
+UINT osize = packetSize+SIZE_ICMP_HDR;
+ if(m_sizeOut<osize){
+ if(m_sizeOut && m_bsOut)
+ delete m_bsOut;
+ m_bsOut = new BYTE[m_sizeOut=osize];
+ if(!m_bsOut)
+ return FALSE;
+ }
+UINT isize = osize+sizeof(ip);
+ if(m_sizeIn<isize){
+ if(m_sizeIn && m_bsIn)
+ delete m_bsIn;
+ m_bsIn = new BYTE[m_sizeIn=isize];
+ if(!m_bsIn)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+WORD CICMPWS::cksum(LPVOID data,int count)
+{
+long lSum = 0;
+WORD *pData = (WORD*)data;
+ while(count>0){
+ if(count>1){
+ lSum+=*(pData++);
+ count-=2;
+ }else{
+ lSum+=((WORD)*(BYTE*)pData)&0xFF;
+ count--;
+ }
+ }
+ lSum = (lSum&0xFFFF)+(lSum>>16);
+ lSum += (lSum>>16);
+ return (~lSum)&0xFFFF;
+}
+
+CICMP* CICMP::CreateICMP()
+{
+ if(m_mechanismus==_icmpUndetermined)
+ GuessMechanismus();
+ switch(m_mechanismus){
+ case _icmpWinsock:
+ return new CICMPWS;
+ break;
+ case _icmpDLL:
+ return new CICMPDll;
+ break;
+ }
+ return NULL;
+}
+
+void CICMP::GuessMechanismus()
+{
+ m_mechanismus=_icmpUndetermined;
+SOCKET testSocket = socket(AF_INET,SOCK_RAW,1);
+ if(testSocket!=INVALID_SOCKET){
+ closesocket(testSocket);
+ m_mechanismus=_icmpWinsock;
+ }else{
+ HINSTANCE hICMP = ::LoadLibraryEx("ICMP",NULL,0);
+ if(!hICMP)
+ return;
+ BOOL isThere = (
+ ::GetProcAddress(hICMP,"IcmpCreateFile")
+ && ::GetProcAddress(hICMP,"IcmpSendEcho")
+ && ::GetProcAddress(hICMP,"IcmpCloseHandle")
+ );
+ ::FreeLibrary(hICMP);
+ if(isThere)
+ m_mechanismus=_icmpDLL;
+ }
+} \ No newline at end of file
diff --git a/shared-code/kICMP.h b/shared-code/kICMP.h
new file mode 100644
index 0000000..7a5ceaa
--- a/dev/null
+++ b/shared-code/kICMP.h
@@ -0,0 +1,80 @@
+#ifndef __KICMP_H
+#define __KICMP_H
+
+class CICMP {
+ enum _mechanismus {
+ _icmpUndetermined = -1,
+ _icmpWinsock = 0, _icmpDLL
+ };
+static _mechanismus m_mechanismus;
+static void GuessMechanismus();
+public:
+static
+ CICMP* CreateICMP();
+
+ enum {
+ ipSuccess = 0,
+ ipBuffTooSmall, ipDestNetUnreachable, ipDestHostUnreachable,
+ ipDestProtUnreachable, ipDestPortUnreachable, ipNoResources,
+ ipBadOption, ipHWError, ipPacketTooBig, ipTimeOut, ipBadRequest,
+ ipBadRoute, ipTTLExpiredInTransit, ipTTLExpiredInReasm,
+ ipParamProblem, ipSourceQuench, ipOptionTooBig, ipBadDest,
+ ipUnknown = -1,
+ icmpNotInitialized = -2,
+ icmpSocketError = -3
+ };
+
+ virtual BOOL Initialize() = 0;
+ virtual void Deinitialize() = 0;
+
+ virtual LONG Ping(const in_addr host,const UINT packetSize=0,
+ const UINT timeOut=10000,LPINT pStatus=NULL) = 0;
+};
+
+class CICMPDll : public CICMP {
+ HANDLE (WINAPI *m_icmpCF)(VOID);
+ BOOL (WINAPI *m_icmpSE)(HANDLE,ULONG,LPVOID,WORD,
+ PIPINFO,LPVOID,DWORD,DWORD);
+ BOOL (WINAPI *m_icmpCH)(HANDLE);
+public:
+ HINSTANCE m_hICMPDLL;
+ HANDLE m_hICMP;
+ LPBYTE m_bsIn, m_bsOut;
+ UINT m_sizeIn, m_sizeOut;
+
+ CICMPDll() : m_hICMP(INVALID_HANDLE_VALUE), m_hICMPDLL(NULL),
+ m_bsIn(NULL), m_bsOut(NULL), m_sizeIn(0), m_sizeOut(0) {}
+ virtual ~CICMPDll() { Deinitialize(); }
+
+ virtual BOOL Initialize();
+ virtual void Deinitialize();
+
+ virtual LONG Ping(const in_addr host,const UINT packetSize=0,
+ const UINT timeOut=10000,LPINT pStatus=NULL);
+
+ BOOL AdjustBuffers(UINT packetSize=0);
+};
+
+class CICMPWS : public CICMP {
+static
+ WORD m_icmpSeq;
+public:
+ SOCKET m_socket;
+ LPBYTE m_bsIn, m_bsOut;
+ UINT m_sizeIn, m_sizeOut;
+
+ CICMPWS() : m_socket(INVALID_SOCKET), m_bsIn(NULL), m_bsOut(NULL),
+ m_sizeIn(0), m_sizeOut(0) {}
+ virtual ~CICMPWS() { Deinitialize(); }
+
+ virtual BOOL Initialize();
+ virtual void Deinitialize();
+
+ virtual LONG Ping(const in_addr host,const UINT packetSize=0,
+ const UINT timeOut=10000,LPINT pStatus=NULL);
+
+ BOOL AdjustBuffers(UINT packetSize=0);
+ WORD cksum(LPVOID data,int count);
+};
+
+#endif // __KICMP_H \ No newline at end of file
diff --git a/shared-code/kinhelp.xsl b/shared-code/kinhelp.xsl
new file mode 100644
index 0000000..0bb384a
--- a/dev/null
+++ b/shared-code/kinhelp.xsl
@@ -0,0 +1,250 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ >
+ <xsl:output
+ method="text"
+ encoding="us-ascii"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="winhelp">
+ <xsl:text>{\rtf1\ansi</xsl:text>
+ <xsl:text>&#xA;@{\footnote</xsl:text>
+ <xsl:text>&#xA;THIS FILE WAS AUTOMATICALLY GENERATED FROM XML DOCUMENT.</xsl:text>
+ <xsl:text>&#xA;DO NOT MODIFY THIS FILE DIRECTLY. EDIT XML DOCUMENT INSTEAD</xsl:text>
+ <xsl:text>&#xA;}&#xA;</xsl:text>
+ <xsl:call-template name="fonttbl"/>
+ <xsl:call-template name="colortbl"/>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="topic">
+ <xsl:text>&#xA;\pard\plain</xsl:text>
+ <xsl:if test="descendant::*[ (@scroll='no') and
+ count(preceding-sibling::*[not(@scroll='no') and (name()!='a' and @name)])=0] ">
+ <xsl:text>\keepn</xsl:text>
+ </xsl:if>
+ <xsl:if test="@id">
+ <xsl:text>&#xA;#{\footnote </xsl:text>
+ <xsl:value-of select="@id"/>
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+ <xsl:if test="@title">
+ <xsl:text>&#xA;${\footnote </xsl:text>
+ <xsl:value-of select="@title"/>
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+ <xsl:if test="@keywords">
+ <xsl:text>&#xA;K{\footnote </xsl:text>
+ <xsl:value-of select="@keywords"/>
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+ <xsl:apply-templates/>
+ <xsl:text>&#xA;\page&#xA;</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="a[@name]">
+ <xsl:text>{#{\footnote </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>}}</xsl:text>
+ </xsl:template>
+ <xsl:template match="a[@href]">
+ <xsl:call-template name="hyperref">
+ <xsl:with-param name="href" select="@href"/>
+ <xsl:with-param name="inset"><xsl:apply-templates/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template name="hyperref">
+ <xsl:param name="href"/>
+ <xsl:param name="inset"/>
+ <xsl:choose>
+ <xsl:when test="starts-with($href,'http:') or starts-with($href,'mailto:') or
+ starts-with($href,'ftp:')">
+ <xsl:text>{\uldb </xsl:text>
+ <xsl:value-of select="$inset"/>
+ <xsl:text>}{\v %!ExecFile("</xsl:text>
+ <xsl:value-of select="$href"/>
+ <xsl:text>")}</xsl:text>
+ </xsl:when>
+ <xsl:when test="starts-with($href,'#')">
+ <xsl:text>{\uldb </xsl:text>
+ <xsl:value-of select="$inset"/>
+ <xsl:text>}{\v </xsl:text>
+ <xsl:value-of select="substring($href,2)"/>
+ <xsl:text>}</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message>Warining: Unqualified hyper-reference. Using as help-internal</xsl:message>
+ <xsl:text>{\uldb </xsl:text>
+ <xsl:value-of select="$inset"/>
+ <xsl:text>}{\v </xsl:text>
+ <xsl:value-of select="$href"/>
+ <xsl:text>}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="heading">
+ <xsl:text>&#xA;</xsl:text>
+ <xsl:if test="@scroll!='no'">
+ <xsl:text>\pard </xsl:text>
+ </xsl:if>
+ <xsl:text>{ \f1\fs18\b\sb120 </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="p">
+ <xsl:text>&#xA;\par\sa120\sb120\qj</xsl:text>
+ <xsl:if test="@scroll!='no'">
+ <xsl:text>\pard</xsl:text>
+ </xsl:if>
+ <xsl:text> \f1\fs18\sb120 </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="note">
+ <xsl:text>&#xA;\par\sa120\sb120\qj\f1\fs16 </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="dedication">
+ <xsl:text>&#xA;\par\sa120\sb120\qr\f1\fs16 </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="image">
+ <xsl:text>\{bmct </xsl:text>
+ <xsl:value-of select="@source"/>
+ <xsl:text>\}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="newsfor">
+ <xsl:text>&#xA;\par\pard\plain\f1\fs24\qc\cf2\b </xsl:text>
+ <xsl:value-of select="@version"/>
+ <xsl:text> - </xsl:text>
+ <xsl:value-of select="@date"/>
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="ni">
+ <xsl:text>&#xA;\par\pard\plain\fi0\li0\f1\fs18 \bullet </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="b">
+ <xsl:text>{\b </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+ <xsl:template match="i">
+ <xsl:text>{\i </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+ <xsl:template match="u">
+ <xsl:text>{\ul </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+ <xsl:template match="strike">
+ <xsl:text>{\strike </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="kin">
+ <xsl:choose>
+ <xsl:when test="@href">
+ <xsl:call-template name="hyperref">
+ <xsl:with-param name="href" select="@href"/>
+ <xsl:with-param name="inset"><xsl:text>{\b </xsl:text><xsl:apply-templates/><xsl:text>}</xsl:text></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>{\b </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="product">
+ <xsl:choose>
+ <xsl:when test="@href">
+ <xsl:call-template name="hyperref">
+ <xsl:with-param name="href" select="@href"/>
+ <xsl:with-param name="inset"><xsl:text>{\b\cf6 </xsl:text><xsl:apply-templates/><xsl:text>}</xsl:text></xsl:with-param>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>{\b\cf6 </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <xsl:template match="term">
+ <xsl:text>{\i </xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="rfc">
+ <xsl:call-template name="hyperref">
+ <xsl:with-param name="href" select="concat('http://www.rfc-editor.org/rfc/rfc',@num,'.txt')"/>
+ <xsl:with-param name="inset" select="concat('{\b RFC',@num,'}')"/>
+ </xsl:call-template>
+ </xsl:template>
+
+ <xsl:template match="license">
+ <xsl:text>&#xA;{</xsl:text>
+ <xsl:text>&#xA;\par\pard\plain\sb360\sa120 \f1\fs16 Copyright (c) </xsl:text>
+ <xsl:value-of select="@years"/>
+ <xsl:text> {\uldb\cf0 Klever Group (http://www.klever.net/)}{\v %!ExecFile("http://www.klever.net/")}</xsl:text>
+ <xsl:text>&#xA;\par\qj\sb120\sa120</xsl:text>
+ <xsl:text>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</xsl:text>
+ <xsl:text>&#xA;\par The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</xsl:text>
+ <xsl:text>&#xA;\par \sa360 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</xsl:text>
+ <xsl:text>&#xA;}</xsl:text>
+ </xsl:template>
+ <xsl:template match="credits">
+ <xsl:text>&#xA;\par \sa0\sb120\ql \f1\fs16 Author: {\b\uldb\cf11 Michael Krelin ({\i hacker@klever.net})}{\v %!ExecFile("mailto:hacker@klever.net")}</xsl:text>
+ <xsl:text>&#xA;\par \sa0\sb0 Fan mail send to {\i\uldb gefilte@klever.net}{\v %!ExecFile("mailto:gefilte@klever.net")}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="ul">
+ <xsl:text>\pard</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>\pard</xsl:text>
+ </xsl:template>
+ <xsl:template match="li">
+ <!-- TODO: could be done better, but you never know with winhelp.. -->
+ <xsl:variable name="li" select=" count(ancestor::ul) "/>
+ <xsl:text>&#xA;\par \fi0\li</xsl:text><xsl:value-of
+ select="0"/><xsl:text> \bullet </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="topic/text()">
+ <!-- maybe only omit spaces? -->
+ </xsl:template>
+ <xsl:template match="ul/text()">
+ </xsl:template>
+
+ <xsl:template name="colortbl">
+ <xsl:text>{\colortbl;
+ \red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+ \red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;
+ \red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;
+ \red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
+ </xsl:text>
+ </xsl:template>
+ <xsl:template name="fonttbl">
+ <xsl:text>{\fonttbl</xsl:text>
+ <xsl:text>{\f0\froman Times New Roman;}</xsl:text>
+ <xsl:text>{\f1\fswiss Arial;}</xsl:text>
+ <xsl:text>{\f3\froman Symbol;}</xsl:text>
+ <xsl:text>}</xsl:text>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/shared-code/ms_icmp.h b/shared-code/ms_icmp.h
new file mode 100644
index 0000000..32d97f5
--- a/dev/null
+++ b/shared-code/ms_icmp.h
@@ -0,0 +1,77 @@
+/*------------------------------------------------------------------
+* Filename: MS_ICMP.H
+*
+* Description: Prototypes of Microsoft's ICMP.DLL functions for
+* access to Internet Control Message Protocol (their stacks do
+* not support the standard Berkeley Sockets raw socket API).
+* Use this to do "ping" or "traceroute," although beware that
+* Microsoft discourages its use.
+*/
+
+
+/* Note 2: For the most part, you can refer to RFC 791 for detials on
+* how to fill in values for the IP option information structure. */
+typedef struct ip_option_information {
+ u_char Ttl; /* Time To Live (used for traceroute) */
+ u_char Tos; /* Type Of Service (usually 0) */
+ u_char Flags; /* IP header flags (usually 0) */
+ u_char OptionsSize; /* Size of options data (usually 0, max 40) */
+ u_char FAR *OptionsData;/* Options data buffer */
+} IPINFO, *PIPINFO, FAR *LPIPINFO;
+
+/* Note 1: The Reply Buffer will have an array of ICMP_ECHO_REPLY
+* structures, followed by options and the data in ICMP echo reply
+* datagram received. You must have room for at least one ICMP
+* echo reply structure, plus 8 bytes for an ICMP header. */
+typedef struct icmp_echo_reply {
+ u_long Address; /* source address */
+ u_long Status; /* IP status value (see below) */
+ u_long RTTime; /* Round Trip Time in milliseconds */
+ u_short DataSize; /* reply data size */
+ u_short Reserved; /* */
+ void FAR *Data; /* reply data buffer */
+ typedef struct ip_option_information Options; /* reply options */
+} ICMPECHO, *PICMPECHO, FAR *LPICMPECHO;
+
+#define IP_STATUS_BASE 11000
+#define IP_SUCCESS 0
+#define IP_BUF_TOO_SMALL (IP_STATUS_BASE + 1)
+#define IP_DEST_NET_UNREACHABLE (IP_STATUS_BASE + 2)
+#define IP_DEST_HOST_UNREACHABLE (IP_STATUS_BASE + 3)
+#define IP_DEST_PROT_UNREACHABLE (IP_STATUS_BASE + 4)
+#define IP_DEST_PORT_UNREACHABLE (IP_STATUS_BASE + 5)
+#define IP_NO_RESOURCES (IP_STATUS_BASE + 6)
+#define IP_BAD_OPTION (IP_STATUS_BASE + 7)
+#define IP_HW_ERROR (IP_STATUS_BASE + 8)
+#define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9)
+#define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10)
+#define IP_BAD_REQ (IP_STATUS_BASE + 11)
+#define IP_BAD_ROUTE (IP_STATUS_BASE + 12)
+#define IP_TTL_EXPIRED_TRANSIT (IP_STATUS_BASE + 13)
+#define IP_TTL_EXPIRED_REASSEM (IP_STATUS_BASE + 14)
+#define IP_PARAM_PROBLEM (IP_STATUS_BASE + 15)
+#define IP_SOURCE_QUENCH (IP_STATUS_BASE + 16)
+#define IP_OPTION_TOO_BIG (IP_STATUS_BASE + 17)
+#define IP_BAD_DESTINATION (IP_STATUS_BASE + 18)
+#define IP_ADDR_DELETED (IP_STATUS_BASE + 19)
+#define IP_SPEC_MTU_CHANGE (IP_STATUS_BASE + 20)
+#define IP_MTU_CHANGE (IP_STATUS_BASE + 21)
+#define IP_UNLOAD (IP_STATUS_BASE + 22)
+#define IP_GENERAL_FAILURE (IP_STATUS_BASE + 50)
+#define MAX_IP_STATUS IP_GENERAL_FAILURE
+#define IP_PENDING (IP_STATUS_BASE + 255)
+
+
+HANDLE WINAPI PASCAL IcmpCreateFile(VOID); /* INVALID_HANDLE_VALUE on error */
+BOOL WINAPI PASCAL IcmpCloseHandle(HANDLE IcmpHandle); /* FALSE on error */
+DWORD WINAPI PASCAL IcmpSendEcho(
+ HANDLE IcmpHandle, /* handle returned from IcmpCreateFile() */
+ u_long DestAddress, /* destination IP address (in network order) */
+ LPVOID RequestData, /* pointer to buffer to send */
+ WORD RequestSize, /* length of data in buffer */
+ LPIPINFO RequestOptns, /* see Note 2 below */
+ LPVOID ReplyBuffer, /* see Note 1 below */
+ DWORD ReplySize, /* length of reply (must allow at least 1 reply) */
+ DWORD Timeout /* time in milliseconds to wait for reply */
+);
+