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