static void ParseFile(const char *szFilePath) { int i, mv, mvMirror, nComp; PositionStruct pos, posMirror; PgnFileStruct pgn; if (pgn.Read(szFilePath)) { pos = posMirror = pgn.posStart; posMirror.Mirror(); for (i = 0; i < pgn.nMaxMove; i ++) { mv = pgn.wmvMoveTable[i + 1]; mvMirror = MOVE_MIRROR(mv); if (pos.zobr.dwLock1 < posMirror.zobr.dwLock1) { nComp = -1; } else if (pos.zobr.dwLock1 > posMirror.zobr.dwLock1) { nComp = 1; } else { if (pos.zobr.dwLock0 < posMirror.zobr.dwLock0) { nComp = -1; } else if (pos.zobr.dwLock0 > posMirror.zobr.dwLock0) { nComp = 1; } else { nComp = 0; } } if (nComp <= 0) { AddTemp(TempStruct(pos, mv, MoveValue(pos.sdPlayer, pgn.nResult))); } if (nComp >= 0) { AddTemp(TempStruct(posMirror, mvMirror, MoveValue(pos.sdPlayer, pgn.nResult))); } if (pos.ucpcSquares[DST(mv)] == 0) { pos.MakeMove(mv); } else { pos.MakeMove(mv); pos.SetIrrev(); } if (posMirror.ucpcSquares[DST(mvMirror)] == 0) { posMirror.MakeMove(mvMirror); } else { posMirror.MakeMove(mvMirror); posMirror.SetIrrev(); } } } }
static void AddEcco(const char *szPgnFile, const EccoApiStruct &EccoApi) { int i, nStatus; uint32_t dwEccoIndex, dwFileMove[20]; PgnFileStruct pgn; PositionStruct pos; if (pgn.Read(szPgnFile, NO_ADVERT)) { pos.FromFen(cszStartFen); for (i = 1; i <= MIN(pgn.nMaxMove, 20); i ++) { dwFileMove[i - 1] = Move2File(pgn.wmvMoveTable[i], pos); TryMove(pos, nStatus, pgn.wmvMoveTable[i]); } if (pgn.nMaxMove < 20) { dwFileMove[pgn.nMaxMove] = 0; } dwEccoIndex = EccoApi.EccoIndex((const char *) dwFileMove); strcpy(pgn.szEcco, (const char *) &dwEccoIndex); strcpy(pgn.szOpen, EccoApi.EccoOpening(dwEccoIndex)); strcpy(pgn.szVar, EccoApi.EccoVariation(dwEccoIndex)); pgn.Write(szPgnFile); } }
int Pgn2Xqf(const char *szPgnFile, const char *szXqfFile) { int i, nCommentLen; char szRed[MAX_STR_LEN * 2], szBlack[MAX_STR_LEN * 2]; FILE *fp; PgnFileStruct pgn; XqfHeaderStruct xqfhd; XqfMoveStruct xqfmv; if (!pgn.Read(szPgnFile)) { return PGN2XQF_ERROR_OPEN; } fp = fopen(szXqfFile, "wb"); if (fp == NULL) { return PGN2XQF_ERROR_CREATE; } memset(xqfhd.szTag, 0, sizeof(XqfHeaderStruct)); xqfhd.szTag[0] = 'X'; xqfhd.szTag[1] = 'Q'; xqfhd.szTag[2] = 10; for (i = 0; i < 32; i ++) { xqfhd.szPiecePos[i] = ccSquare2Xqf[pgn.posStart.ucsqPieces[cpcXqf2Piece[i]]]; } xqfhd.szResult[3] = cnResultTrans[pgn.nResult]; xqfhd.szSetUp[0] = 2; SetXqfString(xqfhd.szEvent, pgn.szEvent, sizeof(xqfhd.szEvent)); SetXqfString(xqfhd.szDate, pgn.szDate, sizeof(xqfhd.szDate)); SetXqfString(xqfhd.szSite, pgn.szSite, sizeof(xqfhd.szSite)); if (pgn.szRedTeam[0] == '\0') { SetXqfString(xqfhd.szRed, pgn.szRed, sizeof(xqfhd.szRed)); } else { sprintf(szRed, "%s %s", pgn.szRedTeam, pgn.szRed); SetXqfString(xqfhd.szRed, szRed, sizeof(xqfhd.szRed)); } if (pgn.szBlackTeam[0] == '\0') { SetXqfString(xqfhd.szBlack, pgn.szBlack, sizeof(xqfhd.szBlack)); } else { sprintf(szBlack, "%s %s", pgn.szBlackTeam, pgn.szBlack); SetXqfString(xqfhd.szBlack, szBlack, sizeof(xqfhd.szBlack)); } fwrite(&xqfhd, sizeof(xqfhd), 1, fp); memset(&xqfhd, 0, sizeof(xqfhd)); fwrite(&xqfhd, sizeof(xqfhd), 1, fp); for (i = 0; i <= pgn.nMaxMove; i ++) { xqfmv.ucTag = (i == pgn.nMaxMove ? 0 : 240); if (i == 0) { xqfmv.ucSrc = 24; xqfmv.ucDst = 32; xqfmv.ucReserved = 255; } else { xqfmv.ucSrc = 24 + ccSquare2Xqf[SRC(pgn.wmvMoveTable[i])]; xqfmv.ucDst = 32 + ccSquare2Xqf[DST(pgn.wmvMoveTable[i])]; xqfmv.ucReserved = 0; } fwrite(&xqfmv, sizeof(XqfMoveStruct), 1, fp); nCommentLen = (pgn.szCommentTable[i] == NULL ? 0 : strlen(pgn.szCommentTable[i])); fwrite(&nCommentLen, sizeof(int), 1, fp); if (pgn.szCommentTable[i] != NULL) { fwrite(pgn.szCommentTable[i], nCommentLen, 1, fp); } } fclose(fp); return 0; }
int Xqf2Pgn(const char *szXqfFile, const char *szPgnFile, const EccoApiStruct &EccoApi) { int i, nArg0, nArgs[4]; int nCommentLen, mv, nStatus; bool bHasNext; PgnFileStruct pgn; PositionStruct pos; FILE *fp; XqfHeaderStruct xqfhd; XqfMoveStruct xqfmv; // 版本号和加密偏移值 int nXqfVer, nPieceOff, nSrcOff, nDstOff, nCommentOff; // 密钥流 int nEncStream[32]; // 密钥流索引号 int nEncIndex; // 局面初始位置 int nPiecePos[32]; uint32_t dwEccoIndex, dwFileMove[20]; fp = fopen(szXqfFile, "rb"); if (fp == NULL) { return XQF2PGN_ERROR_OPEN; } fread(&xqfhd, sizeof(xqfhd), 1, fp); fseek(fp, sizeof(xqfhd), SEEK_CUR); if (xqfhd.szTag[0] == 'X' && xqfhd.szTag[1] == 'Q') { // PGN文件可以打开,现在正式解析XQF文件 nXqfVer = xqfhd.szTag[2]; if (nXqfVer < 11) { nPieceOff = nSrcOff = nDstOff = nCommentOff = 0; for (i = 0; i < 32; i ++) { nEncStream[i] = 0; } } else { // 局面初始位置的加密偏移值 nPieceOff = (uint8_t) (Square54Plus221((uint8_t) xqfhd.szTag[13]) * (uint8_t) xqfhd.szTag[13]); // 着法起点的加密偏移值 nSrcOff = (uint8_t) (Square54Plus221((uint8_t) xqfhd.szTag[14]) * nPieceOff); // 着法终点的加密偏移值 nDstOff = (uint8_t) (Square54Plus221((uint8_t) xqfhd.szTag[15]) * nSrcOff); // 注释的加密偏移值 nCommentOff = ((uint8_t) xqfhd.szTag[12] * 256 + (uint8_t) xqfhd.szTag[13]) % 32000 + 767; // 基本掩码 nArg0 = xqfhd.szTag[3]; // 密钥 = 前段密钥 | (后段密钥 & 基本掩码) for (i = 0; i < 4; i ++) { nArgs[i] = xqfhd.szTag[8 + i] | (xqfhd.szTag[12 + i] & nArg0); } // 密钥流 = 密钥 & 密钥流掩码 for (i = 0; i < 32; i ++) { nEncStream[i] = (uint8_t) (nArgs[i % 4] & cszEncStreamMask[i]); } } nEncIndex = 0; // 记录棋谱信息 if (xqfhd.szEvent[0] == 0) { GetXqfString(pgn.szEvent, xqfhd.szTitle); } else { GetXqfString(pgn.szEvent, xqfhd.szEvent); } GetXqfString(pgn.szDate, xqfhd.szDate); GetXqfString(pgn.szSite, xqfhd.szSite); GetXqfString(pgn.szRed, xqfhd.szRed); GetXqfString(pgn.szBlack, xqfhd.szBlack); pgn.nResult = cnResultTrans[(int) xqfhd.szResult[3]]; if (xqfhd.szSetUp[0] < 2) { // 如果是开局或者全局,那么直接设置起始局面 pgn.posStart.FromFen(cszStartFen); } else { // 如果是中局或者排局,那么根据"xqfhd.szPiecePos[32]"的内容摆放局面 // 当版本号达到12时,还要进一步解密局面初始位置 if (nXqfVer < 12) { for (i = 0; i < 32; i ++) { nPiecePos[i] = (uint8_t) (xqfhd.szPiecePos[i] - nPieceOff); } } else { for (i = 0; i < 32; i ++) { nPiecePos[(nPieceOff + 1 + i) % 32] = (uint8_t) (xqfhd.szPiecePos[i] - nPieceOff); } } // 把"nPiecePos[32]"的数据放到"PositionStruct"中 pgn.posStart.ClearBoard(); for (i = 0; i < 32; i ++) { if (nPiecePos[i] < 90) { pgn.posStart.AddPiece(cucsqXqf2Square[nPiecePos[i]], cpcXqf2Piece[i]); } } pgn.posStart.SetIrrev(); } pos = pgn.posStart; bHasNext = true; while (bHasNext && pgn.nMaxMove < MAX_MOVE_LEN) { // 读取着法记录 if (nXqfVer < 11) { fread(&xqfmv, sizeof(xqfmv), 1, fp); fread(&nCommentLen, sizeof(int), 1, fp); if ((xqfmv.ucTag & 0xf0) == 0) { bHasNext = false; } } else { ReadAndDecrypt(fp, &xqfmv, sizeof(xqfmv), nEncStream, nEncIndex); if ((xqfmv.ucTag & 0x20) != 0) { ReadAndDecrypt(fp, &nCommentLen, sizeof(int), nEncStream, nEncIndex); nCommentLen -= nCommentOff; } else { nCommentLen = 0; } if ((xqfmv.ucTag & 0x80) == 0) { bHasNext = false; } } if (pgn.nMaxMove > 0) { // 记录着法 mv = MOVE(cucsqXqf2Square[(uint8_t) (xqfmv.ucSrc - 24 - nSrcOff)], cucsqXqf2Square[(uint8_t) (xqfmv.ucDst - 32 - nDstOff)]); if (pgn.nMaxMove == 1) { if ((pgn.posStart.ucpcSquares[SRC(mv)] & 32) != 0) { pgn.posStart.ChangeSide(); pos.ChangeSide(); } } if (xqfhd.szSetUp[0] < 2 && pgn.nMaxMove <= 20) { dwFileMove[pgn.nMaxMove - 1] = Move2File(mv, pos); } TryMove(pos, nStatus, mv); pgn.wmvMoveTable[pgn.nMaxMove] = mv; if (pos.nMoveNum == MAX_MOVE_NUM) { pos.SetIrrev(); } } if (nCommentLen > 0) { pgn.szCommentTable[pgn.nMaxMove] = new char[nCommentLen + 1]; ReadAndDecrypt(fp, pgn.szCommentTable[pgn.nMaxMove], nCommentLen, nEncStream, nEncIndex); pgn.szCommentTable[pgn.nMaxMove][nCommentLen] = '\0'; } pgn.nMaxMove ++; } pgn.nMaxMove --; // 解析ECCO if (xqfhd.szSetUp[0] < 2) { if (pgn.nMaxMove < 20) { dwFileMove[pgn.nMaxMove] = 0; } if (EccoApi.Available()) { dwEccoIndex = EccoApi.EccoIndex((const char *) dwFileMove); strcpy(pgn.szEcco, (const char *) &dwEccoIndex); strcpy(pgn.szOpen, EccoApi.EccoOpening(dwEccoIndex)); strcpy(pgn.szVar, EccoApi.EccoVariation(dwEccoIndex)); } } fclose(fp); return (pgn.Write(szPgnFile) ? XQF2PGN_OK : XQF2PGN_ERROR_CREATE); } else { fclose(fp); return XQF2PGN_ERROR_FORMAT; } }