Ejemplo n.º 1
0
bool SGFParser::parse(const QString &fileName, const QString &/*filter*/)
{
	if (fileName.isNull() || fileName.isEmpty())
	{
		qWarning("No filename given!");
		return false;
	}
	
//	CHECK_PTR(boardHandler);
	
	QString toParse = loadFile(fileName);
	if (toParse.isNull() || toParse.isEmpty())
		return false;

	/*
	// Check for filter, if given
	if (!filter.isNull())
	{
		// XML
		if (filter == Board::tr("XML"))
		{
			// Init xmlparser if not yet done
			if (xmlParser == NULL)
				xmlParser = new XMLParser(boardHandler);
			xmlParser->parse(fileName);
			return true;
		}
	}
	*/
	if (!initGame(toParse, fileName))
		return corruptSgf();
	return doParse(toParse);
}
Ejemplo n.º 2
0
bool SGFParser::parse(const QString &fileName, const QString &filter, bool fastLoad)
{
	if (fileName.isNull() || fileName.isEmpty())
	{
		qWarning("No filename given!");
		return false;
	}
	
	CHECK_PTR(boardHandler);
	
	QString toParse = loadFile(fileName);
	if (toParse.isNull() || toParse.isEmpty())
		return false;
	// Convert old sgf/mgt format into new
//	if (toParse.find("White[") != -1)  // Do a quick test if this is necassary.
//		convertOldSgf(toParse);
	
	// Check for filter, if given
	if (!filter.isNull())
	{
		// XML
		if (filter == Board::tr("XML"))
		{
			// Init xmlparser if not yet done
			if (xmlParser == NULL)
				xmlParser = new XMLParser(boardHandler);
			xmlParser->parse(fileName);
			return true;
		}
	}
	
	if (!initGame(toParse, fileName))
		return corruptSgf();
	return doParse(toParse, fastLoad);
}
Ejemplo n.º 3
0
// Return false: corrupt sgf, true: sgf okay. result = 0 when property not found
bool SGFParser::parseProperty(const QString &toParse, const QString &prop, QString &result)
{
	int pos, strLength=toParse.length();
	result = "";
	
	pos = toParse.indexOf(prop+"[");
	if (pos == -1)
		return true;
	
	pos += 2;
	if (toParse[pos] != '[')
		return  corruptSgf(pos);
	while (toParse[++pos] != ']' && pos < strLength)
		result.append(toParse[pos]);
	if (pos > strLength)
		return  corruptSgf(pos);
	
	return true;
}
Ejemplo n.º 4
0
bool SGFParser::doParse(const QString &toParseStr)
{
	if (toParseStr.isNull() || toParseStr.isEmpty())
	{
		qWarning("Failed loading from file. Is it empty?");
		return false;
	}
	QString tmp;

	if(!loadedfromfile)
	{
		/* This bit of ugliness is because sgfs are used to duplicate boards as well
		 * as load from file FIXME */
		parseProperty(toParseStr, "CA", tmp);		//codec
		if (!tmp.isEmpty())
			readCodec = QTextCodec::codecForName(tmp.toLatin1().constData());
	}
	
	const MyString *toParse = NULL;

//////TODO	if (static_cast<Codec>(setting->readIntEntry("CODEC")) == codecNone)
/////////		toParse = new MySimpleString(toParseStr);
///////	else
		toParse = new MyString(toParseStr);

	Q_CHECK_PTR(toParse);
	
	int 	pos = 0,
		posVarBegin = 0,
		posVarEnd = 0,
		posNode = 0,
		moves = 0,
		i, x=-1, y=-1;

	int 	a_offset = QChar::fromLatin1('a').unicode() - 1 ;

	unsigned int pointer = 0,
		strLength = toParse->length();
	bool black = true,
		setup = false,
        old_label = false;
	isRoot = true;
	bool remember_root;
	QString unknownProperty;
	State state;
	MarkType markType;
	QString moveStr, commentStr;
	Position *position;
	MoveNum *moveNum;
	QStack<Move*> stack;
	QStack<MoveNum*> movesStack;
	/* FIXME toRemove, et., al., appears unused Remove it */
	QStack<Position*> toRemove;
/*
////TODO	stack.setAutoDelete(false);
	movesStack.setAutoDelete(true);
	toRemove.setAutoDelete(true);
*/
	// Initialises the tree with board size
	parseProperty(toParseStr, "SZ", tmp);
//	Tree *tree = new Tree(tmp.isEmpty() ? 19 : tmp.toInt()) ;// boardHandler->getTree();
	
	state = stateVarBegin;
	
	bool cancel = false;
    //FIXME abort does nothing!!
	
	// qDebug("File length = %d", strLength);
	
    tree->setLoadingSGF(true);
	
	QString sss="";
    do {
		posVarBegin = toParse->find('(', pointer);
		posVarEnd = toParse->find(')', pointer);
		posNode = toParse->find(';', pointer);
		
		pos = minPos(posVarBegin, posVarEnd, posNode);

		// Switch states

		// Node -> VarEnd
		if (state == stateNode && pos == posVarEnd)
			state = stateVarEnd;
		
		// Node -> VarBegin
		if (state == stateNode && pos == posVarBegin)
			state = stateVarBegin;
		
		// VarBegin -> Node
		else if (state == stateVarBegin && pos == posNode)
			state = stateNode;
		
		// VarEnd -> VarBegin
		else if (state == stateVarEnd && pos == posVarBegin)
			state = stateVarBegin;
		
		// qDebug("State after switch = %d", state);
		
		// Do the work
		switch (state)
		{
		case stateVarBegin:
			if (pos != posVarBegin)
			{
				delete toParse;
				return corruptSgf(pos);
			}
			
			// qDebug("Var BEGIN at %d, moves = %d", pos, moves);
			
			stack.push(tree->getCurrent());
			moveNum = new MoveNum;
			moveNum->n = moves;
			movesStack.push(moveNum);
			pointer = pos + 1;
			break;
			
		case stateVarEnd:
			if (pos != posVarEnd)
			{
				delete toParse;
				return corruptSgf(pos);
			}
			
			// qDebug("VAR END");
			
			if (!movesStack.isEmpty() && !stack.isEmpty())
			{
				Move *m = stack.pop();
				Q_CHECK_PTR(m);
				x = movesStack.pop()->n;
				
				// qDebug("Var END at %d, moves = %d, moves from stack = %d", pos, moves, x);
				
				for (i=moves; i > x; i--)
				{
					position = toRemove.pop();
					if (position == NULL)
						continue;
///////////////////			boardHandler->getStoneHandler()->removeStone(position->x, position->y);
//					tree->removeStone(position->x, position->y);
					// qDebug("Removing %d %d from stoneHandler.", position->x, position->y);
				}
				
				moves = x;
 							
				
				tree->setCurrent(m);
			}
			pointer = pos + 1;
			break;
			
		case stateNode:
			if (pos != posNode)
			{
				delete toParse;
				return corruptSgf(pos);
			}
			
			// qDebug("Node at %d", pos);
			commentStr = QString();
			setup = false;
			markType = markNone;
			
			// Create empty node
			remember_root = isRoot;
			if (!isRoot)
			{
/////////////////////		boardHandler->createMoveSGF();
//				qDebug("############### Before creating move ####################");
//				qDebug(toParse->Str.toLatin1().constData());
				//tree->createMoveSGF();
				/* This does happen, why??? FIXME */
//				qDebug("###############                      ####################");
//				qDebug(toParse->Str.toLatin1().constData());
//				qDebug("############### After creating move ####################");
				unknownProperty = QString();
#ifdef FIXME	//why is this a warning? this happens on loading a file with time info
				if (tree->getCurrent()->getTimeinfo())
				qWarning("*** Timeinfo set !!!!");
#endif //FIXME
				//tree->getCurrent()->setTimeinfo(false);
			}
			else
				isRoot = false;
						
			Property prop;
			pos ++;

			do {
				uint tmppos=0;
				pos = toParse->next_nonspace (pos);
				
                if ((tmppos = toParse->isProperty("B",pos)))
				{
					prop = moveBlack;
					pos = tmppos;
					black = true;
				}
                else if ((tmppos = toParse->isProperty("W",pos)))
				{
					prop = moveWhite;
					pos = tmppos;
					black = false;
				}
                else if ((tmppos = toParse->isProperty("N",pos)))
				{
					prop = nodeName;
					pos = tmppos;
				}
                else if ((tmppos = toParse->isProperty("AB",pos)))
				{
					prop = editBlack;
					pos = tmppos;
					setup = true;
					black = true;
				}
                else if ((tmppos = toParse->isProperty("AW",pos)))
				{
					prop = editWhite;
					pos = tmppos;
					setup = true;
					black = false;
				}
                else if ((tmppos = toParse->isProperty("AE",pos)))
				{
					prop = editErase;
					pos = tmppos;
					setup = true;
				}
                else if ((tmppos = toParse->isProperty("TR",pos)))
				{
					prop = editMark;
					markType = markTriangle;
					pos = tmppos;
				}
                else if ((tmppos = toParse->isProperty("CR",pos)))
				{
					prop = editMark;
					markType = markCircle;
					pos = tmppos;
				}
                else if ((tmppos = toParse->isProperty("SQ",pos)))
				{
					prop = editMark;
					markType = markSquare;
					pos = tmppos;
				}
                else if ((tmppos = toParse->isProperty("MA",pos)))
				{
					prop = editMark;
					markType = markCross;
					pos = tmppos;
				}
				// old definition
                else if ((tmppos = toParse->isProperty("M",pos)))
				{
					prop = editMark;
					markType = markCross;
					pos = tmppos;
				}
                else if ((tmppos = toParse->isProperty("LB",pos)))
				{
					prop = editMark;
					markType = markText;
					pos = tmppos;
					old_label = false;
				}
				// Added old L property. This is not SGF4, but many files contain this tag.
                else if ((tmppos = toParse->isProperty("L",pos)))
				{
					prop = editMark;
					markType = markText;
					pos = tmppos;
					old_label = true;
				}
                else if ((tmppos = toParse->isProperty("C",pos)))
				{
					prop = comment;
					pos = tmppos;
				}
                else if ((tmppos = toParse->isProperty("TB",pos)))
				{
					prop = editMark;
					markType = markTerrBlack;
					pos = tmppos;
					black = true;
				}
                else if ((tmppos = toParse->isProperty("TW",pos)))
				{
					prop = editMark;
					markType = markTerrWhite;
					pos = tmppos;
					black = false;
				}
                else if ((tmppos = toParse->isProperty("BL",pos)))
				{
					prop = timeLeft;
					pos = tmppos;
					black = true;
				}
                else if ((tmppos = toParse->isProperty("WL",pos)))
				{
					prop = timeLeft;
					pos = tmppos;
					black = false;
				}
                else if ((tmppos = toParse->isProperty("OB",pos)))
				{
					prop = openMoves;
					pos = tmppos;
					black = true;
				}
                else if ((tmppos = toParse->isProperty("OW",pos)))
				{
					prop = openMoves;
					pos = tmppos;
					black = false;
				}
                else if ((tmppos = toParse->isProperty("PL",pos)))
				{
					prop = nextMove;
					pos = tmppos;
				}
                    else if ((tmppos = toParse->isProperty("RG",pos)))
				{
					prop = unknownProp;
					pos = tmppos;
          				setup = true;
				}
				// Empty node
				else if (toParse->at(pos) == ';' || toParse->at(pos) == '(' || toParse->at(pos) == ')')
				{
					qDebug("Found empty node at %d", pos);
					while (toParse->at(pos).isSpace())
						pos++;
					continue;
				}
				else
				{
					// handle like comment
					prop = unknownProp;
					pos = toParse->next_nonspace (pos);
					//qDebug("SGF: next nonspace (1st):" + QString(toParse->at(pos)) + QString(toParse->at(pos+1)) + QString(toParse->at(pos+2)));
				}
				
				//qDebug("Start do loop : FOUND PROP %d, pos at %d now", prop, pos);
				//qDebug(toParse->getStr());			//causes crash
				// Next is one or more '[xx]'.
				// Only one in a move property, several in a setup propery
				do {
					if (toParse->at(pos) != '[' && prop != unknownProp)
					{
						delete toParse;
						return corruptSgf(pos);
					}
					
					// Empty type
					if (toParse->at(pos+1) == ']')
					{
						// CGoban stores pass as 'B[]' or 'W[]'
						if (prop == moveBlack || prop == moveWhite)
						{
							tree->doPass(true);
							
							// Remember this move for later, to remove from the matrix.
							position = new Position;
							position->x = x;
							position->y = y;
							toRemove.push(position);
							moves ++;
						}
						
						pos += 2;
						continue;
					}
					
					switch (prop)
					{
					case moveBlack:
					case moveWhite:
						// rare case: root contains move or placed stone:
						if (remember_root)
						{
							qDebug("root contains stone -> node created");
							/* Something is screwy here, inconsistencies
							 * in the way SGF's are treated. Like the below:
							 * the whole point of "remember_root", FIXME*/
							tree->addEmptyMove();
							isRoot = false;
							unknownProperty = QString();
#ifdef FIXME	//why is this a warning?
							if (tree->getCurrent()->getTimeinfo())
								qWarning("*** Timeinfo set (2)!!!!");
#endif //FIXME
							//tree->getCurrent()->setTimeinfo(false);
						}
					case editBlack:
					case editWhite:
					case editErase:
					{
						x = toParse->at(pos+1).unicode() - a_offset ;// - 'a';// + 1;
						y = toParse->at(pos+2).unicode() - a_offset ; //- 'a' + 1;

						int x1, y1;
						bool compressed_list;

						// check for compressed lists
						if (toParse->at(pos+3) == ':')
						{
							x1 = toParse->at(pos+4).unicode() -a_offset;// - 'a' + 1;
							y1 = toParse->at(pos+5).unicode() -a_offset;// - 'a' + 1;
							compressed_list = true;
						}
						else
						{
							x1 = x;
							y1 = y;
							compressed_list = false;
						}
/*								
*						TODO Do we nned this when the tree is created from file ?
*						boardHandler->setModeSGF(setup || compressed_list ? modeEdit : modeNormal);
*/
						
						int i, j;
						for (i = x; i <= x1; i++)
							for (j = y; j <= y1; j++)
                            {
                                if (prop == editErase)
								{
									tree->addStoneToCurrentMove(stoneErase, i, j);
								}
								else
								{
									if(setup)
									{
                                        if ((!remember_root) && (stack.top() == tree->getCurrent()))
                                            tree->addEmptyMove(); //if this is first in branch we need to add an empty move

										tree->addStoneToCurrentMove(black ? stoneBlack : stoneWhite, i, j);
									}
									else
                                    {
                                        Move *result = tree->getCurrent()->makeMove(black ? stoneBlack : stoneWhite, i, j);
                                        if (result)
                                            tree->setCurrent(result);
                                    }
								}
								// tree->getCurrent()->getMatrix()->debug();
								//qDebug("ADDING MOVE %s %d/%d", black?"B":"W", x, y);
								
								// Remember this move for later, to remove from the matrix.
								position = new Position;
								position->x = i;
								position->y = j;
								toRemove.push(position);
								moves ++;
							}
												
						if (compressed_list)
							// Advance pos by 7
							pos += 7;
						else
							// Advance pos by 4
							pos += 4;
						break;
					}
						
					case nodeName:
					{
						commentStr = QString();
						bool skip = false;
						
						while (toParse->at(++pos) != ']')
						{
							if (static_cast<unsigned int>(pos) > strLength-1)
							{
								qDebug("SGF: Nodename string ended immediately");
								delete toParse;
								return corruptSgf(pos, "SGF: Nodename string ended immediately");
							}

							// white spaces
							if (toParse->at(pos) == '\\')
							{
								while (toParse->at(pos+1).isSpace() &&
									static_cast<unsigned int>(pos) < strLength-2)
									pos++;
								if (toParse->at(pos).isSpace())
									pos++;

								// case: "../<cr><lf>]"
								if (toParse->at(pos) == ']')
								{
									pos--;
									skip = true;
								}
							}

							// escaped chars: '\', ']', ':'
							if (!(toParse->at(pos) == '\\' &&
								(toParse->at(pos+1) == ']' ||
								 toParse->at(pos+1) == '\\' ||
								 toParse->at(pos+1) == ':')) &&
								 !skip &&
								 // no formatting
								!(toParse->at(pos) == '\n') &&
								!(toParse->at(pos) == '\r'))
								commentStr.append(toParse->at(pos));
						}
						
					 	//qDebug("Node name read: %s", commentStr.toLatin1().constData());
						if (!commentStr.isEmpty())
							// add comment; skip 'C[]'
							tree->getCurrent()->setNodeName(commentStr);
						pos++;
						break;
					}

					case comment:
					{
						commentStr = QString();
						bool skip = false;
						
						while (toParse->at(++pos) != ']' ||
							(toParse->at(pos-1) == '\\' && toParse->at(pos) == ']'))
						{
							if (static_cast<unsigned int>(pos) > strLength-1)
							{
								qDebug("SGF: Comment string ended immediately");
								delete toParse;
								return corruptSgf(pos, "SGF: Comment string ended immediately");
							}

							// white spaces
							if (toParse->at(pos) == '\\')
							{
								while (toParse->at(pos+1).isSpace() &&
									static_cast<unsigned int>(pos) < strLength-2)
									pos++;
								if (toParse->at(pos).isSpace())
									pos++;

								// case: "../<cr><lf>]"
								if (toParse->at(pos) == ']')
								{
									pos--;
									skip = true;
								}
							}

							// escaped chars: '\', ']', ':'
							if (!(toParse->at(pos) == '\\' &&
								(toParse->at(pos+1) == ']' ||
								 toParse->at(pos+1) == '\\' ||
								 toParse->at(pos+1) == ':')) &&
								 !skip)
								commentStr.append(toParse->at(pos));
						}

						//qDebug("Comment read: %s", commentStr.toLatin1().constData());
						if (!commentStr.isEmpty())
						{
							// add comment; skip 'C[]'
							if(readCodec)
								tree->getCurrent()->setComment(readCodec->toUnicode(commentStr.toLatin1().constData()));
							else
								tree->getCurrent()->setComment(commentStr.toLatin1().constData());
						}
						pos ++;
						break;
					}

					case unknownProp:
					{
						// skip if property is known anyway
						bool skip = false;

						// save correct property name (or p.n. + '[')
						commentStr = QString(toParse->at(pos));
						commentStr += toParse->at(tmppos = toParse->next_nonspace (pos + 1));
						pos = tmppos;

						// check if it's really necessary to hold properties
						// maybe they are handled at another position
						if (commentStr == "WR" ||
							commentStr == "BR" ||
							commentStr == "PW" ||
							commentStr == "PB" ||
							commentStr == "SZ" ||
							commentStr == "KM" ||
							commentStr == "HA" ||
							commentStr == "RE" ||
							commentStr == "DT" ||
							commentStr == "PC" ||
							commentStr == "CP" ||
							commentStr == "GN" ||
							commentStr == "OT" ||
							commentStr == "TM" ||
							// now: general options
							commentStr == "GM" ||
							commentStr == "ST" ||
							commentStr == "AP" ||
							commentStr == "FF")
						{
							skip = true;
						}
						sss= toParse->at(pos);
						while (toParse->at(++pos) != ']' ||
							(toParse->at(pos-1) == '\\' && toParse->at(pos) == ']'))
						{
							if (static_cast<unsigned int>(pos) > strLength-1)
							{
								qDebug("SGF: Unknown property ended immediately");
								delete toParse;
								return corruptSgf(pos, "SGF: Unknown property ended immediately");
							}
              						sss= toParse->at(pos);
							if (!skip)
								commentStr.append(toParse->at(pos));
						}

						if (!skip)
							commentStr.append("]");

						// qDebug("Comment read: %s", commentStr.latin1());
						if ((!commentStr.isEmpty()) && (!skip))
						{
							// cumulate unknown properties; skip empty property 'XZ[]'
							unknownProperty += commentStr;
							tree->getCurrent()->setUnknownProperty(unknownProperty);
						}
						pos ++;
            					sss= toParse->at(pos);
						break;
					}

					case editMark:
						// set moveStr for increment labels of old 'L[]' property
						moveStr = "A";
						while (toParse->at(pos) == '[' &&
							static_cast<unsigned int>(pos) < strLength)
						{
							x = toParse->at(pos+1).unicode() -a_offset;// - 'a' + 1;
							y = toParse->at(pos+2).unicode() -a_offset;// - 'a' + 1;
							// qDebug("MARK: %d at %d/%d", markType, x, y);
							pos += 3;
							
							// 'LB' property? Then we need to get the text
							if (markType == markText && !old_label)
							{
								if (toParse->at(pos) != ':')
								{
									delete toParse;
									return corruptSgf(pos);
								}
								moveStr = "";
								while (toParse->at(++pos) != ']' &&
									static_cast<unsigned int>(pos) < strLength)
									moveStr.append(toParse->at(pos));
								// qDebug("LB TEXT = %s", moveStr.latin1());
								// It might me a number mark?
								bool check = false;
								moveStr.toInt(&check);  // Try to convert to Integer
								// treat integers as characters...
								check = false;
								
								if (check)
									tree->getCurrent()->getMatrix()->
									insertMark(x, y, markNumber);  // Worked, its a number
								else
									tree->getCurrent()->getMatrix()->
									insertMark(x, y, markType);    // Nope, its a letter
								tree->getCurrent()->getMatrix()->
										setMarkText(x, y, moveStr);
							
								/*else	//fastload
								{
									if (check)  // Number
										tree->getCurrent()->insertFastLoadMark(x, y, markNumber);
									else        // Text
										tree->getCurrent()->insertFastLoadMark(x, y, markType, moveStr);
								}*/
							}
							else
							{
								int x1, y1;
								bool compressed_list;

								// check for compressed lists
								if (toParse->at(pos) == ':')
								{
									x1 = toParse->at(pos+1).unicode() -a_offset;// - 'a' + 1;
									y1 = toParse->at(pos+2).unicode() -a_offset;// - 'a' + 1;
									compressed_list = true;
								}
								else
								{
									x1 = x;
									y1 = y;
									compressed_list = false;
								}
								
								int i, j;
								for (i = x; i <= x1; i++)
									for (j = y; j <= y1; j++)
									{
										tree->getCurrent()->getMatrix()->insertMark(i, j, markType);
										//else	//fastload
										//	tree->getCurrent()->insertFastLoadMark(i, j, markType);

										// auto increment for old property 'L'
										if (old_label)
										{
											tree->getCurrent()->getMatrix()->
												setMarkText(x, y, moveStr);
											QChar c1 = moveStr[0];
											if (c1 == 'Z')
												moveStr = QString("a");
											else
												moveStr = c1.unicode() + 1;
										}
									}

//								new_node = false;

								if (compressed_list)
									// Advance pos by 3
									pos += 3;

								if((markType == markTerrWhite || markType == markTerrBlack) && !tree->getCurrent()->isTerritoryMarked())
									tree->getCurrent()->setTerritoryMarked();
							}

							//old_label = false;
							pos ++;
							while (toParse->at(pos).isSpace()) pos++;
						}
						break;

					case openMoves:
					{
						QString tmp_mv;
						while (toParse->at(++pos) != ']')
							tmp_mv += toParse->at(pos);
						tree->getCurrent()->setOpenMoves(tmp_mv.toInt());
						pos++;

						if (!tree->getCurrent()->getTimeinfo())
						{
							tree->getCurrent()->setTimeinfo(true);
							tree->getCurrent()->setTimeLeft(0);
						}
						break;
					}

					case timeLeft:
					{
						QString tmp_mv;
						while (toParse->at(++pos) != ']')
							tmp_mv += toParse->at(pos);
						tree->getCurrent()->setTimeLeft(tmp_mv.toFloat());
						pos++;

						if (!tree->getCurrent()->getTimeinfo())
						{
							tree->getCurrent()->setTimeinfo(true);
							tree->getCurrent()->setOpenMoves(0);
						}
						break;
					}

					case nextMove:
						if (toParse->at(++pos) == 'W')
							tree->getCurrent()->setPLinfo(stoneWhite);
						else if (toParse->at(pos) == 'B')
							tree->getCurrent()->setPLinfo(stoneBlack);

						pos += 2;
						break;

					default:
						break;
				}
		
				while (toParse->at(pos).isSpace())
			    		pos++;
        	
				sss= toParse->at(pos);

			} while (setup && toParse->at(pos) == '[');
			
//			tree->getCurrent()->getMatrix()->debug();
//			qDebug("end do loop");
//			qDebug(toParse->getStr());
			
			while (toParse->at(pos).isSpace())
				pos++;

		} while (toParse->at(pos) != ';' && toParse->at(pos) != '(' && toParse->at(pos) != ')' &&    static_cast<unsigned int>(pos) < strLength);
		
		// Advance pointer
		pointer = pos;
	
		break;
	
	default:
		delete toParse;
		return corruptSgf(pointer);
	}
	
	} while (pointer < strLength && pos >= 0);

	tree->setLoadingSGF(false);
	
	delete toParse;
	return !cancel;
}
Ejemplo n.º 5
0
bool SGFParser::doParse(const QString &toParseStr, bool fastLoad)
{
	if (toParseStr.isNull() || toParseStr.isEmpty())
	{
		qWarning("Failed loading from file. Is it empty?");
		return false;
	}
	
	const MyString *toParse = NULL;
	if (static_cast<Codec>(setting->readIntEntry("CODEC")) == codecNone)
		toParse = new MySimpleString(toParseStr);
	else
		toParse = new MyString(toParseStr);
	CHECK_PTR(toParse);
	
	int pos = 0,
		posVarBegin = 0,
		posVarEnd = 0,
		posNode = 0,
		moves = 0,
		i, x=-1, y=-1;
	unsigned int pointer = 0,
		strLength = toParse->length();
	bool black = true,
		setup = false,
		old_label = false,
		new_node = false;
	isRoot = true;
	bool remember_root;
	QString unknownProperty;
	State state;
	MarkType markType;
	QString moveStr, commentStr;
	Position *position;
	MoveNum *moveNum;
	QPtrStack<Move> stack;
	QPtrStack<MoveNum> movesStack;
	QPtrStack<Position> toRemove;
	stack.setAutoDelete(FALSE);
	movesStack.setAutoDelete(TRUE);
	toRemove.setAutoDelete(TRUE);
	Tree *tree = boardHandler->getTree();
	
	state = stateVarBegin;
	
	bool cancel = false;
	int progressCounter = 0;
	QProgressDialog progress(Board::tr("Reading sgf file..."), Board::tr("Abort"), strLength,
		boardHandler->board, "progress", true);
	
	// qDebug("File length = %d", strLength);
	
	progress.setProgress(0);
	QString sss="";
	do {
		if (!(++progressCounter%10))
		{
			progress.setProgress(pointer);
			if (progress.wasCancelled())
			{
				cancel = true;
				break;
			}
		}
		
		// qDebug("POINTER = %d: %c", pointer, toParse->Str[pointer]);
		
		posVarBegin = toParse->find('(', pointer);
		posVarEnd = toParse->find(')', pointer);
		posNode = toParse->find(';', pointer);
		
		pos = minPos(posVarBegin, posVarEnd, posNode);
		// qDebug("VarBegin %d, VarEnd %d, Move %d, MINPOS %d", posVarBegin, posVarEnd, posNode, pos);

		// qDebug("State before switch = %d", state);

		// Switch states

		// Node -> VarEnd
		if (state == stateNode && pos == posVarEnd)
			state = stateVarEnd;
		
		// Node -> VarBegin
		if (state == stateNode && pos == posVarBegin)
			state = stateVarBegin;
		
		// VarBegin -> Node
		else if (state == stateVarBegin && pos == posNode)
			state = stateNode;
		
		// VarEnd -> VarBegin
		else if (state == stateVarEnd && pos == posVarBegin)
			state = stateVarBegin;
		
		// qDebug("State after switch = %d", state);
		
		// Do the work
		switch (state)
		{
		case stateVarBegin:
			if (pos != posVarBegin)
			{
				delete toParse;
				return corruptSgf(pos);
			}
			
			// qDebug("Var BEGIN at %d, moves = %d", pos, moves);
			
			stack.push(tree->getCurrent());
			moveNum = new MoveNum;
			moveNum->n = moves;
			movesStack.push(moveNum);
			pointer = pos + 1;
			break;
			
		case stateVarEnd:
			if (pos != posVarEnd)
			{
				delete toParse;
				return corruptSgf(pos);
			}
			
			// qDebug("VAR END");
			
			if (!movesStack.isEmpty() && !stack.isEmpty())
			{
				Move *m = stack.pop();
				CHECK_PTR(m);
				x = movesStack.pop()->n;
				
				// qDebug("Var END at %d, moves = %d, moves from stack = %d", pos, moves, x);
				
				for (i=moves; i > x; i--)
				{
					position = toRemove.pop();
					if (position == NULL)
						continue;
					boardHandler->getStoneHandler()->removeStone(position->x, position->y);
					// qDebug("Removing %d %d from stoneHandler.", position->x, position->y);
				}
				
				moves = x;
				
				if (!fastLoad)
					boardHandler->getStoneHandler()->updateAll(m->getMatrix(), false);
				
				tree->setCurrent(m);
			}
			pointer = pos + 1;
			break;
			
		case stateNode:
			if (pos != posNode)
			{
				delete toParse;
				return corruptSgf(pos);
			}
			
			// qDebug("Node at %d", pos);
			commentStr = QString();
			setup = false;
			markType = markNone;
			
			// Create empty node
			remember_root = isRoot;
			if (!isRoot)
			{
				boardHandler->createMoveSGF();
				unknownProperty = QString();
if (tree->getCurrent()->getTimeinfo())
	qWarning("*** Timeinfo set !!!!");
				//tree->getCurrent()->setTimeinfo(false);
			}
			else
				isRoot = false;
			
			new_node = true;
			
			Property prop;
			pos ++;

			do {
				uint tmppos=0;
				pos = toParse->next_nonspace (pos);
				
				// qDebug("READING PROPERTY AT %d: %c", pos, toParse->at(pos));
				
				// if (toParse->find("B[", pos) == pos)
				if (toParse->at(pos) == 'B' && toParse->at(tmppos = toParse->next_nonspace (pos + 1)) == '[')
				{
					prop = moveBlack;
					pos = tmppos;
					black = true;
				}
				// else if (toParse->find("W[", pos) == pos)
				else if (toParse->at(pos) == 'W' && toParse->at(tmppos = toParse->next_nonspace (pos + 1)) == '[')
				{
					prop = moveWhite;
					pos = tmppos;
					black = false;
				}
				else if (toParse->at(pos) == 'N' && toParse->at(tmppos = toParse->next_nonspace (pos + 1)) == '[')
				{
					prop = nodeName;
					pos = tmppos;
				}
				else if (toParse->find("AB", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editBlack;
					pos = tmppos;
					setup = true;
					black = true;
				}
				else if (toParse->find("AW", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editWhite;
					pos = tmppos;
					setup = true;
					black = false;
				}
				else if (toParse->find("AE", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editErase;
					pos = tmppos;
					setup = true;
				}
				else if (toParse->find("TR", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markTriangle;
					pos = tmppos;
				}
				else if (toParse->find("CR", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markCircle;
					pos = tmppos;
				}
				else if (toParse->find("SQ", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markSquare;
					pos = tmppos;
				}
				else if (toParse->find("MA", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markCross;
					pos = tmppos;
				}
				// old definition
				else if (toParse->find("M", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 1)) == '[')
				{
					prop = editMark;
					markType = markCross;
					pos = tmppos;
				}
				else if (toParse->find("LB", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markText;
					pos = tmppos;
					old_label = false;
				}
				// Added old L property. This is not SGF4, but many files contain this tag.
				else if (toParse->at(pos) == 'L' && toParse->at(tmppos = toParse->next_nonspace (pos + 1)) == '[')
				{
					prop = editMark;
					markType = markText;
					pos = tmppos;
					old_label = true;
				}
				else if (toParse->at(pos) == 'C' && toParse->at(tmppos = toParse->next_nonspace (pos + 1)) == '[')
				{
					prop = comment;
					pos = tmppos;
				}
				else if (toParse->find("TB", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markTerrBlack;
					pos = tmppos;
					black = true;
				}
				else if (toParse->find("TW", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = editMark;
					markType = markTerrWhite;
					pos = tmppos;
					black = false;
				}
				else if (toParse->find("BL", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = timeLeft;
					pos = tmppos;
					black = true;
				}
				else if (toParse->find("WL", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = timeLeft;
					pos = tmppos;
					black = false;
				}
				else if (toParse->find("OB", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = openMoves;
					pos = tmppos;
					black = true;
				}
				else if (toParse->find("OW", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = openMoves;
					pos = tmppos;
					black = false;
				}
				else if (toParse->find("PL", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = nextMove;
					pos = tmppos;
				}
        else if (toParse->find("RG", pos) == pos && toParse->at(tmppos = toParse->next_nonspace (pos + 2)) == '[')
				{
					prop = unknownProp;
					pos = tmppos;
          setup = true;
				}
				// Empty node
				else if (toParse->at(pos) == ';' || toParse->at(pos) == '(' || toParse->at(pos) == ')')
				{
					qDebug("Found empty node at %d", pos);
					while (toParse->at(pos).isSpace())
						pos++;
					continue;
				}
				else
				{
					// handle like comment
					prop = unknownProp;
					pos = toParse->next_nonspace (pos);
//qDebug("SGF: next nonspace (1st):" + QString(toParse->at(pos)) + QString(toParse->at(pos+1)) + QString(toParse->at(pos+2)));
				}
				
				// qDebug("FOUND PROP %d, pos at %d now", prop, pos);
				
				// Next is one or more '[xx]'.
				// Only one in a move property, several in a setup propery
				do {
					if (toParse->at(pos) != '[' && prop != unknownProp)
					{
						delete toParse;
						return corruptSgf(pos);
					}
					
					// Empty type
					if (toParse->at(pos+1) == ']')
					{
						// CGoban stores pass as 'B[]' or 'W[]'
						if (prop == moveBlack || prop == moveWhite)
						{
							boardHandler->doPass(true);
							
							// Remember this move for later, to remove from the matrix.
							position = new Position;
							position->x = x;
							position->y = y;
							toRemove.push(position);
							moves ++;
						}
						
						pos += 2;
						continue;
					}
					
					switch (prop)
					{
					case moveBlack:
					case moveWhite:
						// rare case: root contains move or placed stone:
						if (remember_root)
						{
							qDebug("root contains stone -> node created");
							boardHandler->createMoveSGF();
							unknownProperty = QString();
							isRoot = false;
if (tree->getCurrent()->getTimeinfo())
	qWarning("*** Timeinfo set !!!!");
							//tree->getCurrent()->setTimeinfo(false);
						}
					case editBlack:
					case editWhite:
					case editErase:
					{
						x = toParse->at(pos+1) - 'a' + 1;
						y = toParse->at(pos+2) - 'a' + 1;

						int x1, y1;
						bool compressed_list;

						// check for compressed lists
						if (toParse->at(pos+3) == ':')
						{
							x1 = toParse->at(pos+4) - 'a' + 1;
							y1 = toParse->at(pos+5) - 'a' + 1;
							compressed_list = true;
						}
						else
						{
							x1 = x;
							y1 = y;
							compressed_list = false;
						}
						
						boardHandler->setModeSGF(setup || compressed_list ? modeEdit : modeNormal);
						
						int i, j;
						for (i = x; i <= x1; i++)
							for (j = y; j <= y1; j++)
							{
								if (i == 20 && j == 20)
									boardHandler->doPass(true);
								else if (prop == editErase)
								{
									if (!fastLoad)
										boardHandler->removeStone(i, j, true, false);
									else
									{
										tree->getCurrent()->setX(0);
										tree->getCurrent()->setY(0);
										tree->getCurrent()->setColor(stoneNone);
									}
								}
								else
								{
									if (!fastLoad)
										boardHandler->addStoneSGF(black ? stoneBlack : stoneWhite, i, j, new_node);
									else
									{
										tree->getCurrent()->setX(i);
										tree->getCurrent()->setY(j);
										tree->getCurrent()->setColor(black? stoneBlack : stoneWhite);
									}
								}
								// tree->getCurrent()->getMatrix()->debug();
								// qDebug("ADDING MOVE %s %d/%d", black?"B":"W", x, y);
								
								// Remember this move for later, to remove from the matrix.
								position = new Position;
								position->x = i;
								position->y = j;
								toRemove.push(position);
								moves ++;
							}
						
						new_node = false;
						
						if (compressed_list)
							// Advance pos by 7
							pos += 7;
						else
							// Advance pos by 4
							pos += 4;
						break;
					}
						
					case nodeName:
					{
						commentStr = QString();
						bool skip = false;
						
						while (toParse->at(++pos) != ']')
						{
							if (static_cast<unsigned int>(pos) > strLength-1)
							{
								qDebug("SGF: Nodename string ended immediately");
								delete toParse;
								return corruptSgf(pos, "SGF: Nodename string ended immediately");
							}

							// white spaces
							if (toParse->at(pos) == '\\')
							{
								while (toParse->at(pos+1).isSpace() &&
									static_cast<unsigned int>(pos) < strLength-2)
									pos++;
								if (toParse->at(pos).isSpace())
									pos++;

								// case: "../<cr><lf>]"
								if (toParse->at(pos) == ']')
								{
									pos--;
									skip = true;
								}
							}

							// escaped chars: '\', ']', ':'
							if (!(toParse->at(pos) == '\\' &&
								(toParse->at(pos+1) == ']' ||
								 toParse->at(pos+1) == '\\' ||
								 toParse->at(pos+1) == ':')) &&
								 !skip &&
								 // no formatting
								!(toParse->at(pos) == '\n') &&
								!(toParse->at(pos) == '\r'))
								commentStr.append(toParse->at(pos));
						}

						// qDebug("Comment read: %s", commentStr.latin1());
						if (commentStr)
							// add comment; skip 'C[]'
							tree->getCurrent()->setNodeName(commentStr);
						pos++;
						break;
					}

					case comment:
					{
						commentStr = QString();
						bool skip = false;
						
						while (toParse->at(++pos) != ']' ||
							(toParse->at(pos-1) == '\\' && toParse->at(pos) == ']'))
						{
							if (static_cast<unsigned int>(pos) > strLength-1)
							{
								qDebug("SGF: Comment string ended immediately");
								delete toParse;
								return corruptSgf(pos, "SGF: Comment string ended immediately");
							}

							// white spaces
							if (toParse->at(pos) == '\\')
							{
								while (toParse->at(pos+1).isSpace() &&
									static_cast<unsigned int>(pos) < strLength-2)
									pos++;
								if (toParse->at(pos).isSpace())
									pos++;

								// case: "../<cr><lf>]"
								if (toParse->at(pos) == ']')
								{
									pos--;
									skip = true;
								}
							}

							// escaped chars: '\', ']', ':'
							if (!(toParse->at(pos) == '\\' &&
								(toParse->at(pos+1) == ']' ||
								 toParse->at(pos+1) == '\\' ||
								 toParse->at(pos+1) == ':')) &&
								 !skip)
								commentStr.append(toParse->at(pos));
						}

						// qDebug("Comment read: %s", commentStr.latin1());
						if (commentStr)
						{
							// add comment; skip 'C[]'
							tree->getCurrent()->setComment(commentStr);
						}
						pos ++;
						break;
					}

					case unknownProp:
					{
						// skip if property is known anyway
						bool skip = false;

						// save correct property name (or p.n. + '[')
						commentStr = toParse->at(pos);
						commentStr += toParse->at(tmppos = toParse->next_nonspace (pos + 1));
						pos = tmppos;

						// check if it's really necessary to hold properties
						// maybe they are handled at another position
						if (commentStr == "WR" ||
							commentStr == "BR" ||
							commentStr == "PW" ||
							commentStr == "PB" ||
							commentStr == "SZ" ||
							commentStr == "KM" ||
							commentStr == "HA" ||
							commentStr == "RE" ||
							commentStr == "DT" ||
							commentStr == "PC" ||
							commentStr == "CP" ||
							commentStr == "GN" ||
							commentStr == "OT" ||
							commentStr == "TM" ||
							// now: general options
							commentStr == "GM" ||
							commentStr == "ST" ||
							commentStr == "AP" ||
							commentStr == "FF")
						{
							skip = true;
						}
						sss= toParse->at(pos);
						while (toParse->at(++pos) != ']' ||
							(toParse->at(pos-1) == '\\' && toParse->at(pos) == ']'))
						{
							if (static_cast<unsigned int>(pos) > strLength-1)
							{
								qDebug("SGF: Unknown property ended immediately");
								delete toParse;
								return corruptSgf(pos, "SGF: Unknown property ended immediately");
							}
              sss= toParse->at(pos);
							if (!skip)
								commentStr.append(toParse->at(pos));
						}

						if (!skip)
							commentStr.append("]");

						// qDebug("Comment read: %s", commentStr.latin1());
						if (commentStr && !skip)
						{
							// cumulate unknown properties; skip empty property 'XZ[]'
							unknownProperty += commentStr;
							tree->getCurrent()->setUnknownProperty(unknownProperty);
						}
						pos ++;
            sss= toParse->at(pos);
						break;
					}

					case editMark:
						// set moveStr for increment labels of old 'L[]' property
						moveStr = "A";
						while (toParse->at(pos) == '[' &&
							static_cast<unsigned int>(pos) < strLength)
						{
							x = toParse->at(pos+1) - 'a' + 1;
							y = toParse->at(pos+2) - 'a' + 1;
							// qDebug("MARK: %d at %d/%d", markType, x, y);
							pos += 3;
							
							// 'LB' property? Then we need to get the text
							if (markType == markText && !old_label)
							{
								if (toParse->at(pos) != ':')
								{
									delete toParse;
									return corruptSgf(pos);
								}
								moveStr = "";
								while (toParse->at(++pos) != ']' &&
									static_cast<unsigned int>(pos) < strLength)
									moveStr.append(toParse->at(pos));
								// qDebug("LB TEXT = %s", moveStr.latin1());
								// It might me a number mark?
								bool check = false;
								moveStr.toInt(&check);  // Try to convert to Integer
// treat integers as characters...
check = false;
								
								if (!fastLoad)
								{
									if (check)
										tree->getCurrent()->getMatrix()->
										insertMark(x, y, markNumber);  // Worked, its a number
									else
										tree->getCurrent()->getMatrix()->
										insertMark(x, y, markType);    // Nope, its a letter
									tree->getCurrent()->getMatrix()->
										setMarkText(x, y, moveStr);
								}
								else
								{
									if (check)  // Number
										tree->getCurrent()->insertFastLoadMark(x, y, markNumber);
									else        // Text
										tree->getCurrent()->insertFastLoadMark(x, y, markType, moveStr);
								}
							}
							else
							{
								int x1, y1;
								bool compressed_list;

								// check for compressed lists
								if (toParse->at(pos) == ':')
								{
									x1 = toParse->at(pos+1) - 'a' + 1;
									y1 = toParse->at(pos+2) - 'a' + 1;
									compressed_list = true;
								}
								else
								{
									x1 = x;
									y1 = y;
									compressed_list = false;
								}
								
//								boardHandler->setModeSGF(setup || compressed_list ? modeEdit : modeNormal);
								
								int i, j;
								for (i = x; i <= x1; i++)
									for (j = y; j <= y1; j++)
									{
										if (!fastLoad)
											tree->getCurrent()->getMatrix()->insertMark(i, j, markType);
										else
											tree->getCurrent()->insertFastLoadMark(i, j, markType);

										// auto increment for old property 'L'
										if (old_label)
										{
											tree->getCurrent()->getMatrix()->
												setMarkText(x, y, moveStr);
											QChar c1 = moveStr[0];
											if (c1 == 'Z')
												moveStr = QString("a");
											else
												moveStr = c1.unicode() + 1;
										}
									}

//								new_node = false;

								if (compressed_list)
									// Advance pos by 3
									pos += 3;
							}

							//old_label = false;
							pos ++;
							while (toParse->at(pos).isSpace()) pos++;
						}
						break;

					case openMoves:
					{
						QString tmp_mv;
						while (toParse->at(++pos) != ']')
							tmp_mv += toParse->at(pos);
						tree->getCurrent()->setOpenMoves(tmp_mv.toInt());
						pos++;

						if (!tree->getCurrent()->getTimeinfo())
						{
							tree->getCurrent()->setTimeinfo(true);
							tree->getCurrent()->setTimeLeft(0);
						}
						break;
					}

					case timeLeft:
					{
						QString tmp_mv;
						while (toParse->at(++pos) != ']')
							tmp_mv += toParse->at(pos);
						tree->getCurrent()->setTimeLeft(tmp_mv.toFloat());
						pos++;

						if (!tree->getCurrent()->getTimeinfo())
						{
							tree->getCurrent()->setTimeinfo(true);
							tree->getCurrent()->setOpenMoves(0);
						}
						break;
					}

					case nextMove:
						if (toParse->at(++pos) == 'W')
							tree->getCurrent()->setPLinfo(stoneWhite);
						else if (toParse->at(pos) == 'B')
							tree->getCurrent()->setPLinfo(stoneBlack);

						pos += 2;
						break;

					default:
						break;
		    }

		    while (toParse->at(pos).isSpace())
			    pos++;
        sss= toParse->at(pos);
		} while (setup && toParse->at(pos) == '[');
		
		//tree->getCurrent()->getMatrix()->debug();
		while (toParse->at(pos).isSpace())
			pos++;

	    } while (toParse->at(pos) != ';' && toParse->at(pos) != '(' && toParse->at(pos) != ')' &&
		    static_cast<unsigned int>(pos) < strLength);
	    
	    // Advance pointer
	    pointer = pos;
	    
	    break;
	    
	default:
		delete toParse;
		return corruptSgf(pointer);
	}
	
    } while (pointer < strLength && pos >= 0);
    
    progress.setProgress(strLength);
    
    delete toParse;
    return !cancel;
}
Ejemplo n.º 6
0
// Called from clipboard SGF import
bool SGFParser::parseString(const QString &toParse)
{
	if (toParse.isNull() || toParse.isEmpty() || !initGame(toParse, NULL))
		return corruptSgf();
	return doParse(toParse);
}