Hebrew Visual to Logical, Logical to Visual Source Code

This is Open Source code for a cpp file.

You may use it, change it, fix it and distribute it freely.
You are required however to comply with the following:
1) any software distributed based on a work derived from this code must include this original file and the derived code.
2) any site distributing such software must link to: http://www.evrit.co.il/code.htm from the download page.
3) if the code, or derived work is used for server side software a link to: http://www.evrit.co.il/code.htm must be placed on the site.

may the source be with you.
Comments:

Algorithm by Yaron Ilan, Coding by Michael Kertesz.
Ctrl-CC is based on this code. It had more than 250,000 installations in Israel. Most worked just fine.
If this doesn't work - don't blame us, even we have no idea how it did work in the past.

//////////////////////////////////////////
// This is Open Source code for a cpp file.
// You may use it, change it, fix it and distribute it freely.
// You are required however to comply with the following:
// 1) any software distributed based on a work derived from this code must include this original file and the derived code.
// 2) any site distributing such software must link to: http://www.evrit.co.il/code.htm from the download page.
// 3) if the code, or derived work is used for server side software a link to: http://www.evrit.co.il/code.htm must be placed on the site.
// may the source be with you.
///////////////////////////////////////////

#include "stdafx.h"
#include "Segment.h"
#include "Taskbar.h"
#include "DirectionDlg.h"
#include "InconsistDlg.h"

extern CTaskbarApp theApp;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

bool CheckCode (CString ToCheck, char *Buffer = NULL);
CSegment *BuildSegments (const char *InString, long MaxLen);
CSegment *MinSegments (CSegment *Cur);
void ComposeLine (char *Result, long MaxLen, CSegment *pCur);
void sleep (int seconds);
void l2v (char *Buffer, char *InLine);

int SmartGuess (char *Source);
int VCutLine (char *Dest, char *Source, int LineLen);
char *TrimLR (char *Dest);

void Reverse (char *ToReverse);
void AddChar (char c, char *Dest);
void AddChar (char *Dest, char c);

unsigned char BidiSwap[256];
unsigned char LetterType[] = {

 //   0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15

	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	//   0
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	//  16
	  3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5,	//  32
	  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 3, 3, 3, 3, 3,	//  48
	  3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	//  64
	  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,	//  80
	  3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	//  96
	  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3,	// 112
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	// 128
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	// 144
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	// 160
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	// 176
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	// 192
	  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	// 208
	  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	// 224
	  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; // 240

	/****************************************************
	 * LetterType
	 * 
	 * Returns group type
	 *      1=English
	 *      2=Hebrew
	 *      3=Bidi chars
	 *      4=Numbers
	 *      5=Aritmetics
	 *****************************************************/


void Convert (char *Dest, char *Source) {

	int ConvertType = dMode;

	// dual mode
	if (!dMode) {

		// if not in smart mode, or guess failed
		if ( (!bSmartMode) || !(ConvertType = SmartGuess (Source))) {

			// display message box asking the user what type
			// of conversion we are doing.

			HWND			CurWnd = GetForegroundWindow();
			CDirectionDlg	DirDlg;

			MessageBeep (MB_ICONQUESTION);

			int Result = DirDlg.DoModal();

			if (Result == -1) {
				Dest[0]=0;
				return;
			}
			
			ConvertType = Result;   // l2v or v2l

			SetForegroundWindow (CurWnd);
		}

		// if string short and without CR -- treat as l2v.
		if (ConvertType == 4)
			ConvertType = 2;
	}
	else {
		if (bSmartMode) {
			
			int dSG = SmartGuess (Source);
			
			// if string short and without CR, then don't care...
			if (dSG == 4)
				dSG = dMode;

			if ( (dSG) && (dSG != dMode) ) {

				// smart mode detected inconsistancy
				HWND			CurWnd = GetForegroundWindow();
				CInconsistDlg	inconsist;

				MessageBeep (MB_ICONQUESTION);

				int Result = inconsist.DoModal();

				switch (Result) {

				case 1:		// yes

					ConvertType = dSG;
					break;

				case 2:		// no
					ConvertType = dMode;
					break;

				case 3:		// allways
					ConvertType = dSG;
					dMode = 0;
					break;
				}
				
				SetForegroundWindow (CurWnd);
			}
		}
	}

	Dest[0]='\x0';

	switch (ConvertType) {
	
	case 1:		// v2l
		char *pCR, *pTrimmed, *Buffer;
		BOOL bLineStart, bContinue;
		
		bLineStart = TRUE;
		bContinue = TRUE;

		Buffer = new char[strlen (Source)+1000];
		Buffer[0]='\x0';

		while ( bContinue ) {
			
			if ( !(pCR = strrchr (Source, 13)) ) {
				pCR = Source-1;
				bContinue = FALSE;
			}

			if (!bClearWS) {
				strcat (Buffer, pCR+1);	//1
				strcat (Buffer, "\n\r");
			}
			else {
				// trim whitespaces
				pTrimmed = TrimLR(pCR+1);
				
				if (bClearPar) {

					if (pTrimmed[0]=='\x0') {
						// empty line
						strcat (Buffer, "\n\r");
						bLineStart = TRUE;
					}
					else {
						if (!bLineStart)
							strcat (Buffer, " ");

						strcat (Buffer, pTrimmed);
						bLineStart = FALSE;
					}
				}
				else {
					// no paragraph cleaning
					strcat (Buffer, pTrimmed);
					strcat (Buffer, "\n\r");
				}
			}

			if (bContinue) {
				*pCR='\x0';
				if ( (pCR != Source) && (*(pCR-1) == 10) )
					*(pCR-1)='\x0';
			}
		}

		l2v (Dest, Buffer);
		delete Buffer;
		
		break;
		
	case 2:		// l2v	
		int CurStart, SourceLen, NextLineLen;
		char *SBuffer, *DBuffer;

		SBuffer = new char[dVLineLen+10];
		DBuffer = new char[dVLineLen+10];

		CurStart = 0;
		SourceLen = strlen (Source);

		while (CurStart < SourceLen) {

			NextLineLen = VCutLine (SBuffer, Source+CurStart, dVLineLen);
			l2v (DBuffer, SBuffer);

			strcat (Dest, DBuffer);

			CurStart += NextLineLen + 1;

			if (CurStart < SourceLen)
				strcat (Dest, "\r\n");
		}

		delete DBuffer;
		delete SBuffer;
	}

	// add "unregistered" message if needed

	if (!strUserName.GetLength()) {
	
		if (uiRuns > UNREG_MESSAGE_RUNS)
			strcpy (Dest, ST_UNREG_MESSAGE_2);

		if (uiRuns > NO_UNREG_MESSAGE_RUNS)
			strcat (Dest, ST_UNREG_MESSAGE);
	}
}

char *TrimLR (char *Dest) {

	int len, i;
	char *RetStr;
	
	if ( (!Dest) || (!(len = strlen(Dest))))
		return (Dest);

	// right-trim

	i = len - 1;
	while ( (i) && ( (Dest[i]==32) || (Dest[i]==9) || (Dest[i]==10) ) )
		Dest[i--]=0;

	// left-trim

	RetStr=Dest;
	while ( (RetStr[0]==32) || (RetStr[0]==9) || (RetStr[0]==10) )
		RetStr++;
	
	return (RetStr);
}

int SmartGuess (char *Source) {

	char	Terminals[] = "σονκυ";
	char	*pCur = Source;
	int		Visual = 0;
	int		Logical = 0;

	// if the string is very short, and does not contain any
	// CRs, then we don't care what it is... just convert it!

	if ( ((int)strlen (Source) < dVLineLen) && (strchr (Source, 13) == NULL) )
		return (4);

	// the situation is more complicated, so check the position
	// of the 'terminal' letters in the string...

	while ( (pCur = strpbrk(pCur, Terminals)) ) {
		if ((unsigned char)*(pCur+1) > 208)
			Visual++;
	
		if ((unsigned char)*(pCur-1) > 208)
			Logical++;

		pCur++;
	}

	// clear winners:
	if ( (Visual > 0) && (Logical == 0) )
		return (1);

	if ( (Logical > 0) && (Visual == 0) )
		return (2);

	// big advantage:
	if ( (Visual > Logical*10) )
		return (1);

	if ( (Logical > Visual*10) )
		return (2);

	// don't know...
	return (0);
}

		
int VCutLine (char *Dest, char *Source, int LineLen) {

	int CurLen;
	int LastWS = 0;

	for (CurLen = 0; CurLen < LineLen; CurLen++) {

		if ( (Source[CurLen]==13) || (Source[CurLen]==0) ) {
			strncpy (Dest, Source, CurLen);
			Dest[CurLen]=0;
			return (CurLen+1);
		}

		if (Source[CurLen]==32)
			LastWS = CurLen;
	}

	if (LastWS) {
		strncpy (Dest, Source, LastWS);
		Dest[LastWS]=0;
		return (LastWS);
	}

	strncpy (Dest, Source, LineLen);
	Dest[LineLen]=0;
	return (LineLen-1);
}

void l2v (char *Buffer, char *InLine) {

	// return if input string is empty
	if ( (!InLine) || (!strlen (InLine))) {
		Buffer[0]='\x0';
		return;
	}

	CSegment *pLast, *pTemp;
	long MaxLen = strlen (InLine) + 2;
	char *Result = new char[MaxLen];

	// initialize swap array

	for (int i=0; i<256; i++)
		BidiSwap[i]=(unsigned char)i;

	BidiSwap[40]=41;	BidiSwap[41]=40;
	BidiSwap[60]=62;	BidiSwap[62]=60;
	BidiSwap[91]=93;	BidiSwap[93]=91;
	BidiSwap[123]=125;	BidiSwap[125]=123;

	pLast = BuildSegments (InLine, MaxLen);
	pLast = MinSegments (pLast);
	ComposeLine (Result, MaxLen, pLast);

	strcpy (Buffer, Result);
	delete Result;

	// free memory allocated by segments
	pLast = pLast->MoveFirst();

	while (pLast) {
		pTemp = pLast->pNext;
		delete pLast;
		pLast = pTemp;
	}
}

void ComposeLine (char *Result, long MaxLen, CSegment *pCur) {

	char	*TempStack = new char[MaxLen];
	char	*Temp = new char[MaxLen];

	Result[0]='\x0';
	TempStack[0]='\x0';


	while (pCur->pPrev) {

		switch (pCur->LType) {

		case 1:
			strcat (TempStack, pCur->GetString());
			break;

		case 2:
			strcpy (Temp, pCur->GetString());
			strcat (Temp, TempStack);
			strcat (Temp, Result);
			strcpy (Result, Temp);
			TempStack[0]='\x0';
			break;
		}

		pCur=pCur->pPrev;

	}

	strcat (TempStack, Result);
	strcpy (Result, TempStack);

	delete TempStack;
	delete Temp;
}

CSegment *BuildSegments (const char *InString, long MaxLen) {

	unsigned char	l;
	int				c=0;
	int				i;
	unsigned char	LType, LastType=0;
	char			*Temp;

	CSegment		*pFirst,
					*pCurrent;

	pCurrent = pFirst = new CSegment();

	pFirst->LType = 0;

	Temp = new char[MaxLen];
	Temp[0]='\x0';

	for (i=strlen (InString); i--; ) {

		l = BidiSwap[(unsigned char) InString[i]];

		if ( (LType = LetterType[l]) != LastType) {
			pCurrent->SetString (Temp);
			Temp[0]='\x0';

			pCurrent->pNext = new CSegment();
			pCurrent->pNext->pPrev = pCurrent;

			pCurrent = pCurrent->pNext;
			pCurrent->LType = LType;
		}

		switch (LType) {
		case 1:
			AddChar (l, Temp);
			break;
			
		case 4:
			AddChar (l, Temp);
			break;

		default:
			AddChar (Temp, l);
		}

		LastType = LType;

		// QQQ new addition: what does it do??

		if ( (pCurrent->LType == 5) && (strlen (Temp) != 1) )
			pCurrent->LType = 3;
	}

	// unload string to current segment

	pCurrent->SetString (Temp);

	// create a dummy next segment

	pCurrent->pNext = new CSegment();
	pCurrent->pNext->pPrev = pCurrent;
	pCurrent->pNext->LType = 0;

	delete Temp;
	return (pCurrent);
}

CSegment *MinSegments (CSegment *Cur) {

	unsigned char LastDir;

	CSegment *Prev, *Next, *pTemp, *LastDirPos;
	int Was, Will, Now;

	while (Cur->pPrev->pPrev) {
		Prev = Cur->pPrev;
		Next = Cur->pNext;

		Now = Cur->LType;
		Was = Prev->LType;
		Will = Next->LType;

		switch (Now) {
		case 1:
			if ( (Was==Will) && (Was < 3) && (Was != 0) ) {
				Prev->AddTail (Cur, Next);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}
			break;

		case 3:
			// When building objects a 33 is possible (done by BuildObjArr)
			// This attaches both into one object.
 
			if ( Now == Was ) {
				Prev->AddTail (Cur);
				Cur = Cur->Kill();
			}

			// attach 131 and situations into one object.

			if ( (Was == 1) && (Will == 1) ) {
				Reverse (Cur->GetString());
				Prev->AddHead (Next, Cur);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}

			// attach 232 and situations into one object.

			if ( (Was == 2) && (Will == 2) ) {
				Prev->AddTail (Cur, Next);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}

			break;

		case 5:
			// attach 454 and situations into one object !!!!

			if ( (Was == 4) && (Will == 4) ) {
				Prev->AddHead (Next, Cur);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}

			// attach 353 and situations into one object.

			if ( (Was == 3) && (Will == 3) ) {
				Prev->AddTail (Cur, Next);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}

			// attach 151 and situations into one object.

			if ( (Was == 1) && (Will == 1) ) {
				Prev->AddHead (Next, Cur);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}

			break;
		}
			
		Cur = Prev;

	}

	// Second stage is to attach 5 to numbers according to direction.

	Cur = Cur->MoveLast();
	Cur = Cur->pPrev;
	
	while (Cur->pPrev) {
		if ( (Cur->LType == 1) || (Cur->LType == 2) )
			LastDir = Cur->LType;

		if ( (Cur->LType == 4) && (Cur->pPrev->LType == 5) ) {
			if (LastDir == 1)
				Cur->pPrev->AddHead (Cur);
			else
				Cur->pPrev->AddTail (Cur);

			Cur->pPrev->LType = 4;
			Cur = Cur->Kill();
		}

		Cur = Cur->pPrev;
	}

	// Third stage is attach numbers to their directional string
	// This is the tough part...

	Cur = Cur->MoveLast();
	Cur = Cur->pPrev;

	LastDirPos = Cur;
	LastDir = 2;

	while (Cur->pPrev) {
		if ( (Cur->LType == 1) || (Cur->LType == 2) ) {
			LastDirPos = Cur;
			LastDir = Cur->LType;
		}

		if ( (Cur->LType == 4) && (Cur->pNext->pNext) ) {
			// make sure you don't loose LastDirPos
			LastDirPos = LastDirPos->pNext;

			for (pTemp = Cur->pNext; pTemp != LastDirPos; ) {
				if (LastDir == 2)
					Cur->AddTail (pTemp);
				else {
					if (pTemp->LType == 3)
						Reverse (pTemp->GetString());
					Cur->AddHead (pTemp);
				}

				// kill elements after added to current
				pTemp = pTemp->Kill();
			}

			Cur->LType = LastDir;
			LastDirPos = Cur;
		}


		if (Cur->LType == 4)
			Cur->LType = 3;

		Cur = Cur->pPrev;
	}

	// Remove type 5 - all can be considered as 3
	// (we do this while stepping forward in the list)

	while (Cur->pNext) {
		if (Cur->LType == 5)
			Cur->LType = 3;

		Cur = Cur->pNext;
	}

	// Minimize x,x situations resulting from 4 attachments and 5 cleanup

	while (Cur->pPrev->pPrev) {
		if (Cur->LType == Cur->pPrev->LType) {
			switch (Cur->LType) {
			case 1:
				Cur->pPrev->AddHead (Cur);
				break;

			case 2:
			case 3:
				Cur->pPrev->AddTail (Cur);
				break;
			}

			Cur = Cur->Kill();
		}

		Cur = Cur->pPrev;
	}

	// Minimize 3 in between situations

	Cur = Cur->MoveLast();
	Cur = Cur->pPrev;

	while (Cur->pPrev) {

		if (Cur->LType == 3) {
			if ( (Cur->pPrev->LType == 1) && (Cur->pNext->LType == 1) ) {
				Reverse (Cur->GetString());
				Cur->pPrev->AddHead (Cur->pNext, Cur);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}

			if ( (Cur->pPrev->LType == 2) && (Cur->pNext->LType == 2) ) {
				Cur->pPrev->AddTail (Cur, Cur->pNext);
				Cur = Cur->Kill();
				Cur = Cur->Kill();
			}
		}
		Cur = Cur->pPrev;
	}

	// attach 3

	Cur = Cur->MoveLast();
	Cur = Cur->pPrev;

	while (Cur->pPrev) {

		if (Cur->LType == 3)
			Cur->LType = 2;

		if ( (Cur->LType == 1) || (Cur->LType == 2) ) 
			LastDir = Cur->LType;

		if (Cur->pPrev->LType == 3) {
			Cur->pPrev->AddTail (Cur);
			Cur->pPrev->LType = Cur->LType;
			Cur = Cur->Kill();
		}

		Cur = Cur->pPrev;
	}

	Cur = Cur->MoveLast();
	Cur = Cur->pPrev;

	return (Cur);
}


// reverse whole string, then change all needed bidi
// characters (){} etc...

void Reverse (char *ToReverse) {

	strrev (ToReverse);

	for (int i=strlen (ToReverse); i--; )
		ToReverse[i]=BidiSwap[(unsigned char) ToReverse[i]];
}

	
void AddChar (char *Dest, char c) {
	
	int DestLen = strlen (Dest);

	Dest[DestLen]=c;
	Dest[DestLen+1]='\x0';
}

void AddChar (char c, char *Dest) {
	
	char	*TempStr = new char[strlen(Dest)+2];

	TempStr[0]=c;
	strcpy (TempStr+1, Dest);
	strcpy (Dest, TempStr);

	delete TempStr;
}

void sleep (int seconds)
{
	clock_t goal;
	
	goal = (clock_t)seconds * CLOCKS_PER_SEC + clock();
	while (goal > clock());
}

CString CheckCode (CString ToCheck) {

	 int			CSum,
					RealSum=0,
					i;

	CString			PureCode,
					EMail;

	if (ToCheck.GetLength() < 10)
		return ("");

	CSum = atoi (ToCheck.Right (5));

	PureCode = ToCheck.Mid (2, ToCheck.GetLength() - 7);

	for (i = 0; i < PureCode.GetLength(); i++) {
		RealSum += (int) PureCode[i] -5;
		EMail += (char) (PureCode[i]-5);
	}

	// checksum OK
	if ( (RealSum * 5 - 705) == CSum ) {
		EMail.MakeLower();
		return (EMail);
	}

	return ("");
}

void DisplayErrorMessage () {

	LPVOID lpMsgBuf;

	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL 
	);

	// Display the string.
	AfxMessageBox((LPSTR)lpMsgBuf);

	// Free the buffer.
	LocalFree( lpMsgBuf );
 
}

void _My_assert (int exp) {

	if (!exp)
		AfxMessageBox ("My_assert!");
}


Back to: evrit
Back to: Ctrl-CC