From 9d67c8a67859e3cd84406766ebbb2dba172726d5 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Fri, 14 Jun 2019 11:37:06 +0800 Subject: [PATCH 01/33] =?UTF-8?q?deck=E7=9A=84=E9=85=8D=E5=A5=97convert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/EncodingConvert.cpp | 10 +++++++++- Dice/EncodingConvert.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Dice/EncodingConvert.cpp b/Dice/EncodingConvert.cpp index 8b219e22..504a4917 100644 --- a/Dice/EncodingConvert.cpp +++ b/Dice/EncodingConvert.cpp @@ -24,6 +24,7 @@ #include #include #include +#include std::string GBKtoUTF8(const std::string& strGBK) { @@ -38,7 +39,14 @@ std::string GBKtoUTF8(const std::string& strGBK) delete[] str2; return strOutUTF8; } - +std::vector GBKtoUTF8(const std::vector &strGBK) +{ + std::vector vOutUTF8; + for (auto it : strGBK) { + vOutUTF8.push_back(GBKtoUTF8(it)); + } + return vOutUTF8; +} std::string UTF8toGBK(const std::string& strUTF8) { int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, nullptr, 0); diff --git a/Dice/EncodingConvert.h b/Dice/EncodingConvert.h index 95a30bc0..a62c4a92 100644 --- a/Dice/EncodingConvert.h +++ b/Dice/EncodingConvert.h @@ -24,7 +24,9 @@ #ifndef DICE_ENCODING_CONVERT #define DICE_ENCODING_CONVERT #include +#include std::string GBKtoUTF8(const std::string& strGBK); +std::vector GBKtoUTF8(const std::vector &strGBK); std::string UTF8toGBK(const std::string& strUTF8); std::string UrlEncode(const std::string& str); std::string UrlDecode(const std::string& str); From 6d4806e94325780152d5946020f24c1fe28f82af Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Fri, 21 Jun 2019 18:18:13 +0800 Subject: [PATCH 02/33] =?UTF-8?q?bug=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/Dice.cpp | 2 +- Dice/DiceEvent.h | 32 ++++++++++++-------------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index 0e13afd3..ea88d39e 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -100,7 +100,7 @@ void dataBackUp() { //备份管理员列表 ofstream ofstreamAdmin(strFileLoc + "AdminQQ.RDconf"); for (auto it : AdminQQ) { - ofstreamAdmin << it; + ofstreamAdmin << it << std::endl; } ofstreamAdmin.close(); //备份监控窗口列表 diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index fd3051f3..a00d6f25 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -1003,15 +1003,11 @@ class FromMsg { string QQNum; if (strLowerMessage.substr(intMsgCnt, 10) == "[cq:at,qq=") { intMsgCnt += 10; - while (isdigit(strLowerMessage[intMsgCnt])) { - QQNum += strLowerMessage[intMsgCnt]; - intMsgCnt++; - } + QQNum = readDigit(); intMsgCnt++; } - else while (isdigit(strLowerMessage[intMsgCnt])) { - QQNum += strLowerMessage[intMsgCnt]; - intMsgCnt++; + else { + QQNum = readDigit(); } while (isspace(static_cast(strLowerMessage[intMsgCnt]))) intMsgCnt++; @@ -1025,11 +1021,7 @@ class FromMsg { reply(GlobalMsg["strSelfPermissionErr"]); return 1; } - string strMainDice; - while (isdigit(strLowerMessage[intMsgCnt]) || (strLowerMessage[intMsgCnt]) == 'd' || (strLowerMessage[intMsgCnt]) == '+' || (strLowerMessage[intMsgCnt]) == '-') { - strMainDice += strLowerMessage[intMsgCnt]; - intMsgCnt++; - } + string strMainDice = readDice(); const int intDefaultDice = DefaultDice.count(fromQQ) ? DefaultDice[fromQQ] : 100; RD rdMainDice(strMainDice, intDefaultDice); rdMainDice.Roll(); @@ -3312,7 +3304,7 @@ class FromMsg { bool isLinkOrder = false; //跳过空格 void readSkipSpace() { - while (isspace(strLowerMessage[intMsgCnt]))intMsgCnt++; + while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; } string readRest() { return strMsg.substr(intMsgCnt); @@ -3320,8 +3312,8 @@ class FromMsg { //读取参数(统一小写) string readPara() { string strPara; - while (isspace(strLowerMessage[intMsgCnt]))intMsgCnt++; - while (!isspace(strLowerMessage[intMsgCnt]) && !isdigit(strLowerMessage[intMsgCnt]) && (strLowerMessage[intMsgCnt] != '-') && (strLowerMessage[intMsgCnt] != '+') && intMsgCnt != strLowerMessage.length()) { + while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; + while (!isspace(static_cast(strLowerMessage[intMsgCnt])) && !isdigit(static_cast(strLowerMessage[intMsgCnt])) && (strLowerMessage[intMsgCnt] != '-') && (strLowerMessage[intMsgCnt] != '+') && intMsgCnt != strLowerMessage.length()) { strPara += strLowerMessage[intMsgCnt]; intMsgCnt++; } @@ -3330,8 +3322,8 @@ class FromMsg { //读取数字 string readDigit() { string strMum; - while (!isdigit(strMsg[intMsgCnt]) && intMsgCnt != strMsg.length())intMsgCnt++; - while (isdigit(strMsg[intMsgCnt])) { + while (!isdigit(static_cast(strMsg[intMsgCnt])) && intMsgCnt != strMsg.length())intMsgCnt++; + while (isdigit(static_cast(strMsg[intMsgCnt]))) { strMum += strMsg[intMsgCnt]; intMsgCnt++; } @@ -3346,7 +3338,7 @@ class FromMsg { //读取掷骰表达式 string readDice(){ string strDice; - while (isspace(strLowerMessage[intMsgCnt]))intMsgCnt++; + while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; while (isdigit(static_cast(strLowerMessage[intMsgCnt])) || strLowerMessage[intMsgCnt] == 'd' || strLowerMessage[intMsgCnt] == 'k' || strLowerMessage[intMsgCnt] == 'p' || strLowerMessage[intMsgCnt] == 'b' @@ -3384,8 +3376,8 @@ class FromMsg { //读取分项 string readItem() { string strMum; - while (isspace(strMsg[intMsgCnt]) || strMsg[intMsgCnt] == '|')intMsgCnt++; - while (!isspace(strMsg[intMsgCnt]) && strMsg[intMsgCnt] != '|'&& intMsgCnt != strMsg.length()) { + while (isspace(static_cast(strMsg[intMsgCnt])) || strMsg[intMsgCnt] == '|')intMsgCnt++; + while (!isspace(static_cast(strMsg[intMsgCnt])) && strMsg[intMsgCnt] != '|'&& intMsgCnt != strMsg.length()) { strMum += strMsg[intMsgCnt]; intMsgCnt++; } From be09c7f5e94a0c1559598929f1bc1d201075681f Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Fri, 21 Jun 2019 18:54:56 +0800 Subject: [PATCH 03/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A5=BD=E5=8F=8B?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 绉佺敤妯″紡涓嶅啀鎷掔粷闈炵櫧鍚嶅崟鐢ㄦ埛 鐜板湪鍚屾剰濂藉弸鍚庝細鍙戦佸洖鎵 --- Dice/DiceConsole.cpp | 35 ++++++++++++++++------------------- Dice/GlobalVar.cpp | 13 ++++++++++--- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 3d8336f1..9fd0c622 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -234,26 +234,23 @@ EVE_Menu(eventGlobalSwitch) { return 0; } EVE_Request_AddFriend(eventAddFriend) { - if (masterQQ&&boolMasterMode) { - string strMsg = "好友添加请求,来自:" + printQQ(fromQQ) + ","; - if (BlackQQ.count(fromQQ)) { - strMsg += "已拒绝(用户在黑名单中)"; - setFriendAddRequest(responseFlag, 2, ""); - } - else if (WhiteQQ.count(fromQQ)) { - strMsg += "已同意(用户在白名单中)"; - setFriendAddRequest(responseFlag, 1, ""); - } - else if (boolPreserve) { - strMsg += "已拒绝(当前在私用模式)"; - setFriendAddRequest(responseFlag, 2, ""); - } - else { - strMsg += "已同意"; - setFriendAddRequest(responseFlag, 1, ""); - } - sendAdmin(strMsg); + string strMsg = "好友添加请求,来自:" + printQQ(fromQQ); + if (BlackQQ.count(fromQQ)) { + strMsg += ",已拒绝(用户在黑名单中)"; + setFriendAddRequest(responseFlag, 2, ""); + } + else if (WhiteQQ.count(fromQQ)) { + strMsg += ",已同意(用户在白名单中)"; + setFriendAddRequest(responseFlag, 1, ""); + GlobalMsg["strAddFriendWhiteQQ"].empty() ? AddMsgToQueue(GlobalMsg["strAddFriend"], fromQQ) + : AddMsgToQueue(GlobalMsg["strAddFriendWhiteQQ"], fromQQ); + } + else { + strMsg += ",已同意"; + setFriendAddRequest(responseFlag, 1, ""); + AddMsgToQueue(GlobalMsg["strAddFriend"], fromQQ); } + sendAdmin(strMsg); return 1; } diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index 6e16fd5a..a8d314e5 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -35,7 +35,7 @@ CQ::logger DiceLogger("Dice!"); * 请勿修改Dice_Build, Dice_Ver_Without_Build,DiceRequestHeader以及Dice_Ver常量 * 请修改Dice_Short_Ver或Dice_Full_Ver常量以达到版本自定义 */ -const unsigned short Dice_Build = 543; +const unsigned short Dice_Build = 544; const std::string Dice_Ver_Without_Build = "2.3.8Express7"; const std::string DiceRequestHeader = "Dice/2.3.8"; const std::string Dice_Ver = Dice_Ver_Without_Build + "(" + std::to_string(Dice_Build) + ")"; @@ -217,6 +217,13 @@ std::map GlobalMsg {"strPreserve", "本机器人私有私用,勿扰勿怪"}, {"strJrrp", "{0}今天的人品值是: {1}"}, {"strJrrpErr", "JRRP获取失败! 错误信息: \n{0}"}, + { "strAddFriendWhiteQQ","" }, //此项非空,则白名单用户添加好友时回复此句 + { "strAddFriend", R"(欢迎使用本机器人! +.help协议 确认服务协议 +.help指令 查看指令列表 +.help设定 确认骰娘设定 +.help链接 查看源码文档 +使用服务默认已经同意服务协议)" }, //同意添加好友时额外发送的语句 {"strAddGroup", R"(欢迎使用本机器人! 请使用.dismiss QQ号(或后四位) 使本机器人退群退讨论组 .bot on/off QQ号(或后四位) //插件开启或关闭 @@ -224,7 +231,7 @@ std::map GlobalMsg .help指令 查看指令列表 .help设定 确认骰娘设定 .help链接 查看源码文档 -千万别想当然以为本机器人和别的骰娘一样!)" }, +邀请入群默认视为同意服务协议)" }, {"strSelfName", ""}, {"strBotMsg", "\n使用.help更新 查看本机器人更新内容"}, {"strHlpMsg" , Dice_Short_Ver + "\n" + @@ -240,7 +247,7 @@ std::map GlobalMsg std::map EditedMsg; std::map HelpDoc = { -{"更新","543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能\n533:更新了.rc/ra功能\n532:更新了消息转发功能(当前Master专用)\n528:更新.help帮助功能,允许后接参数"}, +{"更新","544:优化好友申请处理\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能\n528:更新.help帮助功能,允许后接参数"}, {"协议","0.本协议是Shiki(Death、Judgement、The World)的服务协议。如果你看到了这句话,意味着Master应用默认协议,请注意。\n1.邀请骰娘、使用掷骰服务和在群内阅读此协议视为同意并承诺遵守此协议,否则请使用.dismiss移出骰娘。\n2.不允许禁言、移出骰娘或刷屏掷骰等对骰娘的不友善行为,这些行为将会提高骰娘被制裁的风险。开关骰娘响应请使用.bot on/off。\n3.骰娘默认邀请行为已事先得到群内同意,因而会自动同意群邀请。因擅自邀请而使骰娘遭遇不友善行为时,邀请者因未履行预见义务而将承担连带责任。\n4.禁止将骰娘用于赌博及其他违法犯罪行为。\n5.对于设置敏感昵称等无法预见但有可能招致言论审查的行为,骰娘可能会出于自我保护而拒绝提供服务\n6.由于技术以及资金原因,我们无法保证机器人100%的时间稳定运行,可能不定时停机维护或遭遇冻结,但是相应情况会及时通过各种渠道进行通知,敬请谅解。临时停机的骰娘不会有任何响应,故而不会影响群内活动,此状态下仍然禁止不友善行为。\n7.对于违反协议的行为,骰娘将视情况终止对用户和所在群提供服务,并将不良记录共享给其他服务提供方。黑名单相关事宜可以与服务提供方协商,但最终裁定权在服务提供方。\n8.本协议内容随时有可能改动。请注意帮助信息、签名、空间、官方群等处的骰娘动态。\n9.骰娘提供掷骰服务是完全免费的,欢迎投食。\n10.本服务最终解释权归服务提供方所有。"}, {"链接","查看源码:https://github.com/w4123/Dice/tree/Shiki\n插件下载:https://github.com/w4123/Dice/releases\n官方文档:https://www.stringempty.xyz\n跑团记录着色器:https://logpainter.kokona.tech"}, {"设定","Master:()\n.me使用:禁止\n.jrrp使用:允许\n邀请处理:黑名单制,非禁即入\n讨论组使用:允许\n移出反制:拉黑群和操作者\n禁言反制:默认拉黑群和群主\n刷屏反制:警告\n邀请人责任:有限连带\n窥屏可能:有\n其他插件:无\n官方群:941980833\n私骰群:192499947"}, From 03db52cc6e556174e30700ebfb454f6fca7a1403 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 25 Jun 2019 10:34:00 +0800 Subject: [PATCH 04/33] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=8C=87=E4=BB=A4=E7=9A=84=E7=AE=A1=E7=90=86=E5=91=98=E6=9D=83?= =?UTF-8?q?=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .link .helpdoc鍏佽绠$悊鍛樹娇鐢 --- Dice/DiceEvent.h | 10 +++------- Dice/GlobalVar.cpp | 3 ++- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index a00d6f25..9711a643 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -711,13 +711,9 @@ class FromMsg { } if (!isCalled && (intT == GroupT && DisabledGroup.count(fromGroup)))return 0; if (!isCalled && (intT == DiscussT && DisabledDiscuss.count(fromGroup)))return 0; - if (strLowerMessage.substr(intMsgCnt, 7) == "helpdoc") + if (strLowerMessage.substr(intMsgCnt, 7) == "helpdoc"&&isAdmin) { intMsgCnt += 7; - if (!isMaster) { - reply(GlobalMsg["strNotMaster"]); - return true; - } while (strMsg[intMsgCnt] == ' ') intMsgCnt++; if (intMsgCnt == strMsg.length()) { @@ -1418,8 +1414,8 @@ class FromMsg { } else if (strLowerMessage.substr(intMsgCnt, 4) == "link") { intMsgCnt += 4; - if (!isMaster) { - reply(GlobalMsg["strNotMaster"]); + if (!isAdmin) { + reply(GlobalMsg["strNotAdmin"]); return true; } isLinkOrder = true; diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index a8d314e5..89ad7b4d 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -106,7 +106,8 @@ std::map GlobalMsg {"strLinkWarning","尝试创建时空门,但不保证能否连通"}, {"strLinkNotFound","时空门要通向不可名状的地方了×"}, {"strNotMaster","你不是本机器人的master!你想做什么?"}, - {"strDismiss", ""}, + {"strNotAdmin","你不是本机器人的管理员×"}, + {"strDismiss", ""}, //.dismiss退群前的回执 {"strHlpSet","已为{0}设置词条√"}, {"strHlpReset","已清除{0}的词条,重启应用后重置默认词条√"}, {"strHlpNameEmpty","Master想要自定义什么词条呀?"}, From 33f396724da73bf485c253fb940724a4a2bf87e2 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 25 Jun 2019 18:52:00 +0800 Subject: [PATCH 05/33] =?UTF-8?q?=E5=85=81=E8=AE=B8deck=E4=BB=8E=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=AF=BB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/CardDeck.cpp | 36 ++----------------- Dice/CardDeck.h | 2 -- Dice/Dice.cpp | 18 +++++----- Dice/Dice.vcxproj | 1 + Dice/Dice.vcxproj.filters | 3 ++ Dice/Jsonio.h | 74 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+), 44 deletions(-) create mode 100644 Dice/Jsonio.h diff --git a/Dice/CardDeck.cpp b/Dice/CardDeck.cpp index 94cb55c0..e50e687f 100644 --- a/Dice/CardDeck.cpp +++ b/Dice/CardDeck.cpp @@ -74,46 +74,14 @@ namespace CardDeck std::map PublicComplexDeck{ //{"调查员背景","个人描述:{个人描述}\n思想信念:{思想信念}\n重要之人:{重要之人}\n重要之人理由:{重要之人理由}\n意义非凡之地:{意义非凡之地}\n宝贵之物:{宝贵之物}\n特点:{调查员特点}"} }; - //读取备份牌堆 - int loadDeck(std::string strLoc, std::map> &deck) { - ifstream fin(strLoc); - if (fin) { - json j; - fin >> j; - for (json::iterator it = j.begin(); it != j.end(); ++it) - { - long long llID = stoll(it.key()); - std::vector card = {}; - for (auto iit : it.value()) { - card.push_back(UTF8toGBK(iit)); - } - deck[llID]= card; - } - fin.close(); - } - return 0; - } - //保存备份牌堆 - int saveDeck(std::string strLoc, std::map> deck) { - if (deck.empty())return 0; - ofstream fout(strLoc); - if (fout) { - json j; - for (auto it : deck) { - j[to_string(it.first)] = GBKtoUTF8(it.second); - } - fout << j; - fout.close(); - } - return 0; - } + //返回0:未找到;1:公共牌组;2:自然数列 int findDeck(std::string strDeckName) { std::string strDeck; if (mPublicDeck.count(strDeckName)) { return 1; } - else if (isdigit(strDeckName[0]) && strDeckName.length() < 3 || strDeckName == "100") { + else if (isdigit(static_cast(strDeckName[0])) && strDeckName.length() < 3 || strDeckName == "100") { return 2; } return 0; diff --git a/Dice/CardDeck.h b/Dice/CardDeck.h index f7975af8..7c2eed21 100644 --- a/Dice/CardDeck.h +++ b/Dice/CardDeck.h @@ -22,8 +22,6 @@ namespace CardDeck //私人临时牌堆 extern std::map> mPrivateDeckTmp; extern std::map PublicComplexDeck; - int loadDeck(std::string strLoc, std::map> &deck); - int saveDeck(std::string strLoc, std::map> deck); int findDeck(std::string strDeckName); std::string drawCard(std::vector &TempDeck,bool boolBack=false); std::string drawCard(std::string strDeckName, bool boolBack = false); diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index ea88d39e..26a4cb0e 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -34,6 +34,7 @@ #include #include "APPINFO.h" +#include "jsonio.h" #include "RandomGenerator.h" #include "RD.h" #include "CQEVE_ALL.h" @@ -195,10 +196,10 @@ void dataBackUp() { } ofstreamDefaultCOC.close(); //保存卡牌 - CardDeck::saveDeck(strFileLoc + "GroupDeck.json", CardDeck::mGroupDeck); - CardDeck::saveDeck(strFileLoc + "GroupDeckTmp.json", CardDeck::mGroupDeckTmp); - CardDeck::saveDeck(strFileLoc + "PrivateDeck.json", CardDeck::mPrivateDeck); - CardDeck::saveDeck(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); + saveJMap(strFileLoc + "GroupDeck.json", CardDeck::mGroupDeck); + saveJMap(strFileLoc + "GroupDeckTmp.json", CardDeck::mGroupDeckTmp); + saveJMap(strFileLoc + "PrivateDeck.json", CardDeck::mPrivateDeck); + saveJMap(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); } EVE_Enable(eventEnable) { @@ -564,10 +565,11 @@ EVE_Enable(eventEnable) GlobalMsg[it.first] = strMsg; } //读取卡牌 - CardDeck::loadDeck(strFileLoc + "GroupDeck.json",CardDeck::mGroupDeck); - CardDeck::loadDeck(strFileLoc + "GroupDeckTmp.json", CardDeck::mGroupDeckTmp); - CardDeck::loadDeck(strFileLoc + "PrivateDeck.json", CardDeck::mPrivateDeck); - CardDeck::loadDeck(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); + loadJMap(strFileLoc + "GroupDeck.json",CardDeck::mGroupDeck); + loadJMap(strFileLoc + "GroupDeckTmp.json", CardDeck::mGroupDeckTmp); + loadJMap(strFileLoc + "PrivateDeck.json", CardDeck::mPrivateDeck); + loadJMap(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); + loadJMap(strFileLoc + "PublicDeck.json", CardDeck::mPublicDeck); //读取替身模式 ifstream ifstreamStandByMe(strFileLoc + "StandByMe.RDconf"); if (ifstreamStandByMe) diff --git a/Dice/Dice.vcxproj b/Dice/Dice.vcxproj index d30c121d..040a4f9e 100644 --- a/Dice/Dice.vcxproj +++ b/Dice/Dice.vcxproj @@ -261,6 +261,7 @@ + diff --git a/Dice/Dice.vcxproj.filters b/Dice/Dice.vcxproj.filters index 5c2ba640..28dad614 100644 --- a/Dice/Dice.vcxproj.filters +++ b/Dice/Dice.vcxproj.filters @@ -218,6 +218,9 @@ 澶存枃浠 + + 澶存枃浠 + diff --git a/Dice/Jsonio.h b/Dice/Jsonio.h new file mode 100644 index 00000000..c3cbe741 --- /dev/null +++ b/Dice/Jsonio.h @@ -0,0 +1,74 @@ +#pragma once +#include +#include +#include +#include "json.hpp" +#include "EncodingConvert.h" + +template +T readJson(std::string strJson) { + return UTF8toGBK(strJson); +} + +template<> +long long readJson(std::string strJson) { + return stoll(strJson); +} + +template +std::vector readJVec(std::vector vJson) { + std::vector vTmp; + for (auto it : vJson) { + vTmp.push_back(readJson(it)); + } + return vTmp; +} + +template +int loadJMap(std::string strLoc, std::map> &mapTmp) { + std::ifstream fin(strLoc); + if (fin) { + nlohmann::json j; + fin >> j; + for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) + { + T1 tKey = readJson(it.key()); + std::vector tVal = readJVec(it.value()); + mapTmp[tKey] = tVal; + } + fin.close(); + } + return 0; +} + +std::string writeJson(std::string strJson) { + return GBKtoUTF8(strJson); +} + +std::string writeJson(long long llJson) { + return std::to_string(llJson); +} + +template +std::vector writeJVec(std::vector vJson) { + std::vector vTmp; + for (auto it : vJson) { + vTmp.push_back(writeJson(it)); + } + return vTmp; +} + +template +int saveJMap(std::string strLoc, std::map> mapTmp) { + if (mapTmp.empty())return 0; + std::ofstream fout(strLoc); + if (fout) { + nlohmann::json j; + for (auto it : mapTmp) { + j[writeJson(it.first)] = writeJVec(it.second); + } + fout << j; + fout.close(); + } + return 0; +} \ No newline at end of file From 91e021db273b2ca8f1d12ffea9273425e7ef0a74 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Fri, 28 Jun 2019 16:54:49 +0800 Subject: [PATCH 06/33] =?UTF-8?q?deck=E8=BF=BD=E5=8A=A0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/CardDeck.cpp | 5 +++-- Dice/Dice.cpp | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dice/CardDeck.cpp b/Dice/CardDeck.cpp index e50e687f..a303eaf1 100644 --- a/Dice/CardDeck.cpp +++ b/Dice/CardDeck.cpp @@ -18,12 +18,14 @@ namespace CardDeck //class Deck {}; std::map> mPublicDeck{ {"硬币",{"正","反"}}, - {"东方角色",{"博丽灵梦 / Hakurei Reimu","雾雨魔理沙 / Kirisame Marisa","神玉 / SinGyoku","魅魔 / Mima","菊理 / Kikuri","矜羯罗 / Konngara","幽幻魔眼 / YuugenMagan","依莉斯 / Elis","萨丽爱尔 / Sariel","玄爷 / Genjii","里香 / Rika","明罗 / Meira","魔梨沙 / Marisa","Flower~战车 / Furawa~sensha","邪眼西格玛 / ibiruai sigma","爱莲 / Ellen","小兔姬 / Kotohime","卡娜·安娜贝拉尔 / Kana Anaberal","朝仓理香子 / Asakura Rikako","北白河千百合 / Kitashirakawa Chiyuri","冈崎梦美 / Okazaki Yumemi","咪咪号(咪咪酱) / Mimichan","留琴 / Ru~koto","玛○奇 / Ma maru chi","苏格拉底 / Sokuratesu","奥莲姬 / Orange","胡桃 / Kurumi","艾丽/ Elliy","幽香 / Yuka","梦月 / Mugetu","幻月 / Gengetu","萨拉 / Sara","露易兹/ Luize","爱丽丝 / Alice","雪 / Yuki","舞 / Mai","梦子 / Yumeko","神绮 / Shinki","露米娅 / Rumia","大妖精 / Daiyousei","琪露诺 / Cirno","红美铃 / Hoan Meirin","小恶魔 / Koakuma","帕秋莉·诺蕾姬 / Patchouli Knowledge","十六夜咲夜 / Izayoi Sakuya","蕾米莉亚·斯卡蕾特/ Remilia Scarlet","芙兰朵露·斯卡蕾特/ Flandre Scarlet","冴月麟 / Satsuki Rin","毛玉 / gedama","蕾蒂·霍瓦特洛克/ Letty Whiterock","橙 / Chen","爱丽丝·玛格特洛依德 / Alice Margatroid","莉莉霍瓦特 / Lily White","露娜萨·普莉兹姆利巴 / Lunasa Prismriver","梅露兰·普莉兹姆利巴 / Merlin Prismriver","莉莉卡·普莉兹姆利巴 / Lyrica Prismriver","魂魄妖梦 / Konpaku Youmu","西行寺幽幽子 / Saigyouji Yuyuko","八云蓝 / Yakumo Ran","八云紫 / Yakumo Yukari","魂魄妖忌 / Konpaku Youki","蕾拉·普莉兹姆利巴 / Leira Prismriver","伊吹萃香 / Ibuki Suika","莉格露·奈特巴格 / Wriggle Nightbug","米斯蒂娅·萝蕾拉 / Mystia Lorelei","上白泽慧音 / Kamishirasawa Keine","因幡帝 / Inaba Tewi","铃仙·优昙华院·因幡 / Reisen Udongein Inaba","八意永琳 / Yagokoro Eirin","蓬莱山辉夜 / Houraisan Kaguya","藤原妹红 / Huziwara no Mokou","射命丸文 / Syameimaru Aya","梅蒂欣·梅兰可莉 / Medicine Melancholy","风见幽香 / Kazami Yuka","小野塚小町 / Onozuka Komachi","四季映姬·亚玛萨那度 / Shikieiki Yamaxanadu","秋静叶 / Aki Shizuha","秋穰子 / Aki Minoriko","键山雏 / Kagiyama Hina","河城荷取 / Kawasiro Nitori","犬走椛 / Inubashiri Momizi","东风谷早苗 / Kochiya Sanae","八坂神奈子 / Yasaka Kanako","洩矢诹访子 / Moriya Suwako","永江衣玖 / Nagae Iku","比那名居天子 / Hinanawi Tenshi","琪斯美 / Kisume","黑谷山女 / Kurodani Yamame","水桥帕露西 / Mizuhashi Parsee","星熊勇仪 / Hoshiguma Yugi","古明地觉 / Komeiji Satori","火焰猫燐 / Kaenbyou Rin","灵乌路空 / Reiuzi Utsuho","古明地恋 / Komeiji Koishi","僵尸妖精 (怨灵附身妖精) / Zombie Fairy","娜兹玲 / Nazrin","多多良小伞 / Tatara Kogasa","云居一轮 & 云山 / Kumoi Ichirin & Unzan","村纱水蜜 / Captain Murasa Minamitsu","寅丸星 / Toramaru Syou","圣白莲 / Hiziri Byakuren","封兽鵺 / Houjuu Nue","命莲 / Myouren","大鲶鱼 / Oo-Namazu","太岁星君 / Taisai Sei-kun","大太法师 / Daidarabotchi","非想天则 / Hisoutensoku","提泰妮娅 / Titania","歌利亚人偶 / Goliath Doll","姬海棠果 (姬海棠羽立 / 姬海棠极) / Himekaidou Hatate","幽谷响子/ Kasodani Kyouko","宫古芳香/ Miyako Yoshika","霍青娥 / Seiga NyanNyan)","苏我屠自古 / Soga no Toziko","物部布都 / Mononobe no Futo","丰聪耳神子 / Toyosatomimi no Miko","二岩猯藏 / Hutatsuiwa Mamizou","秦心 / Hata no Kokoro","秦河胜 / Hata no Kawakatsu","若鹭姬 / Wakasagihime","赤蛮奇 / Sekibanki","今泉影狼 / Imaizumi Kagerou","九十九弁弁 / Tsukumo Benben","九十九八桥 / Tsukumo Yatsuhashi","鬼人正邪 / Kijin Seija","少名针妙丸 / Sukuna Shinmyoumaru","堀川雷鼓 / Horikawa Raiko","宇佐见堇子 / Usami Sumireko","清兰 / Seiran","铃瑚 / Ringo","哆来咪·苏伊特 / Doremy Sweet","稀神探女 / Kisin Sagume","克劳恩皮丝 / Clownpiece","纯狐 / Junko","赫卡提亚·拉碧斯拉祖利 / Hecatia Lapislazuli","依神女苑 / Yorigami Jyoon","依神紫苑 / Yorigami Shion","爱塔妮缇拉尔瓦 / Eternity Larva","坂田合欢乃 / Sakata Nemuno","高丽野阿吽 / Komano Aunn","矢田寺成美 / Yatadera Narumi","尔子田里乃 / Nishida Satono","丁礼田舞 / Teireida Mai","摩多罗隐岐奈 / Matara Okina","森近霖之助 / Morichika Rinnosuke","朱鹭子 / Tokiko","水獭少女/ Kawauso no Shoujyo","桑尼米尔克 / Sunny Milk","露娜切露德 / Lunar Child","斯塔萨菲雅 / Star Sapphire","绵月丰姬 / Watatsuki no Toyohime","绵月依姬 / Watatsuki no Yorihime","铃仙二号 / Reisen","稗田阿求 / Hieda no Akyuu","茨木华扇 / Ibarakasen","本居小铃 / Motoori Kosuzu","易者 / The Fortune-teller","宇佐见莲子 / Usami Renko","玛艾露贝莉·赫恩 / Maribel Hearn(梅莉 / Merry)"}}, + {"性别",{"男","女"}}, {"人偶暗示",{"01 破 灭:不要想起才比较好的惨剧、恶意、背叛。但是,若想要理解如今的情况,除了将之回想起来没有别的办法……","02 绝 望:那是比现在更加残酷的日子。为了不再重复那样的过去,有把它回想起来的必要……","03 陷 阱:有什么突然造访,把你打入地狱,真是不讲理的命运啊。但是,如果连那个的内容都想不起来的话,无论是报复还是克服都做不到了。","04 人 偶:你被其他的什么推动着、驱使着、利用着。如果不了解过去的话,也就无法知晓现在的行动是否出于自己的意志。","05 罪 人:你犯下了无法偿还、无法原谅的罪孽。如果不能回想起来的话,也就无法做出补偿,洗净罪孽了。","06 丧 失:从前的你失去了什么东西,直到现在也没有寻回。不是生命和记忆,而是……其他的,更加重要的什么东西。","07 渴 望:有什么想要的东西,如果没有那个可不行,真让人着急啊。连想要的是什么也想不起来这件事也真让人着急啊。","08 反 转:现在的你和过去的你完全就是不同的两个人。应该回想起真正的自己,至于回到过去与否是另外的事。","09 希 望:你应该知道什么重要的事情。对于死灵法师或者世界来说那是极为重要的秘密。如果能把那个记忆取回来的话,或许……","00 幸 福:温暖的日子、被爱的喜悦、满足的时光。那幸福的日子,即便只能在心中回想,也想要找回来。"}}, {"人偶宝物",{"01 【 照 片 】人类尚存的时候拍摄的照片。被剪下的幸福碎片。或许是生前的你的照片也说不定。","02 【 书 】古老的破旧的损坏的污浊的书。你一遍又一遍读过的书。现在只刻着没有任何意义的文字。","03 【 小小的不死者 】罕见的小猫、乌鸦或老鼠的不死者,为什么会做出这样的东西来?嘛,或许是为了排遣寂寞吧。","04 【 坏 掉 的 部 件 】心存依恋的什么人的部件,或者是过去的自己的部件。已经不再使用的身体的一部分,或许还残留着人性。","05 【 小 镜 子 】小镜子。无论多少年都珍惜地使用者。即便不喜欢那其中映出的自己,它所映出的东西也是非常重要的。","06 【 人 偶 】 可爱的人偶。像现在的你一样不知道哪里坏掉的人偶。","07 【 布 娃 娃 】 可爱的布娃娃。但是经历了长久的战争,就连布娃娃也……","08 【 饰 品 】戒指或者项链一类,闪闪发光的漂亮的首饰。又或者是,只对你有价值的护身符……","09 【 篮 子 】可以放置在荒野中发现的,中意的零碎东西的篮子。但是到底要装些什么……或许连你也不知道。","00 【 可 爱 的 衣 服 】无论身体怎么改变,织入那件衣服中的可爱也不会变。穿着它的你,心灵也会恒久不变。"}}, {"人偶记忆碎片",{"01 蓝 天\n天空确实是蓝色的,而不是现在天空这样的阴沉浑浊的铅色。你所知晓的天空是无比辽阔的如洗碧空,它的存在曾是那样理所当然,现在却已经无法再见了。","02 母 亲 的 手\n你有被温暖的手拥抱过的记忆,而且你清楚的记得那是母亲的手。无论是面容和名字都无法想起,那个拥抱的温暖却似乎还残留着。但你想要拥抱的不是记忆,而是真实存在的那个她。","03 甜 蜜 的 唇\n还记得那柔软嘴唇的触感。那到底是在什么时候、和什么人接的吻早已忘得一干二净了,留下的只有四唇相触的感觉。现在与你相依的那些孩子们,会不会有谁的唇也同样甜蜜呢?","04 密 室\n躲在上锁的小房间里。外面有什么正四处寻找着你的身影。不能被发现,不能被发现——你尽可能蜷缩着。但似乎还是有什么逐渐靠近了大门。然后,你……","05 血 宴\n你一个人坐在散发着铁锈味的鲜红血池之中。人体的各种零件四处散落。那是谁的呢?又是谁做了这一切?为什么你会一个人这样坐在这里?难道说……","06 雨 中\n你站在倾盆大雨之中。大雨的声音和倾注而下的雨水遮住了周围的景色。这雨既不是黑色,也不含强酸,仅仅只是将你的身体濡湿,让你感到寒冷的雨水而已。虽然很难受,但却也让你感到十分怀念。","07 孤 立\n周围的每一个人都远远地窃笑着。你不知道自己做错了什么,又为什么被嘲笑,但你知道自己不想再见到那样的目光,你真的不想被现在的伙伴们丢下。","08 笑 容\n发自内心的笑容,非常幸福的笑容。哪个笑容从你的脑海中浮现。那是谁的笑容呢?重要的人的,还是亲人的?如果是镜中映出的自己的笑容的话就再好不过了。虽然不知道是谁的,但那笑容令你魂牵梦绕。","09 信\n从邮差那里收到的一封信。你确信那封信和自己的现状有着深刻的联系,但却想不起来信的内容。那封信到底写了些什么呢?又是哪个重要之人寄来的呢?还是说……","10 覆 盖 之 影\n巨大的黑影完全覆盖了你的身体,对你做了非常残酷的事情,只要回想起来就觉得头快要裂开了。憎恨,对,你无比憎恨那个影子,那一定就是让你苏醒过来的家伙,不会有错!","11 花 园\n盛开的花园。你在那里编织花冠,一边唱歌一边散步。置身于那片花海之中的时间是毋庸置疑的幸福,即便是现在,你偶尔也会沉浸在那记忆之中。","12 父 亲 的 臂\n你还记得父亲那强壮的双臂和他脸上胡茬的触感。你还记得自己那纤弱的身体被那双手拥抱的感觉。虽然有着那双手臂的人一定已经不在了,但那份温暖却还支撑着你的心。","13 恋 爱 之 花\n苦涩却又甜蜜的恋爱之心。虽然已经无法忆起所爱之人,但那份情感却还残留在心中。即便只是轻轻拂过心尖,那份酸楚也会令你颤抖。","14 诅 咒\n有个家伙绝对不能原谅,所以你怀着憎恨举行了仪式。每天都在诅咒他,永远不会停下。苏醒过来的你自己也被诅咒了吧?所以对那家伙的诅咒一定也成功了。要让那家伙也尝尝一样的滋味!","15 歌\n虽然不知道是怎么来的,但你的心中留有一首歌。即便在无意之中也会轻声哼唱,有时候也会稍微改变一下歌词。虽然仅仅只是一首歌,对你来说也是重要的东西。","16 蛋 糕\n甜甜的蛋糕塞满了你的嘴。细腻柔滑的奶油、色彩鲜艳的水果,还有柔软蓬松的蛋糕。在这个世界上已经再也找不到那种甜美了吧,但即便如此,你也还是想要再次品味。","17 火 焰\n熊熊燃烧的火焰拥抱着周围的一切。从那摇曳的火光之中,你所觉到的陶醉却较恐怖更甚一筹。真希望那火焰能再一次燃烧起来,使你沉醉其中啊,但是现在的世界上,就连能用来烧的东西都那么稀少……","18 割 伤\n你在做家务的时候,被少见的小刀或针划伤手指。即便只是稍微出了一点血,你也哭哭啼啼大吵大闹。现在的你根本不会在意那点小伤,就算身体四分五裂也……","19 白 色 房 间\n白色的房间、药物、注射、身着白衣的人们。那纤细的手臂,瘦弱的双腿,是属于你的身体吗?虽然活着却无法行动的你,虽然死了却得到自由的你,对你来说究竟哪一边才……","20 黑 色 宅 邸\n像是废墟一样的恐怖的黑色宅邸一次又一次地浮现在你的脑海中。虽然那里不能进入的,但记忆中的你却按耐不住自己的好奇心。进去之后……啊,那之后就想不起来了。","21 锁\n铁栅栏、锁、简陋的床铺,每日的苦痛。你是被扯去了翅膀的蝶。即便是已经死去的今天,也能够感觉到来自什么人的枷锁。虽然自以为得到了自由,却也终究只是扯线木偶。还是说,永远被驱使着就是你的宿命?","22 星 空\n在夜空中绽放光芒的是月和星,而你还记得过去那美丽的夜空。过去的夜是那么美丽,而现在的夜晚却只剩下黑暗。但比起那个,是无论黑暗有多么深沉也不会感觉不适的这双死者之眼,更令你感到哀伤。","23 少 女\n在你的身边有一位少女。虽然无论是她的名字还是面容,亦或是你们的关系都已忘却了,但她的笑容还留在你的心中。你是爱着她的,并且你也爱着有着相同笑容的伙伴们。","24 宝 物\n你有一个比任何东西都更加重要,非常非常珍惜的宝物。但那到底是什么呢?一定不是现在所拥有的【宝物】。你和那个东西,是被命运仅仅连在一起的。","25 葬 礼\n有什么人死掉了。大家都很悲伤,消沉,有人还哭了出来,而你又是怎样的呢?那张挂起来的大照片模模糊糊的看不清脸,但那个葬礼毫无疑问是你的重要之人的。","26 聚 会\n召集朋友、聚齐家人,那是非常非常快乐的聚会记忆,毋庸置疑的幸福时光。那实在是太过幸福了,对于只能想起这个的你来说,回忆与现实的差距实在太过于残酷。","27 生 命\n确实有新的生命寄宿在你的身体中。自己体内以外的生命为你带来了作为母亲的感动。但是你不只是个少女而已吗?还是说你的头脑和现在的外表是不同的人物?","28 宠 物 犬\n它虽然不是人类,却也是你重要的家人。那孩子的叫声、呼吸、舌头、毛皮的触感,还有它的名字,无论是哪一个都留你心中、手中。","29 翅 膀\n从很高很高的地方向下俯视。虽已经记不得地上的风景了,但你相信着自己能够在天空中飞翔而踏出了一步。在那之后又怎么样了呢?你真的飞起来了吗?","30 日 常\n虽然无聊却也温暖,恒久不变的幸福的的日常。你相信着这样的日子一定能持续到永远……但当你注意到的时候已经变成了这具身体、置身于这个世界了……到底发生了什么事了?","31 废 弃\n那是被破坏、被舍弃、被埋没的记忆。遭到了毫无理由的虐待,哭喊、愤怒、诅咒,然后终于放弃了一切。即便到了今天也一点儿都没有变。即便是未来也一定、一定不会出现任何希望。","32 谢 罪\n你伤害了很重要的人,你知道必须要道歉,但却连一句抱歉都还没有说出口。注意到的时候你已经死了,又重新活了过来,而那个人一定也是这样的。你必须向那个人道歉,必须要道歉。","33 财 欲\n具有不可思议的魔力纸片,只要是想要的东西就全能换来,那个名字的确是,“钱”。你曾经不择手段地收集着它,因为那个的数量就是人类的价值。这个世界哪里还会有那个呢……","34 死 去\n在你的面前,有一个生命结束了。对你来说,那是非常非常重要的生命。现在的你即使死了也还能行动,那条生命是否也遇到了同样的事情?","35 故 乡\n令人怀念的故乡风景。你在那里出生,在那里成长,在那里游玩。那个地方虽然已经不存在于世界上,但却还存在于你的心中。那是你无法忘却的重要风景,也是你最大的避风港……","36 心 愿\n没有实现的愿望,是不是就这样不要实现才更好?每当想起来的时候,内心深处都会传来剧痛。不可能会更好,怎么可能会更好呢。但是,你已经想不起来那个愿望究竟是什么了。","37 水\n你置身于水中,那是无比清澈的水。是在游泳吗?或者在潜水?又或者是投水自尽?无论如何,水与你都有着深切的关系。只要浸在水中,你就觉得非常幸福。","38 编 织 物\n你在编织着什么,是为谁而编的呢,编的又是什么呢?是围巾,手套还是毛衣呢……你的手指还记得要如何编织,只要有毛线和织针,现在也能编出什么来吧……","39 感 謝\n无论再怎么感谢也不为过的人,但就连“谢谢”这两个字可能也没能说出。如果能重逢的话,第一句话一定就是这个。但是……那个人究竟是谁,是什么样的人呢?","40 土 壤 的 味 道\n最喜欢照料花了。喜欢移植、喜欢施肥、喜欢浇水、喜欢玩弄土壤的你,还记得那充满生命的土壤的气味和花草的芬芳。但是在这个只有沙石的世界上,已经再也找不到……","41 神 灵\n接受祈祷的存在被称为“神”,你相信着只要祈祷的话就能够得到幸福。现在的你幸福吗?如果不够幸福的话,也许是因为你的祈祷还不够虔诚吧。","42 教 师\n黑板、椅子、课桌、讲台……大家或坐或站,纵情玩乐或者努力学习。真想回到那个房间啊,大家如今又身在何方呢,我现在……又身居何处呢?","43 被 窝\n在温暖的被窝之中,迷迷糊糊地在朝阳之中睡了个回笼觉。对你来说,没有比这更加幸福的事情了。记忆之中的被窝总是暖洋洋的,但是醒来之后的这个世界,到底怎么了呢?","44 梳 妆 台\n努力把映在镜中的自己的脸蛋打扮得漂漂亮亮的。第一次涂上口红的时候,变换崭新发型的时候、刚刚开始化妆的时候……但是,现在的你却一副只有死人的脸,只有一副随处可见的人偶的脸……","45 手 术 台\n被捆绑在手术台上的你恐惧地瞪大了眼睛。嘴不知道被什么堵上了,根本叫不出声来。浑身是血的医生靠近了,闪着光芒的手术刀接近了、你的皮肤、皮肤!","46 跟 踪 者\n有什么东西一直紧跟着你。异样的感觉不断积蓄,令你感到无比恐怖。那究竟是谁,究竟是什么,你一点都不知道。啊,窗户外面,外面!","47 嫉 妒\n好嫉妒好嫉妒啊!明明你是那么不幸,为什么大家都那么幸福而面带笑容呢?好嫉妒好嫉妒啊,就连那个时候依然幸福的自己,现在想起来也觉得嫉妒。","48 家 里 蹲\n外面太可怕了,大家都会伤害你。所以你只要待在这间小小的房间里就好了,根本不需要去到外面。啊啊,但是即便如此还是被强拉出来,外面果然好可怕啊,好想回到房间里。","49 洗 浴\n会喷出温暖热水的喷头、淋浴的时候响起的哼唱、肥皂的香气。你好想再洗一次澡啊,但是现在的这具身体,会在热水中完全崩解的吧,所以你只能叹息着度过每一天。","50 枪 声\n突然想起的爆破声,像是什么东西被烧焦的声音。你胸前一热,于是转过头去,然后你……接下来就想不起来了。不过,现在的你每天都能听到相似的爆破声。","51 图 书 馆\n整齐的书本、成排的题名。阅读是多么的愉快,学习是多么的愉快。知识虽并非价值,但却等同于价值。这个自成一体的寂静空间,就是你过去的容身之所。","52 假 面\n你说了谎,无论是谁你都不会相信,无论是谁你都无法相信。你信任现在的伙伴吗?虽然你知道必须要信任不可,虽然你知道,但是你……","53 孤 独\n一直都非常寂寞,一直都孤身一人,希望能得到朋友。现在这个世界虽然有很多讨厌的事情,但却有了能够信任的朋友。正因为有她们的存在,这个世界比过去更加美好。","54 演 奏\n你每天都演奏着乐器,但那个乐器已经不在手边,想要演奏的乐曲也已经不记得名字了。虽然还能哼唱,不过……不过只要能找回那个乐器的话,手指就能记起来要如何演奏那首曲子。","55 雪\n还记得白色的冰冷碎片会摇曳着从天而降,那是将所有的一切都用纯白覆盖隐藏起来的雪。现在的世界会从天而降的只有黑色的灰,白色的雪从天而降的日子已经再也不会有了吧。","56 运 动\n你喜欢活动身体。那并不是拼上性命的战斗,而是更加快乐地活动身体。这个不会疲劳不会痛苦也不会成长的身体,运动起来的话会有着怎样的感觉呢?","57 双 子\n你有着另外一半,那是和你同一天诞生,有着相同面容的孩子。你们两个之间有着不可思议的联系,不管对方在做什么都能知道。所以,即便在这个世界中,你也知道自己的另外一半身处何方。","58 笼 中 鸟\n被关起来的小鸟实在是太可怜了,所以你打开了笼子放飞了那只小鸟。现在的你,也是被关在这不死之躯中的小鸟。有没有人会可怜可怜你,也把你放飞呢?","59 玩 偶\n可爱的玩偶坏掉了,手脚向着奇怪的方向弯曲了、断裂了,好可怜啊……你有着这样的记忆。但是仔细想想的话,现在的你不正是那个玩偶吗?。","60 窗 外\n虽然已经记不起来窗外到底有什么,但有着眺望窗外的记忆。那里虽然寒冷,却比你所在的地方更加美丽,所以你一直憧憬着窗外。至少,现在的这里并不是那个窗外。","61 占 卜\n占卜运势的记忆,有什么人为你确定了运势,那一定是,关于你所期待的幸福未来的话语吧。或许那连祝福都不是,只是随口说说而已,现在却是支持着你的重要话语。","62 牵 手\n你与什么人手牵着手。虽然不记得对方是谁,但是从手中能传来踏实的安心感。如果只要指尖相触就能够安心的话,那就与现在的伙伴们手牵手吧。即便那只是冰冷的手,也足以令你感受到温暖。","63 饥 饿\n有着吃不到很想吃的东西的记忆。已经失去的食欲令你感到疼痛,肚子好饿,好想撕碎咀嚼点什么,好想吃好想吃好想吃,就连自己的手也好想吃。对了,那个时候的你难道……","64 凌 辱\n遭到凌辱的记忆,不断重复的屈辱。自尊被撕得粉碎,唯命是从,任由摆布。只要回响起这些就有什么在体内涌动着。把你唤回这个世界的东西,肯定和那些家伙没什么差别。","65 可 爱 衣 服\n记忆中有着可爱的衣服。虽然记不清楚面容,但你只要想到要把映在镜中的那件衣服把展示给什么人看,便觉得欢欣雀跃……但是,到底想穿给谁看呢?那件衣服,如今又在哪里呢?","66 料 理\n下厨准备饭菜。切碎蔬菜、搅拌大锅、打碎鸡蛋、翻炒肉片。虽然一开始什么都不会做,但是也渐渐熟练、熟练了……但是饭菜到底是什么味道却不记得了。做的,还好吃么……?","67 欺 负\n只是因为心情不好或一时兴起就对那个胆小鬼做了这样的事。和朋友们一起围住他随意欺负,拳打脚踢,扯着头发,用力敲头之类的。啊,那个时候好开心啊!","68 绘 画\n有一幅未完成的画。如果能画完的画,一定会被大家称赞的,那就是最美好的事情了。但是,那到底是怎样的一幅画,你已经想不起来了。明明是必须要画完的……","69 官 能\n情欲的火焰烧灼着你的身体,将你的肌肤染成绯色,沉浸在并非对爱而是对快乐的渴求之中。即便到了现在,心中也会隐隐作痛。但是,这个已死的身体,到底能不能满足你的欲望呢?","70 亡 者\n那是在哪里呢?你被什么东西不断追赶,悲鸣着慌不择路地逃跑。死者的手将你凄惨地活活撕得四分五裂。啊啊,那些家伙,就是不死者啊。就是那些家伙,把你的身体撕成了碎片。","71 迷 糊\n甜美的浅眠。虽然必须醒过来不可,但却没办法离开被窝。从窗户漏进来的朝阳、小鸟的啼鸣、虽然还睡着但却清醒的迷迷糊糊的感觉。但是,现在这个世界没有那些……","72 对 话\n还记得和朋友的漫无边际的对话。关于时尚、关于天气、讨厌的那家伙、喜欢的那个人、还有关于恋爱的事情,无论什么都能聊的那个时候……只要想起来,就会留下羡慕的泪水……","73 行 走 的 尸 体\n你哀悼着什么人的死。在你的面前死去,却想不起来究竟是谁的人。但是,啊,那个人的尸体爬了起来,开始行动。以为那个人复活过来的你,被那个人的手和牙袭击了。","74 游 戏\n不分昼夜地玩游戏。那是什么游戏,为了什么而玩着游戏,你都已经不记得了,只有一直,一直看着画面的记忆,只有不舍得离开房间,也不舍得睡觉的记忆。","75 售 出\n你卖掉了什么。是血液,头发,还是内脏?又或者是欲放的花蕾又或着是绽放的花朵?你把那个卖给了什么人。那个人得到了这个,也露出了笑容。而你把钱拿去……拿去做什么了呢?","76 努 力\n如果不努力学习,取的好成绩的话,就没办法向大家展示你的优秀了,就没办法展示了。你除了这个一无是处,完全的一无是处。不这么做的话,就没有、丝毫、价值。","77 幸 福 时 刻\n啊啊,真幸福。这样的幸福真好啊,真害怕这样的幸福会消失啊,因为不是梦境,而是真正的幸福。你还记得那如梦似幻的幸福时光,但却只是,“记得”而已。","78 埋 葬\n你被埋进了土中。包裹手脚的土是冰冷的,但随后又泛起微微暖意。虽然还有着意识,却不断被无情的泥土覆盖。身体已经没办法动了,随后脸也被埋了起来。你完全被埋进了土中。","79 购 物\n去买各种各样的东西。眺望着橱窗,一次又一次地确认自己的钱包。无比快乐的购物时间,那个时候陪伴着你的是谁呢?记忆中只留下了那时的快乐。","80 游 乐 园\n和家人一起、朋友一起、还是说恋人一起呢?那是关于又有趣又热闹的,像是异世界的游乐园的记忆。五彩缤纷的设施,非常幸福的人们。那一天究竟去了哪里呢?所留下来的痕迹还存在吗?","81 茶 会\n小鸟的鸣叫、美丽的庭院、白色的桌椅、从茶壶倒出来的红茶、香甜的曲奇、快乐的谈笑。那是以身为少女的你生活中的甜美记忆。是那个记忆让你依然保持着少女之心。","82 秘 密\n不会告诉任何人的秘密,因为那是非常可怕、非常羞耻、不能被知道的事情。啊,但是啊,就连你自己都忘记了自己的秘密,还有谁会知道呢?","83 花 圃\n你照料着花朵。施肥、浇水、除虫、然后花朵终于开放,结出果实。那虽然是持续很长时间的工作,却在你的记忆中静静流淌着。那个花圃现在如何了呢?","84 灵 异\n有着遇到了不明真身的什么东西的记忆。奇怪的声音、奇怪的影子、令人毛骨悚然的光影。那个时候的恐怖,放在今天就像童话惹人微笑。因为现在的你,已经变成为了过去的你所害怕的东西。","85 秘 密 地 点\n在阁楼里或壁橱中,你在那里做出了仅容一人的小世界。你躲在里面,躲在那个只属于你的世界之中。现在这里,是不是也有做出秘密地点的必要呢?","86 离 别\n你已经无法再和那个人相见了。离你而去的是一个非常非常重要的人。虽然现在还想不起来那是谁,但是一定能再想起来,因为只有那个人的事情,是你绝对不能忘记的。","87 故 事\n有着不知道是用小说还是用诗歌,写下了什么故事的记忆。你把那个故事写完了吗?那是你自己的故事吗?只要能够读一读,你一定能全部回想起来的。","88 哥 哥\n你有个温柔的哥哥,总是向他撒娇,一直憧憬着他。对你来说,她是最重要的人,也是理想的人。但是,他的名字的面容都想不起来,明明只要见到就肯定能想起来的……","89 迷 失\n你一个人走散了。你什么的不知道,只是一边哭着一边徘徊。不认识的道路,不认识的地方,无论哪里都是一片漆黑,周围都是不认识的人。但即便如此,那个时候也还有人在……","90 海 岸\n拍案的波浪,白色的沙滩。目之所及尽是辽阔的大海,有时还有鱼跃出水面,那是你记忆之中的大海。这个世界也一定是有海的,但那是你记忆之中那充满了生命的大海吗?","91 战 火\n为了逃避战火而四处逃亡,藏匿。四处都是纷飞的子弹和爆炸。逃亡令你失去了认知能力,只能迷茫地彷徨着。你把飞来的炮弹当成了飞近的小鸟,向它伸出了手。","92 操 弄 死 者\n重要的人死掉了。不,一定只是睡着了而已,会再醒过来的,一定能醒过来的。因为已经死去的你就是为此而醒过来的吧?但那个人又在哪里沉睡着呢?","93 药\n必须要吃药,必须要吃药,要坏掉了,要坏掉了,身体要坏掉了,心也要坏掉了,快点快点,药呢要呢,不快点找到的话啊啊啊啊啊啊啊啊","94 虫\n对了,你最讨厌虫子了。爬来爬去的种子,飞来飞去的虫子,你特别憎恨、特别厌恶那种东西。你一直都住在不会出现那种东西的房间里,但是现在……","95 死 亡 降 临\n面容和名字都想不起来,但是,有重要的人死掉了。死亡实在是太悲伤了,心中好像空了一个大洞一样。但是,在死掉之后又复活过来的现在,那个人如果能好好地安息的话就太好了。","96 谎 言\n你说谎了。虽然还想不起来那究竟是怎样的谎言,但是一定有某个人被你欺骗了,就那样被欺骗着死去了。对方一定直到今天也还不知道真相,如果能再次相遇的话,如果不道歉的话……","97 死 后 世 界\n你已经死掉了,这是毫无疑问的。那个时候,你所看到的是与这个世界不同另外一个世界……然后你就被强行拉了出来。真是的,人死掉的话就应该去到那个世界才对……","98 杀 戮 天 使\n你被人教导了要如何杀人。你对此不抱有丝毫疑问,至今为止已经不知道多少次地重复着杀人这件事。只要杀掉就能被表扬了。在现在的这个死不掉的世界,只要一直一直杀戮下去,就能够得到表扬了吧?","99 死 灵 法 师\n你稍微记得一点把你的身体变成现在这样的“那家伙”。你对那家伙,怀有谢意吗?纵然对“那家伙”来说,现在的你不过只是玩具而已?","00 最 终 战 争\n你究竟站在怎样的立场上呢?你有着作为旁观者,见证了人类终结的知识和记忆。到底发生了多少愚行和惨剧,虽然模模糊糊的,但是你确实了解。"}}, + {"人偶依恋",{"01【厌恶】\n无比激烈的恶意。理由的话怎样都好,对方的一举一动都令你感到憎恶。真烦人。\n发狂:敌对认识 “那种家伙要是坏掉就好了。”\n战斗中,未能命中敌人的攻击全部命中厌恶的对象(在射程之内的话)。命中的部位由受伤的一方任选。","02【独占】\n对对方抱有激烈的独占欲。那是只属于自己的东西,不想交给任何人。那是称不上爱情的邪恶欲望。\n发狂:独占冲动 “你的眼睛真是漂亮啊。”\n战斗开始时和战斗结束时,对方任选一个部件破坏。","03【依存】\n对你而言,那是必要的存在。如果没有那个人的话,你就什么都做不到。\n发狂:幼儿退行 「不是两个人的话……不行啊、好害怕……」\n你的最大行动值减少 2 点。","04【执着】\n不想从那个人的身边离开。那个人的身边就是就是你所在的地方。不想分开,永远都不想分开。\n发狂:追踪监视 「一直看着你。嘻嘻,一直……」\n战斗开始时和战斗结束时,对象对你的依恋增加 1 点狂气。(精神崩坏状态的话不需要处理)。","05【恋情】\n只要想着那个人就感到难过。不想被那个人讨厌,也挪不开眼睛,但是好羞啊……\n发狂:自伤行为 “如果那个人不会来看的话,这个身体就一点用处都没有……”\n战斗开始时和战斗结束时,你任选一个部件破坏。","06【对抗】\n只有那个人,绝不能输给她。并不是憎恨,只是绝不能输而已。永远持续着竞争。\n发狂:过剩竞争 “是我比较优秀,优秀就是优秀,真好啊!”\n战斗开始时和战斗结束时,你任选一项依恋增加 1 点狂气。(精神崩坏状态的话不需要处理)。","07【友情】\n作为朋友是很重要的人。只要是为了最好的朋友,你是什么都做得到的。\n发狂:共鸣依存 “脚没有了?没关系,我也和你一样哟。”\n游戏结束时,对象的损坏部件比你更多的话,就破坏你的部件直到数目相同为止。","08【保护】\n那个孩子太弱了,所以你必须要保护她。如果没有你的帮助的话,她一个人什么都做不到。\n发狂:随时紧贴 “不要离开我,你是要被我保护的!”\n战斗中,只要和依恋的对象处于不同的区域,就不能宣言“具有移动以外效果的动作”。另外,移动动作仅能将“自己和依恋的对象”作为目标。","09【憧憬】\n想拥有那样的风度。那是你憧憬的对象。那个人正是你理想中的姿态。\n发狂:赝作妄想 “骗人!姐姐大人才不会那样说话!你是假货吧,骗不了我的!”\n战斗中,只要和依恋的对象处于相同的区域,就不能宣言“具有移动以外效果的动作”。另外,移动动作仅能将“自己和依恋的对象”作为目标。","10【信赖】\n你和对方是一心同体的存在,无论是什么都能托付给她。只要和那个人在一起,就能静下心来。\n发狂:疑神疑鬼 “……有打算从后面偷袭吧?我是不会允许的!”\n除你以外的所有姐妹最大行动值减 1。"}}, {"英雄天赋",{"肉体天赋1 明察秋毫 进行侦查检定时获得一个奖励骰。","肉体天赋2 快速愈合 自然回复增加至每日3HP。","肉体天赋3 昏暗视觉 降低夜间侦查检定的难度等级,忽略在夜间射击时的惩罚骰。","肉体天赋4 耐力卓绝 进行体质检定时获得一个奖励骰,包括建立追逐时。","肉体天赋5 天生神力 进行力量检定时获得一个奖励骰,比如用来举起某人某物。","肉体天赋6 千杯不醉 可以花费5点幸运来避免过度饮酒带来的效果(无视技能惩罚)。","肉体天赋7 强健体魄 可以花费10点幸运使疾病和毒药的伤害和效果减半。","肉体天赋8 铁骨铮铮 可以花费10点幸运来吸收在一轮中收到的5点伤害。","肉体天赋9 耳听八方 进行聆听检定时获得一个奖励骰。","肉体天赋10 魅力四射 进行魅惑检定时获得一个奖励骰。","精神天赋1 坚定不移 无视攻击人类、目睹惨烈创伤或尸体的理智损失。","精神天赋2 百折不挠 可以花费幸运来避免等量的理智损失。","精神天赋3 钢铁意志 进行意志检定时获得一个奖励骰。","精神天赋4 一目十行 阅读书籍和神话典籍时,泛读和精读花费的时间减半。","精神天赋5 语言学家 可以了解遇到的是哪种语言或文字;进行语言检定时获得一个奖励骰。","精神天赋6 魔法亲和 学习法术花费的时间减半;进行施法检定时获得一个奖励骰。","精神天赋7 过目不忘 能够记住事件的诸多细节;进行知识(教育)检定时获得一个奖励骰。","精神天赋8 博学多才 获得学问技能的一个专攻项,如梦境学问、吸血鬼学问、狼人学问;需要向该技能分配职业或兴趣点数。","精神天赋9 灵能觉醒 获得一项灵能,如通灵、占卜、灵媒、心灵感应、念动力,见第六章;需要向该技能分配职业或兴趣点数。","精神天赋10 足智多谋 能够迅速整理线索;进行智力(不是灵感)检定时获得一个奖励骰。","战斗天赋1 处变不惊 不会被突袭。","战斗天赋2 专注打击 在格斗中,可以花费10点幸运来获得额外伤害骰,数量取决于所用武器。如徒手攻击+1D3,剑+1D6。","战斗天赋3 快速装填 选择一种武器,忽略使用该武器在同一回合装填并击发产生的惩罚骰。","战斗天赋4 身手敏捷 应对枪械而寻找掩体时,不会失去攻击机会。","战斗天赋5 目光如炬 忽略瞄准体型较小目标(体格-2)时产生的惩罚骰;忽略瞄准近战中的目标时产生的惩罚骰。","战斗天赋6 技巧卓绝 使用战技时,角色的体格视为+1。","战斗天赋7 疾风连击 在格斗中,可以花费10点幸运再进行一次攻击。","战斗天赋8 动如脱兔 在一整场战斗中,可以花费10点幸运来避免寡不敌众。","战斗天赋9 快速瞄准 决定回合轮次时,即使未准备好进行射击,亦视为获得+50DEX。","战斗天赋10 手枪专精 忽略手枪连射带来的惩罚骰。","其他天赋1 凶神恶煞 进行恐吓检定时降低一级难度等级,或者获得一个奖励骰,由守秘人判断。","其他天赋2 奇妙道具 游戏开始时获得一个奇妙道具,见怪奇技术。","其他天赋3 吉人天相 回复幸运时,额外投一个1D10。","其他天赋4 神话知识 游戏开始时获得10点克苏鲁神话技能。","其他天赋5 怪奇技术 可以制造和修理怪奇技术制品,见怪奇技术。","其他天赋6 遁入暗影 进行潜行检定时降低一级难度等级,或者获得一个奖励骰,由守秘人判断。如果目标未能察觉,在暴露之前可以进行两次突袭。","其他天赋7 能工巧匠 进行操作重型机械、机械维修和电气维修检定时降低一级难度等级,或者获得一个奖励骰,由守秘人判断。","其他天赋8 动物朋友 游戏开始时获得一只可靠的动物伙伴,比如猫、狗、鹦鹉;进行驯兽检定时获得一个奖励骰。","其他天赋9 伪装大师 进行乔装或技艺(表演)检定时,可以花费10点幸运来获得一个奖励骰;可以使用腹语,让声音听起来是从别处发出的;如果有人试图看穿伪装,其侦查或心理学检定提升为困难难度。","其他天赋10 早有准备 需要的东西似乎总在手边;可以花费10点幸运(而非幸运检定)在附近找到有用的道具,如手电筒、够长的绳索、武器等。"}}, {"调查员职业",{"会计师","杂技演员","演员-戏剧演员","演员-电影演员","事务所侦探、保安","精神病医生(古典)","动物训练师","文物学家(原作向)","古董商","考古学家(原作向)","建筑师","艺术家","精神病院看护","运动员","作家(原作向)","酒保","猎人","书商","赏金猎人","拳击手、摔跤手","管家、男仆、女仆","神职人员","程序员、电子工程师(现代)","黑客/骇客(现代)","牛仔","工匠","罪犯-刺客","罪犯-银行劫匪","罪犯-打手、暴徒","罪犯-窃贼","罪犯-欺诈师","罪犯-独行罪犯","罪犯-女飞贼(古典)","罪犯-赃物贩子","罪犯-赝造者","罪犯-走私者","罪犯-混混","教团首领","除魅师(现代)","设计师","业余艺术爱好者(原作向)","潜水员","医生(原作向)","流浪者","司机-私人司机","司机-司机","司机-出租车司机","编辑","政府官员","工程师","艺人","探险家(古典)","农民","联邦探员","消防员","驻外记者","法医","赌徒","黑帮-黑帮老大","黑帮-马仔","绅士、淑女","游民","勤杂护工","记者(原作向)-调查记者","记者(原作向)-通讯记者","法官","实验室助理","工人-非熟练工人","工人-伐木工","工人-矿工","律师","图书馆管理员(原作向)","技师","军官","传教士","登山家","博物馆管理员","音乐家","护士","神秘学家","旅行家","超心理学家","药剂师","摄影师-摄影师","摄影师-摄影记者","飞行员-飞行员","飞行员-特技飞行员(古典)","警方(原作向)-警探","警方(原作向)-巡警","私家侦探","教授(原作向)","淘金客","性工作者","精神病学家","心理学家、精神分析学家","研究员","海员-军舰海员","海员-民船海员","推销员","科学家","秘书","店老板","士兵、海军陆战队士兵","间谍","学生、实习生","替身演员","部落成员","殡葬师","工会活动家","服务生","白领工人-职员、主管","白领工人-中高层管理人员","狂热者","饲养员"}}, + {"调查员背景",{"个人描述:{个人描述}、{个人描述}、{个人描述}\n思想信念:{思想信念}\n重要之人:{重要之人}\n重要之人理由:{重要之人理由}\n意义非凡之地:{意义非凡之地}\n宝贵之物:{宝贵之物}\n特点:{调查员特点}"}}, {"煤气灯",{"任意选择一个有(D)记号的特征。","高龄(D):年龄追加[1D3*10+10]岁,参照6版标准规则,超过30岁后开始获得EDU加值,40岁以后开始对于身体属性造成减值。","优雅的岁数: 40岁开始对身体能力造成减值的规则改为从50岁开始。","白化病患者(D):STR,CON,SIZ,DEX,POW,APP中的任意一项减少3点。在明亮阳光下时【侦察】技能值减少[1D4-1]点,长时间受到光照的话会受到1点以上的HP伤害。白化病人在人群中很显眼并可能被他人用有色目光看待。","酒精中毒(D):CON-1。STR,DEX,POW,APP中任意一项减少1点。为了避免陷入酩酊大醉需要通过一个SAN CHECK。陷入疯狂的情况下,调查员可能会寻求酒精来逃避现实。","警戒:不易被惊吓到。潜伏时一直都保持着能够随时【侦察】或者【聆听】的状态。","同盟者:投掷一个D100=[d100]来决定同盟的力量/数量和出现的频率(D100的出点越大可能能够获得越有利的同盟)。用途不限。","双手灵活:调查员可以灵活的使用他的任意一只手而不会受到非惯用手的惩罚。","讨厌动物(D):技能和动物有关时技能成功率减少[1D6*5]点。","艺术天才:音乐,写作之类的艺术技能增加【INT*5】%。","运动:运动系技能获得加值=选择一个技能+30%,或者选择两个技能各+20%,或者选择三个技能各+10%。","夜视强化:日落西山后视觉相关惩罚只有常人的一半。","累赘(D):调查员出生于世家但是却没能达到家人的期待,或者不服管教。对于交涉系技能可能会造成影响而减少[1D3*10]%。","领导者资质:POW+[1D2],交涉系技能+【INT】*5%。","打斗者:【拳击】或者【擒拿】+[1D4*5]%,每回合可以进行两次【拳击】或者【擒拿】,攻击成功时+1点伤害。","笨拙(D):大失败的几率变成通常的2倍,并且大失败时可能会招致灾难。","收藏家:调查员有收集硬币,书,昆虫,艺术作品,宝石,古董之类的爱好。","身体障碍(D):失去了身体的一部分。投掷一个D6=[d6]。1~2=脚,3~4=手,5=头部(投掷D6=[d6],1~3=眼睛,4~6=耳朵),6=玩家自己选择。失去脚的话DEX-3,STR或者CON-1,MOVE只有常人的一半,所有运动系技能-25%。失去手腕的话STR-1,DEX-2,所有的操作系技能-15%,使用武器会受到限制。失去眼睛的话【侦察】和火器技能等全部-35%,另外投掷一个【幸运】,失败的话APP-[1D2]。失去耳朵的话APP-[1D3],【聆听】等和耳朵有关的技能全部-30%。","再投掷三次,由玩家选择其中一个作为特征。","再投掷三次,玩家和KP各选择一个特征。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","诅咒(D):调查员被吉普赛人,魔女,法师,外国原住民等施予了诅咒,诅咒效果等同【邪眼】咒文或者由KP决定。KP也可以决定解除诅咒的条件。","黑暗先祖(D):调查员具有邪恶的一族,外国人,食人族,甚至神话生物的血统。投掷一个D100=[d100],出点越大,血统也越可怖。","听觉障碍(D):【聆听】减少[1D4*5]%。","绝症缠身(D):调查员身患绝症(癌症,失明,梅毒,结核等),绝症对调查员造成恶劣影响,至少也失去了1点CON,如果病情继续恶化的话还会继续失去其他能力值。投掷一个D100=[d100]来决定剩余寿命,出点越大寿命越长。","钟楼怪人(D):调查员具有巨大的伤痕或者身体变形等特征,对APP造成至少减少[1D4]点影响。对交涉系技能也可能也造成影响【(失去的APP)*5%】。","酒豪:不易喝醉。酒精作为毒素处理的情况下, POT值只有他人的一半。","鹰眼:【侦察】增加[2D3*5]%。","敌人(D):有对调查员不利的敌人存在,投掷一个D100=[d100]来决定敌人的力量/数量,数值越大越恶劣。用途不限。","擅长武器:火器类射程+50%。近战类武器成功率+5%或者伤害增加[1D2]。并且武器不易被破坏(具有更多的耐久度),或者入手的武器具有比一般的武器更高的品质。","传家宝:调查员拥有绘画,书籍,武器,家具等具有高价值的宝物。也可能是模组中追加的宝物的持有人。","俊足:DEX+1。再投掷一个D6=[d6],1~4时MOVE+1,5~6时MOVE+2。","赌徒(D?):进行一次【幸运】鉴定。成功的话调查员获得【(INT+POW)*2】%的【赌博】技能。失败的话只有【INT或者POW*1】%的技能值,资产减少[1D6*10]%,并且调查员遇到赌博时需要通过一个SAN CHECK才能克制自己。","擅长料理:获得【(INT或者EDU)*5】%的【手艺(料理)】技能。","听力良好:【聆听】+[2D3*5]%。","洞察人心:【心理学】+ [2D3*5]%。","反应灵敏:投掷1D6=[d6]。1~3=DEX+1,4~5=DEX+2,6=DEX+3。","驱使动物:技能和动物有关时获得[1D6*5+5]的加值,例如骑马,驾驶马车,特定情况的藏匿,潜行等。","没有特征但是可以选择任意技能(可多选)获得总计[3D20]点技能加值。","玩家自己选择一个特征。","再投掷三次,玩家和KP各选择一个。","贪婪(D):对调查员来说金钱至上。任何状况下都优先考虑金钱。为此欺骗他人也是正常的,欺骗对象也包含其他调查员。","悲叹人生:SAN-[1D10],玩家和KP给调查员设定一个背景(失去爱人,子孙或者其他血亲的悲剧)。","憎恶(D):玩家和KP商议决定,调查员对于特定的国籍,人种或者宗教具有无理由的反感。调查员接触此类人群时会表现出敌意。","比马还要健壮:CON+[1D3]。","快乐主义者:追求个人的喜悦(美食,饮品,性,衣装,音乐,家具等)。为此浪费了[1D4*10+20]%的资产。通过一个【幸运】鉴定,失败的话因为这种放纵的生活而失去1点STR,CON,INT,POW,DEX或者APP。","骑手:[骑马]技能+[(1D6+1)*10]%。","易冲动(D):有不考虑后果轻率的行动的倾向。根据情况可能需要通过一个减半的【灵感】鉴定来使头脑冷静。","巧妙:二选一。A)【灵感】+10%,获得可以临时组装或者发明一些装置的能力。B)武器以外的操纵系技能获得加值,只选择一个技能的话+30%,选择2个技能各+20%,3个各+10%。","疯狂(D):SAN-[1D8]。玩家和KP商议给予调查员一个精神障碍。","土地勘测员:调查员对某一篇地域了解的非常详细(例:建筑配置,道路,商业,住民,历史等)。对应的区域应为都市某一块区域或者单个农村之类的较狭小的范围。对于这篇区域的详细情况调查员通过【知识】或者【灵感】鉴定即可知晓。","意志顽强:POW+[1D3],san也获得对应的上升。","花花公子:APP+[1D3],和异性交往有关的交涉技能+[1D3*10]%。","持有高额财产:调查员拥有某种具有巨大价值的东西(例:船只,工厂,房屋,矿山,大块的土地等)。这些东西可能需要调查员花费很大的时间和精力在这里,玩家和KP要慎重的决定。","语言学家:调查员即使语言不通也有可能和对象成功的交流,增加一个辅助技能【语言学家】,初期技能值为【INT或者EDU】*1%。","家人失踪:调查员有着失踪很久的家人,有可能会在模组中登场(例:兄弟/姐妹/或者其他亲人遭遇海难,死在海外,被其他亲戚带走等情况)。","忠诚:调查员不会抛弃自己的家人,朋友,伙伴,在力所能及的范围内一定会帮助他们。这种性格也使他和自己周围的人群交涉时获得10%的加值。","魔术素质:学习咒文时只需要正常的一半时间,成功率也增加【INT*1】%。","虽然没有特侦但是职业技能值获得额外的[3D20]的技能点。","玩家自己选择一个特征。","虽然没有特征,但是调查员的持有现金为通常规则的2倍。","魔术道具:KP可以给予调查员一个魔术道具(可以杀伤神话生物的附魔武器,召唤神话生物的专用道具,占卜用品,POW储藏器等等)。调查员如果想要知道这件道具的详细性质需要通过一个【POW*1】的鉴定。","射击名人(手枪,步枪以及霰弹枪中选择一项):选择的这项火器技能+[2D3*5]%。","认错人:调查员被频繁的被误认为其他人,通常都会是些有着恶评的人物(罪犯,身怀丑闻的恶人之类的)。模组中在合适的情况下【幸运】可能会被降为原本的一半(简单来说,调查员因为某些理由获得其他人的犯罪历史,恶名,通过诈骗获得的财富或者权力这样的身份或者特征)。","天气预报:通过一个【灵感】鉴定调查员就可以得知[1D6+1]小时里的正确天气情况。有多大的降雨量,下雨的场所,风级,持续时间等等。","对外观的强迫观念(D):APP+1,但是调查员为了让自己看起来亮丽动人而花费大量的金钱来购买华贵的服饰和饰物。储蓄和资产减半。","古书:调查员拥有和模组有关的重要书籍资料或者它的复印(例:杂志,黑魔术书籍,历史书,圣经,神话魔导书,地图等等)。KP可以决定这件道具的性质和价值。","试炼生还者(D):SAN-[1D6]。调查员拥有从恐怖环境中生还的经验(海难,战争,恐怖分子劫持,地震等等)。因为这个经历可能给调查员带来某种长久的影响(通常程度的恐怖症状,或者其他的精神障碍等)。","孤儿:调查员相依为命的家人都不在了,或者不知道自己真正的家人是谁。","其他语言:调查员可以追加获得一项其他语言技能。技能值为[1D4]*INT%。","野外活动爱好者:【导航】,【自然史】,【追踪】各增加[2D3*5+5]%、[2D3*5+5]%、[2D3*5+5]%。","寄托爱意:模组中登场的某位角色对调查员怀有憧憬。由KP决定是哪位角色,为什么以及怀有何种程度。","心怀爱意(D):调查员对其他角色怀有憧憬。由KP决定喜欢谁,为什么以及何种程度。","麻痹(D):调查员因精神,疾病等原因苦于身体抽搐,扭曲等症状。各鉴定一次【幸运】,失败的话减少[1D2]点DEX和1点APP。","超常现象经历:调查员曾经经历过难以说明的遭遇(幽灵,黑魔术,神话生物,超能力等)。玩家和KP讨论决定其内容并失去最多[1D6]点SAN值。","大肚子(D):这位调查员怎么说也太胖了点。鉴定一次【幸运】,失败的话投掷一个D6=[d6],1~3 CON-1,4~6 APP-1。","说服力:【劝说】+[2D3*5+5]%。","宠物:调查员有养狗,猫或者鸟类。","虽然没有特征但是任意技能获得[3D20]点技能点。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","虽然没有特征但是职业技能值额外获得[3D20]点技能点。","恐怖症/疯狂(D):调查员身患恐怖症状或者疯狂症状。参考6版标准规则随机决定症状,或者选择想要的症状。遭遇到自身症状根源的恐怖或者物品时,如果SAN CHECK失败,那么调查员将无法抑制自己的恐怖或者被魅惑。","权力/阶级/企业地位:调查员在政治,经济或者甚至军事环境里持有某种程度的权力。投掷D100=[d100],出点越大权力越大。企业地位影响融资,政治地位可能所属某种政府机关,军队地位远超本身拥有的军衔也说不定。【信用】+25%。详细的情况和KP商议决定。","以前的经验:玩家可以选择获得【(INT或者EDU)*5】%的职业技能点数。","预知梦:由KP决定,游戏中玩家会做一个预言未来的梦。这大概会需要一个【POW*3】的鉴定。梦境没有必须符合现实的必要,如果梦境中见到的景象十分恐怖的话那么会失去一些SAN值(现实中见到相同景象失去SAN值的10%左右)。鉴定失败的话玩家会获得错误的预言。","繁荣:调查员的年收入和资产变成2倍。[信用]增加[1D4*5]%。调查员的事业很成功,或者调查员给富翁,持有权力的人做事或者与他们共事。","心理测量:接触某些物体时(或者抵达某个地方时),通过一个POW*1的鉴定,成功的话可以窥视到这个物品/地方的过去。这个能力的正确度由KP决定。这个能力消耗1D6点MP。因为幻觉也可能失去SAN值(和上述的”预知梦”类似,损失通常的10%左右)。","健谈者:【快读交谈】+[2D4*5]%。调查员有着非常厉害的语言术,可以通过讲故事获得朋友的信任,降低敌人的敌意,赚到一顿免费的餐点也是可能的。","罕见的技能:调查员通过一个【INT*4】%的鉴定的话,可能会持有一些生活中完全不常见,或者一般来说不会有的技能。罕见的语言,格斗技,驾驶热气球之类,和KP商议决定。","红发:调查员有着一头好像燃烧着一般的红发,非常显眼(没有其他效果)。","评价(D?):鉴定一次【幸运】。成功的话调查员被人尊敬(设定其理由),调查员在自家所在的村子/都市中所有的交涉系技能获得15%的加值。【幸运】失败的话调查员获得极坏的评价,所有的交涉系技能-15%。KP也可以决定通过良好的业绩来抵消这个恶评。","报复追求者:调查员相信自己受到了不公正的待遇并且对导致自己受到这种恶意的对象进行报复行为。玩家和KP讨论决定敌人的真身。投掷一个D100=[D100]来决定敌人的强度和调查员受到这种不公正的程度。","伤痕:鉴定一次【幸运】。成功的话伤痕没有影响调查员的外观,甚至彰显其英勇也说不定。失败的话失去[1D3]点APP,交涉系技能也减少[1D3*5]%。","科学的精神:【灵感】+5%。并且选择一个思考类技能+30%并再选择2个思考系技能+20%或者所有其他思考系技能+10%。","秘密(D?):调查员有着决不能告诉别人的秘密。调查员的邻居可能会有些线索也说不定。调查员可能是个罪犯,间谍,或者卖国贼之类的也说不定。内容由玩家和KP商议决定。","秘密结社:调查员所属于秘密主义的团体,可能会是共济会,蔷薇十字团,神志主义者,炼金术师结社,光明会之类团体的一员。或者是地下医学研究者之类的犯罪/阴谋组织的一员。","自学:EDU+[1D3],并增加因此获得的技能值。","可疑的过去/绯闻(D):调查员过去曾经做过一些惹人怀疑的事情(卖淫,偷人等),或者曾经犯下过某些重大罪行。所有的交涉系技能减少[1D3*10]%。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","再投掷两次并获得那两个特征。","投掷三次,玩家和KP各选择一个特征。","病弱(D):CON-[1D3]。","巧妙的手法:[钳工]技能增加【DEX*5】%,可以在偷窃或者魔术的时候使用。","迟缓(D):MOVE-1。","失去名誉(D):探索者因为国籍,性别,人种,宗教或者过去的犯罪记录等原因失去了社会上的名誉地位。作为其影响,调查员可能减少自由活动时间甚至所有的交涉系技能减少[1D4*10]%甚至更多。具体的影响玩家和KP商议决定。","元军人:调查员获得【INT*5】点的技能点加到士兵的职业技能上。","咒文知识:由KP决定!调查员最多可以获知[1D3]种咒文。SAN值减少[1D6]点。","胆小(D):调查员见到血液或者流血就会感觉到身体不适,失去更多的SAN值。也可能因为疾病的原因无法靠近或通过流血现场。","坚毅:调查员不受到现实中的血迹或者流血的影响。遭遇血迹和流血时SAN损失为最小值,即使见到最残虐的场合(大量被撕裂的人,被猎奇杀死的尸体等)也最多只减少通常的一半。","比公牛还要强韧:STR+[1D3]。","迷信(D):调查员迷信不疑,依赖着护身符,仪式或者愚蠢的信念。遭遇超自然现象的时候比通常多损失1点SAN值,即使原本不损失的情况下可能变成损失1点。","同情心:调查员选择一个交涉系技能+30%或者选择两个各+20%,然后额外再选择一个+10%。","意外的帮手:调查员因为一些缘由拥有一个对自己忠实并帮助自己的协助者。KP来决定这个协助者的真身和影响(依旧可以D100来决定)。并且D100也决定其频率。","看不见的财产:调查员有一笔自己不知道的财产。这可能是亲人遗赠的或者理事会之类授予的。这可能会是一块土地,房屋或者事业。这依旧可以用D100来决定去价值程度。","虚弱(D):STR-[1D3]。","戴眼镜(D):调查员要看清东西必须戴眼镜。鉴定一个【幸运】,成功的话眼镜只在读书或者进行精细工作的时候才需要。失败的话会在激烈运动等情况时会感觉到不能自由行动。不戴眼镜的话和视觉关联的技能减少[1D3*10]%(这个惩罚即使幸运成功也一样)。","彬彬有礼:调查员的【信用】+10%,真是个有礼貌的绅士(淑女)。","孩子(D):调查员的年龄变成[10+2D3]岁。最大EDU变成【年龄的1/2+2】,DEX+1,STR,CON,APP中任意一项+1。玩家和KP商议决定,调查员大概依旧和家人住在一起,职业等也需要重新修正。","任意选择一项特征。","投掷两次,玩家任意选择其中一项特征。"}}, {"个人描述",{"结实的","英俊的","笨拙的","机灵的","迷人的","娃娃脸","聪明的","邋遢的","死人脸","肮脏的","耀眼的","书呆子","年轻的","疲倦脸","肥胖的","啤酒肚","长头发","苗条的","优雅的","稀烂的","矮壮的","苍白的","阴沉的","平庸的","乐观的","棕褐色","皱纹人","古板的","狐臭的","狡猾的","健壮的","娇俏的","筋肉人","魁梧的","迟钝的","虚弱的"}}, {"思想信念",{"1:你信仰并祈并一位大能。(例如毗沙门天、耶稣基督、海尔·塞拉西一世)","2:人类无需上帝。(例如坚定的无神论者,人文主义者,世俗主义者)","3:科学万能!科学万岁!你将选择其中之一。(例如进化论,低温学,太空探索)","4:命中注定。(例如因果报应,种姓系统,超自然存在)","5:社团或秘密结社的一员。(例如共济会,女协,匿名者)","6:社会坏掉了,而你将成为正义的伙伴。应斩除之物是?(例如毒品,暴力,种族歧视)","7:神秘依然在。(例如占星术,招魂术,塔罗)","8:诸君,我喜欢政治。(例如保守党,共产党,自由党)","9:“金钱就是力量,我的朋友,我将竭尽全力获取我能看到的一切。”(例如贪婪心,进取心,冷酷心)","10:竞选者/激进主义者。(例如女权运动人,平等主义家,工会权柄)"}}, @@ -61,7 +63,6 @@ namespace CardDeck {"小十字牌阵",{"\n过去:{塔罗牌} {%正逆}\n现在(左):{塔罗牌} {%正逆}\n现在(右):{塔罗牌} {%正逆}\n未来:{塔罗牌} {%正逆}"}}, {"六芒星牌阵",{"\n起因:{塔罗牌} {%正逆}\n现状:{塔罗牌} {%正逆}\n未来:{塔罗牌} {%正逆}\n对策:{塔罗牌} {%正逆}\n周遭:{塔罗牌} {%正逆}\n态度:{塔罗牌} {%正逆}\n结果:{塔罗牌} {%正逆}"}}, {"凯尔特十字牌阵",{"\n问题现状:{塔罗牌} {%正逆}\n障碍助力:{塔罗牌} {%正逆}\n理想状况:{塔罗牌} {%正逆}\n基础条件:{塔罗牌} {%正逆}\n过去状况:{塔罗牌} {%正逆}\n未来发展:{塔罗牌} {%正逆}\n自身现状:{塔罗牌} {%正逆}\n周围环境:{塔罗牌} {%正逆}\n希望恐惧:{塔罗牌} {%正逆}\n最终结果:{塔罗牌} {%正逆}"}}, -{"调查员背景",{"个人描述:{个人描述}\n思想信念:{思想信念}\n重要之人:{重要之人}\n重要之人理由:{重要之人理由}\n意义非凡之地:{意义非凡之地}\n宝贵之物:{宝贵之物}\n特点:{调查员特点}"}} }; //群聊牌堆 std::map> mGroupDeck; diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index 26a4cb0e..13cb6285 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -570,6 +570,7 @@ EVE_Enable(eventEnable) loadJMap(strFileLoc + "PrivateDeck.json", CardDeck::mPrivateDeck); loadJMap(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); loadJMap(strFileLoc + "PublicDeck.json", CardDeck::mPublicDeck); + loadJMap(strFileLoc + "ExternDeck.json", CardDeck::mPublicDeck); //读取替身模式 ifstream ifstreamStandByMe(strFileLoc + "StandByMe.RDconf"); if (ifstreamStandByMe) From f0169d3bed5f9adb768ddcd0369cab02677de9c0 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sun, 30 Jun 2019 22:45:57 +0800 Subject: [PATCH 07/33] =?UTF-8?q?=E9=BB=91=E5=90=8D=E5=8D=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鍏佽鑷姩妫鏌ラ粦鍚嶅崟 --- Dice/Dice.cpp | 72 ++++++++++++++---------- Dice/DiceConsole.cpp | 127 +++++++++++++++++++++++++++++++++++++++---- Dice/DiceConsole.h | 9 +++ Dice/DiceEvent.h | 84 +++++++++++++++++++++------- Dice/Jsonio.h | 42 +++++++++++--- 5 files changed, 264 insertions(+), 70 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index 13cb6285..cb264b88 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -247,12 +247,12 @@ EVE_Enable(eventEnable) for (auto it : AdminQQ) { MonitorList.insert({ it ,Private }); } - MonitorList.insert({ 624807593 ,Group }); - MonitorList.insert({ 941980833 ,Group }); MonitorList.insert({ 863062599 ,Group }); MonitorList.insert({ 192499947 ,Group }); + MonitorList.insert({ 754494359 ,Group }); } ifstreamMonitorList.close(); + getDiceList(); ifstream ifstreamCharacterProp(strFileLoc + "CharacterProp.RDconf"); if (ifstreamCharacterProp) { @@ -630,24 +630,21 @@ EVE_GroupMsg_EX(eventGroupMsg) intAuthCnt++; } } - if (BlackQQ.count(fromQQ) == 0) { - BlackQQ.insert(fromQQ); - AddMsgToQueue(format(GlobalMsg["strBlackQQAddNoticeReason"], { "群内禁言" + GlobalMsg["strSelfName"] }), fromQQ); - } - string strMsg = "在群\"" + getGroupList()[eve.fromGroup] + "\"(" + to_string(eve.fromGroup) + ")中," + eve.message + "\n已拉黑群主" + getStrangerInfo(fromQQ).nick + "(" + to_string(fromQQ) + "),另有管理员" + to_string(intAuthCnt) + "名" + strAuthList; + addBlackQQ(fromQQ, "群内禁言"); + string strNote = "在" + printGroup(eve.fromGroup) + "中," + eve.message; + string strMsg = strNote + "\n已拉黑群主" + getStrangerInfo(fromQQ).nick + "(" + to_string(fromQQ) + "),另有管理员" + to_string(intAuthCnt) + "名" + strAuthList; if (mGroupInviter.count(eve.fromGroup)) { long long llInviter = mGroupInviter[eve.fromGroup]; strMsg += "\n入群邀请者:" + printQQ(llInviter); - if (BlackQQ.count(llInviter) == 0) { - BlackQQ.insert(llInviter); - AddMsgToQueue(format(GlobalMsg["strBlackQQAddNoticeReason"], { "不负责任地邀请" + GlobalMsg["strSelfName"] }), llInviter); - } + addBlackQQ(llInviter, "不负责任地邀请"); } NotifyMonitor(strMsg); BlackGroup.insert(eve.fromGroup); if (WhiteGroup.count(eve.fromGroup))WhiteGroup.erase(eve.fromGroup); //setGroupLeave(eve.fromGroup); - string strInfo = "{\"LoginQQ\":\"" + to_string(getLoginQQ()) + "\",\"fromGroup\":" + to_string(eve.fromGroup) + "\",\"Type\":\"banned\",\"fromQQ\":\"" + to_string(fromQQ) + "\""; + string strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + ",\n\"type\":\"ban\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":" + to_string(getLoginQQ()) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; + if (getGroupMemberInfo(eve.fromGroup, getLoginQQ()).permissions == 2)strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + "\",\n\"type\":\"ban\",\n\"fromQQ\":\"" + to_string(fromQQ) + "\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":\"" + to_string(getLoginQQ()) + "\",\n\"masterQQ\":\"" + to_string(masterQQ) + "\",\n\"note\":\"" + eve.message + "\"\n}"; + NotifyMonitor(strWarning); } else return; } @@ -666,11 +663,12 @@ EVE_DiscussMsg_EX(eventDiscussMsg) setDiscussLeave(eve.fromDiscuss); return; } - if (eve.isSystem()) { - NotifyMonitor("在讨论组" + to_string(eve.fromDiscuss) + "中," + eve.message); - return; + if (BlackQQ.count(eve.fromQQ)) { + string strMsg = "发现黑名单用户" + printQQ(eve.fromQQ) + ",自动执行退群"; + AddMsgToQueue(strMsg, eve.fromDiscuss, Discuss); + Sleep(1000); + sendAdmin(printChat({ eve.fromDiscuss,Discuss }) + strMsg); } - DiscussList[eve.fromDiscuss] = tNow; FromMsg Msg(eve.message, eve.fromDiscuss, Discuss, eve.fromQQ); if (Msg.DiceFilter())eve.message_block(); Msg.FwdMsg(eve.message); @@ -709,9 +707,20 @@ EVE_System_GroupMemberIncrease(eventGroupMemberIncrease) } AddMsgToQueue(strReply, fromGroup, Group); } + if (beingOperateQQ != getLoginQQ() && BlackQQ.count(beingOperateQQ)) { + string strNote = printGroup(fromGroup) + "发现黑名单用户" + printQQ(beingOperateQQ) + "入群"; + if (WhiteGroup.count(fromGroup))strNote += "(群在白名单中)"; + else if(getGroupMemberInfo(fromGroup,getLoginQQ()).permissions>1)strNote += "(群内有权限)"; + else { + AddMsgToQueue("发现黑名单用户" + printQQ(beingOperateQQ) + "入群,将预防性退群", Group); + Sleep(100); + setGroupLeave(fromGroup); + } + } else if(beingOperateQQ == getLoginQQ()){ if (BlackGroup.count(fromGroup)) { AddMsgToQueue(GlobalMsg["strBlackGroup"], fromGroup, Group); + setGroupLeave(fromGroup); } else if (boolPreserve&&WhiteGroup.count(fromGroup)==0) { //避免小群绕过邀请没加上白名单 @@ -737,29 +746,32 @@ EVE_System_GroupMemberIncrease(eventGroupMemberIncrease) EVE_System_GroupMemberDecrease(eventGroupMemberDecrease) { if (beingOperateQQ == getLoginQQ()) { + string strNow = printSTime(stNow); mLastMsgList.erase({ fromGroup ,Group }); - string strMsg = printQQ(fromQQ) + "将" + GlobalMsg["strSelfName"] + "移出了群" + to_string(fromGroup) + "!"; + string strNote = strNow + " " + printQQ(fromQQ) + "将" + GlobalMsg["strSelfName"] + "移出了群" + to_string(fromGroup); if (mGroupInviter.count(fromGroup)) { long long llInviter = mGroupInviter[fromGroup]; - strMsg += "\n入群邀请者:" + printQQ(llInviter); - if (BlackQQ.count(llInviter) == 0) { - BlackQQ.insert(llInviter); - AddMsgToQueue(format(GlobalMsg["strBlackQQAddNoticeReason"], { "不负责任地邀请" + GlobalMsg["strSelfName"] }), llInviter); - } - } - NotifyMonitor(strMsg); - if (WhiteQQ.count(fromQQ)) { - WhiteQQ.erase(fromQQ); + strNote += ",入群邀请者:" + printQQ(llInviter); + addBlackQQ(llInviter, strNote); } - if (BlackQQ.count(fromQQ) == 0) { - BlackQQ.insert(fromQQ); - AddMsgToQueue(format(GlobalMsg["strBlackQQAddNoticeReason"], { "移出" + GlobalMsg["strSelfName"] }), fromQQ); + if (WhiteGroup.count(fromGroup)) { + WhiteGroup.erase(fromGroup); } + BlackGroup.insert(fromGroup); + string strWarning = "!warning{\n\"fromGroup\":" + to_string(fromGroup) + ",\n\"type\":\"kick\",\n\"fromQQ\":" + to_string(fromQQ) + ",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(beingOperateQQ) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; + NotifyMonitor(strWarning); + addBlackQQ(fromQQ, strNote, strWarning); + } + else if (mDiceList.count(beingOperateQQ) && subType == 2) { + string strNow = printSTime(stNow); + string strNote = strNow + " " + printQQ(fromQQ) + "将" + printQQ(beingOperateQQ) + "移出了群" + to_string(fromGroup); + string strWarning = "!warning{\n\"fromGroup\":" + to_string(fromGroup) + ",\n\"type\":\"kick\",\n\"fromQQ\":" + to_string(fromQQ) + ",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(beingOperateQQ) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; + NotifyMonitor(strWarning); if (WhiteGroup.count(fromGroup)) { WhiteGroup.erase(fromGroup); } BlackGroup.insert(fromGroup); - string strInfo = "{\"LoginQQ\":\"" + to_string(getLoginQQ()) + "\",\"fromGroup\":" + to_string(fromGroup) + "\",\"Type\":\"kicked\",\"fromQQ\":\"" + to_string(fromQQ) + "\""; + addBlackQQ(fromQQ, strNote, strWarning); } return 0; } diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 9fd0c622..5e0fca51 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -26,6 +26,8 @@ #include "GlobalVar.h" #include "MsgFormat.h" #include "NameStorage.h" +#include "DiceNetwork.h" +#include "jsonio.h" using namespace std; using namespace CQ; @@ -43,6 +45,8 @@ set MonitorList = {}; bool boolPreserve = false; //禁用讨论组 bool boolNoDiscuss = false; +//骰娘列表 +std::map mDiceList; //讨论组消息记录 std::map DiscussList; //群邀请者 @@ -76,7 +80,9 @@ std::map mGroupInviter; strClock += to_string(clock.second); return strClock; } - +std::string printSTime(SYSTEMTIME st){ + return to_string(st.wYear) + "/" + to_string(st.wMonth) + "/" + to_string(st.wDay) + " " + to_string(st.wHour) + ":" + to_string(st.wMinute) + ":" + to_string(st.wSecond); +} //打印用户昵称QQ string printQQ(long long llqq) { return getStrangerInfo(llqq).nick + "(" + to_string(llqq) + ")"; @@ -101,6 +107,16 @@ std::map mGroupInviter; } return ""; } +//获取骰娘列表 +void getDiceList() { + std::string list; + if (!Network::GET("shiki.stringempty.xyz", "/DiceList", 80, list)) + { + sendAdmin(("获取骰娘列表时遇到错误: \n" + list).c_str(), 0); + return; + } + readJson(list, mDiceList); +} void sendAdmin(std::string strMsg, long long fromQQ) { string strName = fromQQ ? getName(fromQQ) : ""; if(AdminQQ.count(fromQQ)) { @@ -118,13 +134,60 @@ std::map mGroupInviter; } } - void NotifyMonitor(std::string strMsg) { +void NotifyMonitor(std::string strMsg) { if (!boolMasterMode)return; for (auto it : MonitorList) { AddMsgToQueue(strMsg, it.first, it.second); } } - //简易计时器 +//拉黑用户后搜查群 +void checkBlackQQ(long long llQQ, std::string strWarning) { + map GroupList = getGroupList(); + string strNotice; + int intCnt = 0; + for (auto eachGroup : GroupList) { + if (getGroupMemberInfo(eachGroup.first, llQQ).QQID == llQQ) { + strNotice += "\n" + printGroup(eachGroup.first); + if (getGroupMemberInfo(eachGroup.first, llQQ).permissions < getGroupMemberInfo(eachGroup.first, getLoginQQ()).permissions) { + strNotice += "对方群权限较低"; + } + else if (getGroupMemberInfo(eachGroup.first, llQQ).permissions > getGroupMemberInfo(eachGroup.first, getLoginQQ()).permissions) { + AddMsgToQueue(strWarning, eachGroup.first, Group); + AddMsgToQueue("发现新增黑名单成员" + printQQ(llQQ) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first, Group); + strNotice += "对方群权限较高,已退群"; + Sleep(1000); + setGroupLeave(eachGroup.first); + } + else if (WhiteGroup.count(eachGroup.first)) { + strNotice += "群在白名单中"; + } + else { + AddMsgToQueue(strWarning, eachGroup.first, Group); + AddMsgToQueue("发现新增黑名单成员" + printQQ(llQQ) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first, Group); + strNotice += "已退群"; + Sleep(1000); + setGroupLeave(eachGroup.first); + } + intCnt++; + } + } + if (intCnt) { + strNotice = "已清查与" + printQQ(llQQ) + "共同群聊" + to_string(intCnt) + "个:" + strNotice; + sendAdmin(strNotice); + } +} +//拉黑用户 +void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { + if (llQQ == masterQQ || AdminQQ.count(llQQ) || llQQ == getLoginQQ())return; + if (WhiteQQ.count(llQQ))WhiteQQ.erase(llQQ); + if (BlackQQ.count(llQQ) == 0) { + BlackQQ.insert(llQQ); + strReason.empty() ? AddMsgToQueue(GlobalMsg["strBlackQQAddNotice"], llQQ) + : AddMsgToQueue(format(GlobalMsg["strBlackQQAddNoticeReason"], { strReason }), llQQ); + } + checkBlackQQ(llQQ, strNotice); +} +//简易计时器 void ConsoleTimer() { while (Enabled) { GetLocalTime(&stNow); @@ -139,13 +202,17 @@ std::map mGroupInviter; boolDisabledGlobal = false; NotifyMonitor(GlobalMsg["strSelfName"] + GlobalMsg["strClockToWork"]); } + if (stNow.wHour == 5 && stNow.wMinute == 0) { + getDiceList(); + clearGroup("black"); + } } - Sleep(10000); + Sleep(100); } } //一键清退 - int clearGroup(string strPara,long long) { + int clearGroup(string strPara,long long fromQQ) { int intCnt=0; string strReply; map GroupList=getGroupList(); @@ -158,10 +225,10 @@ std::map mGroupInviter; intCnt++; } } - strReply = "筛除无群权限群聊" + to_string(intCnt) + "个√"; + strReply = GlobalMsg["strSelfName"] + "筛除无群权限群聊" + to_string(intCnt) + "个√"; sendAdmin(strReply); } - else if (isdigit(strPara[0])) { + else if (isdigit(static_cast(strPara[0]))) { int intDayLim = stoi(strPara); string strDayLim = to_string(intDayLim); time_t tNow = time(NULL);; @@ -188,9 +255,49 @@ std::map mGroupInviter; intCnt++; } } - strReply += "筛除潜水" + strDayLim + "天群聊" + to_string(intCnt) + "个√"; + strReply += GlobalMsg["strSelfName"] + "已筛除潜水" + strDayLim + "天群聊" + to_string(intCnt) + "个√"; AddMsgToQueue(strReply,masterQQ); } + else if (strPara == "black") { + for (auto eachGroup : GroupList) { + if (BlackGroup.count(eachGroup.first)) { + strReply += "\n" + printGroup(eachGroup.first) + ":" + "黑名单群"; + } + vector MemberList = getGroupMemberList(eachGroup.first); + for (auto eachQQ : MemberList) { + if (BlackQQ.count(eachQQ.QQID)) { + if (getGroupMemberInfo(eachGroup.first, eachQQ.QQID).permissions < getGroupMemberInfo(eachGroup.first, getLoginQQ()).permissions) { + continue; + } + else if (getGroupMemberInfo(eachGroup.first, eachQQ.QQID).permissions > getGroupMemberInfo(eachGroup.first, getLoginQQ()).permissions) { + AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first); + strReply += "\n" + printGroup(eachGroup.first) + ":" + printQQ(eachQQ.QQID) + "对方群权限较高"; + Sleep(10); + setGroupLeave(eachGroup.first); + break; + } + else if (WhiteGroup.count(eachGroup.first)) { + continue; + } + else { + AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first); + strReply += "\n" + printGroup(eachGroup.first) + ":" + printQQ(eachQQ.QQID); + Sleep(100); + setGroupLeave(eachGroup.first); + break; + } + intCnt++; + } + } + } + if (intCnt) { + strReply = GlobalMsg["strSelfName"] + "已按黑名单清查群聊" + to_string(intCnt) + "个:" + strReply; + sendAdmin(strReply); + } + else if (fromQQ) { + sendAdmin(GlobalMsg["strSelfName"] + "未发现涉黑群聊"); + } + } else if (strPara == "preserve") { for (auto eachGroup : GroupList) { if (getGroupMemberInfo(eachGroup.first, masterQQ).QQID != masterQQ&&WhiteGroup.count(eachGroup.first)==0) { @@ -201,11 +308,11 @@ std::map mGroupInviter; intCnt++; } } - strReply = "筛除白名单外群聊" + to_string(intCnt) + "个√"; + strReply = GlobalMsg["strSelfName"] + "筛除白名单外群聊" + to_string(intCnt) + "个√"; sendAdmin(strReply); } else - AddMsgToQueue("无法识别筛选参数×",masterQQ); + AddMsgToQueue("无法识别筛选参数×", fromQQ); return intCnt; } diff --git a/Dice/DiceConsole.h b/Dice/DiceConsole.h index 69b2c29e..e61f85fc 100644 --- a/Dice/DiceConsole.h +++ b/Dice/DiceConsole.h @@ -31,6 +31,8 @@ extern bool boolPreserve; //自动退出一切讨论组 extern bool boolNoDiscuss; + //骰娘列表 + extern std::map mDiceList; //讨论组消息记录 extern std::map DiscussList; //个性化语句 @@ -47,6 +49,8 @@ extern std::set WhiteQQ; //黑名单用户:无条件禁用 extern std::set BlackQQ; + //获取骰娘列表 + void getDiceList(); //通知管理员 void sendAdmin(std::string strMsg, long long fromQQ = 0); //通知监控窗口 @@ -68,9 +72,14 @@ //下班时间 extern std::pair ClockOffWork; std::string printClock(std::pair clock); + std::string printSTime(SYSTEMTIME st); std::string printQQ(long long); std::string printGroup(long long); std::string printChat(chatType); +//拉黑用户后检查群 +void checkBlackQQ(long long, std::string strWarning = ""); +//拉黑用户 +void addBlackQQ(long long, std::string strReason = "", std::string strNotice = ""); extern void ConsoleTimer(); #endif /*Dice_Console*/ diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 9711a643..2117d61b 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -111,29 +111,33 @@ class FromMsg { } } int AdminEvent(string strOption) { - if (strOption == "delete") { - AdminNotify("已经放弃管理员权限√"); - MonitorList.erase({ fromQQ,Private }); - AdminQQ.erase(fromQQ); - return 1; - } - else if (strOption == "state") { - string strReply = getLoginNick(); - strReply = strReply + "的当前情况" + "\n" + if (strOption == "state") { + strReply = GlobalMsg["strSelfName"] + "的当前情况" + "\n" + + "Master:" + printQQ(masterQQ) + "\n" + (ClockToWork.first < 24 ? "定时开启" + printClock(ClockToWork) + "\n" : "") + (ClockOffWork.first < 24 ? "定时关闭" + printClock(ClockOffWork) + "\n" : "") + (boolPreserve ? "私用模式" : "公用模式") + "\n" + (boolNoDiscuss ? "禁用讨论组" : "启用讨论组") + "\n" + "全局开关:" + (boolDisabledGlobal ? "禁用" : "启用") + "\n" + "全局.me开关:" + (boolDisabledMeGlobal ? "禁用" : "启用") + "\n" - + "全局.jrrp开关:" + (boolDisabledJrrpGlobal ? "禁用" : "启用") + "\n" - + "所在群聊数:" + to_string(getGroupList().size()) + "\n" + + "全局.jrrp开关:" + (boolDisabledJrrpGlobal ? "禁用" : "启用") + "\n"; + if (isAdmin) strReply += "所在群聊数:" + to_string(getGroupList().size()) + "\n" + (DiscussList.size() ? "有记录的讨论组数:" + to_string(DiscussList.size()) + "\n" : "") + "黑名单用户数:" + to_string(BlackQQ.size()) + "\n" + "黑名单群数:" + to_string(BlackGroup.size()) + "\n" + "白名单用户数:" + to_string(WhiteQQ.size()) + "\n" + "白名单群数:" + to_string(WhiteGroup.size()); - reply(strReply); + reply(); + return 1; + } + if (!isAdmin) { + reply(GlobalMsg["strNotAdmin"]); + return -1; + } + if (strOption == "delete") { + AdminNotify("已经放弃管理员权限√"); + MonitorList.erase({ fromQQ,Private }); + AdminQQ.erase(fromQQ); return 1; } else if (strOption == "on") { @@ -477,10 +481,8 @@ class FromMsg { reply(printQQ(llTargetID) + "已加入" + GlobalMsg["strSelfName"] + "的黑名单!"); } else { - BlackQQ.insert(llTargetID); + addBlackQQ(llTargetID, strReason); AdminNotify("已将" + printQQ(llTargetID) + "加入黑名单√"); - strReason.empty() ? AddMsgToQueue(GlobalMsg["strBlackQQAddNotice"], llTargetID) - : AddMsgToQueue(format(GlobalMsg["strBlackQQAddNoticeReason"], { strReason }), llTargetID); } } } while (llTargetID = readID()); @@ -499,7 +501,7 @@ class FromMsg { } if (strOption == "groupclr") { std::string strPara = readRest(); - int intGroupCnt = clearGroup(strPara); + int intGroupCnt = clearGroup(strPara, fromQQ); return 1; } else if (strOption == "delete") { @@ -552,7 +554,7 @@ class FromMsg { else return AdminEvent(strOption); return 0; } - bool DiceReply() { + int DiceReply() { intMsgCnt++ ; int intT = (int)fromType; while (isspace(static_cast(strMsg[intMsgCnt]))) @@ -597,7 +599,46 @@ class FromMsg { } return 1; } - if (strLowerMessage.substr(intMsgCnt, 6) == "master"&&boolMasterMode) { + else if (strLowerMessage.substr(intMsgCnt, 7) == "warning") { + if (isAdmin || mDiceList.count(fromQQ)) { + intMsgCnt += 7; + string strWarning = readRest(); + nlohmann::json jInfo = { {"fromGroup",0},{"time","Unknown"},{"fromQQ",0},{"note","" } }; + try { + jInfo = nlohmann::json::parse(GBKtoUTF8(strWarning)); + } + catch (...) { + return -1; + } + string type = UTF8toGBK(jInfo["type"]); + string time = UTF8toGBK(jInfo["time"]); + string note = UTF8toGBK(jInfo["note"]); + long long blackQQ = jInfo["fromQQ"]; + long long blackGroup = jInfo["fromGroup"]; + if (type != "ban" && type != "kick" || (blackGroup&&BlackGroup.count(blackGroup)) && (blackQQ&&BlackQQ.count(blackQQ))) { + return 1; + } + if (!isAdmin)sendAdmin("来自" + printQQ(fromQQ) + ":" + strWarning); + strWarning = "!warning" + strWarning; + if (blackGroup) { + BlackGroup.insert(blackGroup); + if (!intT && blackGroup == fromGroup) { + setGroupLeave(fromGroup); + } + else if(getGroupList().count(blackGroup)){ + AddMsgToQueue(strWarning, blackGroup, Group); + Sleep(100); + setGroupLeave(blackGroup); + } + } + if (blackQQ) { + addBlackQQ(blackQQ, note, strWarning); + } + return 1; + } + else return 0; + } + else if (strLowerMessage.substr(intMsgCnt, 6) == "master"&&boolMasterMode) { intMsgCnt += 6; if (masterQQ == 0) { masterQQ = fromQQ; @@ -923,7 +964,7 @@ class FromMsg { else if (strLowerMessage.substr(intMsgCnt, 5) == "admin") { intMsgCnt += 5; - if(isAdmin)return AdminEvent(readPara()); + return AdminEvent(readPara()); } else if (strLowerMessage.substr(intMsgCnt, 5) == "coc7d" || strLowerMessage.substr(intMsgCnt, 4) == "cocd") { @@ -1758,8 +1799,8 @@ class FromMsg { string strMessage = strMsg.substr(intMsgCnt); if (strMessage == "NULL")strMessage = ""; EditedMsg[strName] = strMessage; - GlobalMsg[strName] = (strName == "strHlpMsg") ? Dice_Short_Ver + "\n" + strMsg : strMessage; - AdminNotify("已自定义" + strName + "的文本"); + GlobalMsg[strName] = (strName == "strHlpMsg") ? Dice_Short_Ver + "\n" + strMessage : strMessage; + isMaster ? reply("已自定义" + strName + "的文本") : AdminNotify("已自定义" + strName + "的文本"); } } else { @@ -3303,6 +3344,7 @@ class FromMsg { while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; } string readRest() { + readSkipSpace(); return strMsg.substr(intMsgCnt); } //读取参数(统一小写) diff --git a/Dice/Jsonio.h b/Dice/Jsonio.h index c3cbe741..e3a71dae 100644 --- a/Dice/Jsonio.h +++ b/Dice/Jsonio.h @@ -6,12 +6,12 @@ #include "EncodingConvert.h" template -T readJson(std::string strJson) { +typename std::enable_if::value, T>::type readJson(std::string strJson) { return UTF8toGBK(strJson); } -template<> -long long readJson(std::string strJson) { +template +typename std::enable_if::value, T>::type readJson(std::string strJson) { return stoll(strJson); } @@ -23,13 +23,36 @@ std::vector readJVec(std::vector vJson) { } return vTmp; } +template +int readJson(std::string strJson, std::map &mapTmp) { + nlohmann::json j; + int intCnt; + try { + j = nlohmann::json::parse(strJson); + } + catch (...) { + return -1; + } + for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) + { + T1 tKey = readJson(it.key()); + T2 tVal = readJson(it.value()); + mapTmp[tKey] = tVal; + intCnt++; + } + return intCnt; +} template int loadJMap(std::string strLoc, std::map> &mapTmp) { std::ifstream fin(strLoc); if (fin) { nlohmann::json j; - fin >> j; + try { + fin >> j; + }catch(...){ + return -1; + } for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) { T1 tKey = readJson(it.key()); @@ -40,12 +63,13 @@ int loadJMap(std::string strLoc, std::map> &mapTmp) { } return 0; } - -std::string writeJson(std::string strJson) { +template +std::string writeJson(typename std::enable_if::value, T>::type strJson) { return GBKtoUTF8(strJson); } -std::string writeJson(long long llJson) { +template +std::string writeJson(typename std::enable_if::value, T>::type llJson) { return std::to_string(llJson); } @@ -53,7 +77,7 @@ template std::vector writeJVec(std::vector vJson) { std::vector vTmp; for (auto it : vJson) { - vTmp.push_back(writeJson(it)); + vTmp.push_back(writeJson(it)); } return vTmp; } @@ -65,7 +89,7 @@ int saveJMap(std::string strLoc, std::map> mapTmp) { if (fout) { nlohmann::json j; for (auto it : mapTmp) { - j[writeJson(it.first)] = writeJVec(it.second); + j[writeJson(it.first)] = writeJVec(it.second); } fout << j; fout.close(); From 5d12e36d320f0b9494609eb3d29dc5eb287a9219 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sun, 30 Jun 2019 23:49:46 +0800 Subject: [PATCH 08/33] =?UTF-8?q?.group=E6=96=87=E6=9C=AC=E5=A4=84?= =?UTF-8?q?=E7=90=86=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/DiceEvent.h | 35 +++++++++++++++-------------------- Dice/GlobalVar.cpp | 1 + 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 2117d61b..d8ce26b8 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -990,13 +990,7 @@ class FromMsg { intMsgCnt += 5; while (isspace(static_cast(strLowerMessage[intMsgCnt]))) intMsgCnt++; - string Command; - while (intMsgCnt != strLowerMessage.length() && !isdigit(static_cast(strLowerMessage[intMsgCnt])) && !isspace( - static_cast(strLowerMessage[intMsgCnt]))) - { - Command += strLowerMessage[intMsgCnt]; - intMsgCnt++; - } + string Command=readPara(); string strReply; if (Command == "state") { time_t tNow = time(NULL); @@ -1035,21 +1029,13 @@ class FromMsg { reply(GlobalMsg["strSelfPermissionErr"]); return 1; } - while (isspace(static_cast(strLowerMessage[intMsgCnt]))) - intMsgCnt++; - string QQNum; - if (strLowerMessage.substr(intMsgCnt, 10) == "[cq:at,qq=") { - intMsgCnt += 10; - QQNum = readDigit(); - intMsgCnt++; - } - else { - QQNum = readDigit(); - } - while (isspace(static_cast(strLowerMessage[intMsgCnt]))) - intMsgCnt++; if (Command == "ban") { + string QQNum = readDigit(); + if (QQNum.empty()) { + reply(GlobalMsg["strQQIDEmpty"]); + return -1; + } long long llMemberQQ = stoll(QQNum); GroupMemberInfo Member = getGroupMemberInfo(fromGroup, llMemberQQ); if (Member.QQID == llMemberQQ) @@ -1059,6 +1045,10 @@ class FromMsg { return 1; } string strMainDice = readDice(); + if (strMainDice.empty()) { + reply(GlobalMsg["strValueErr"]); + return -1; + } const int intDefaultDice = DefaultDice.count(fromQQ) ? DefaultDice[fromQQ] : 100; RD rdMainDice(strMainDice, intDefaultDice); rdMainDice.Roll(); @@ -3318,6 +3308,10 @@ class FromMsg { strMsg = strMsg.substr(strAt.length()); isCalled = true; } + else if (strMsg.substr(0, 14) == "[CQ:at,qq=all]") { + strMsg = strMsg.substr(14); + isCalled = true; + } else { return false; @@ -3365,6 +3359,7 @@ class FromMsg { strMum += strMsg[intMsgCnt]; intMsgCnt++; } + if (strMsg[intMsgCnt] == ']')intMsgCnt++; return strMum; } //读取群号 diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index 89ad7b4d..01d2c42e 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -131,6 +131,7 @@ std::map GlobalMsg {"strObExit","成功退出旁观模式!"}, {"strObEnterAlready","已经处于旁观模式!"}, {"strObExitAlready","没有加入旁观模式!"}, + {"strQQIDEmpty","QQ号不能为空×"}, {"strGroupIDEmpty","群号不能为空×"}, {"strBlackGroup", "该群在黑名单中,如有疑问请联系master"}, {"strBotOn","成功开启本机器人!"}, From f68318eb81b809ee59ba9b0bbfad5c9d6ea21b5f Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Mon, 1 Jul 2019 00:57:49 +0800 Subject: [PATCH 09/33] =?UTF-8?q?.st=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鐜板湪st榛樿鍊间細琚嚜鍔ㄥ拷鐣 --- Dice/DiceEvent.h | 10 +++------- Dice/RDConstant.h | 1 + 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index d8ce26b8..5050d5ee 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -2721,18 +2721,14 @@ class FromMsg { while (isspace(static_cast(strLowerMessage[intMsgCnt])) || strLowerMessage[intMsgCnt] == '|')intMsgCnt++; continue; } - string strSkillVal; - while (isdigit(static_cast(strLowerMessage[intMsgCnt]))) - { - strSkillVal += strLowerMessage[intMsgCnt]; - intMsgCnt++; - } + string strSkillVal = readDigit(); if (strSkillName.empty() || strSkillVal.empty() || strSkillVal.length() > 3) { boolError = true; break; } - CharacterProp[SourceType(fromQQ, GroupT, fromGroup)][strSkillName] = stoi(strSkillVal); + int intSkillVal = stoi(strSkillVal); + if (SkillDefaultVal.count(strSkillName) && SkillDefaultVal[strSkillName] != intSkillVal)CharacterProp[SourceType(fromQQ, GroupT, fromGroup)][strSkillName] = intSkillVal; while (isspace(static_cast(strLowerMessage[intMsgCnt])) || strLowerMessage[intMsgCnt] == '|')intMsgCnt++; } if (boolError) diff --git a/Dice/RDConstant.h b/Dice/RDConstant.h index 50bbf3b8..a778126b 100644 --- a/Dice/RDConstant.h +++ b/Dice/RDConstant.h @@ -99,6 +99,7 @@ static std::map SkillNameReplace = { {"耕做", "耕作"}, {"机枪", "机关枪"}, {"导航", "领航"}, + {"骑术", "骑乘"}, {"船", "船驾驶"}, {"驾驶船", "船驾驶"}, {"驾驶(船)", "船驾驶"}, From 62b47a56a8a3609571939c8ebd8745c73571ed51 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 2 Jul 2019 21:13:37 +0800 Subject: [PATCH 10/33] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/Dice.cpp | 2 ++ Dice/DiceEvent.h | 6 ++--- Dice/EncodingConvert.cpp | 9 ++++++- Dice/EncodingConvert.h | 1 + Dice/Jsonio.h | 51 +++++++++++++++++++++++++--------------- 5 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index cb264b88..3ebe31d9 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -713,8 +713,10 @@ EVE_System_GroupMemberIncrease(eventGroupMemberIncrease) else if(getGroupMemberInfo(fromGroup,getLoginQQ()).permissions>1)strNote += "(群内有权限)"; else { AddMsgToQueue("发现黑名单用户" + printQQ(beingOperateQQ) + "入群,将预防性退群", Group); + strNote += "(已退群)"; Sleep(100); setGroupLeave(fromGroup); + sendAdmin(strNote); } } else if(beingOperateQQ == getLoginQQ()){ diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 5050d5ee..cca268cc 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -610,9 +610,9 @@ class FromMsg { catch (...) { return -1; } - string type = UTF8toGBK(jInfo["type"]); - string time = UTF8toGBK(jInfo["time"]); - string note = UTF8toGBK(jInfo["note"]); + string type = readJVal(jInfo["type"]); + string time = readJVal(jInfo["time"]); + string note = readJVal(jInfo["note"]); long long blackQQ = jInfo["fromQQ"]; long long blackGroup = jInfo["fromGroup"]; if (type != "ban" && type != "kick" || (blackGroup&&BlackGroup.count(blackGroup)) && (blackQQ&&BlackQQ.count(blackQQ))) { diff --git a/Dice/EncodingConvert.cpp b/Dice/EncodingConvert.cpp index 504a4917..05490fc6 100644 --- a/Dice/EncodingConvert.cpp +++ b/Dice/EncodingConvert.cpp @@ -60,7 +60,14 @@ std::string UTF8toGBK(const std::string& strUTF8) delete[] wszGBK; return strTemp; } - +std::vector UTF8toGBK(const std::vector &vUTF8) +{ + std::vector vOutGBK; + for (auto it : vUTF8) { + vOutGBK.push_back(UTF8toGBK(it)); + } + return vOutGBK; +} unsigned char ToHex(const unsigned char x) { return x > 9 ? x + 55 : x + 48; diff --git a/Dice/EncodingConvert.h b/Dice/EncodingConvert.h index a62c4a92..70dc30fa 100644 --- a/Dice/EncodingConvert.h +++ b/Dice/EncodingConvert.h @@ -28,6 +28,7 @@ std::string GBKtoUTF8(const std::string& strGBK); std::vector GBKtoUTF8(const std::vector &strGBK); std::string UTF8toGBK(const std::string& strUTF8); +std::vector UTF8toGBK(const std::vector &strUTF8); std::string UrlEncode(const std::string& str); std::string UrlDecode(const std::string& str); #endif /*DICE_ENCODING_CONVERT*/ diff --git a/Dice/Jsonio.h b/Dice/Jsonio.h index e3a71dae..56ea0d2d 100644 --- a/Dice/Jsonio.h +++ b/Dice/Jsonio.h @@ -6,20 +6,30 @@ #include "EncodingConvert.h" template -typename std::enable_if::value, T>::type readJson(std::string strJson) { +typename std::enable_if::value, T>::type readJKey(std::string strJson) { return UTF8toGBK(strJson); } template -typename std::enable_if::value, T>::type readJson(std::string strJson) { +typename std::enable_if::value, T>::type readJKey(std::string strJson) { return stoll(strJson); } +template +typename std::enable_if::value, T>::type readJVal(T strJson) { + return UTF8toGBK(strJson); +} + +template +typename std::enable_if::value, T>::type readJVal(T Json) { + return Json; +} + template std::vector readJVec(std::vector vJson) { std::vector vTmp; for (auto it : vJson) { - vTmp.push_back(readJson(it)); + vTmp.push_back(readJVal(it)); } return vTmp; } @@ -29,40 +39,43 @@ int readJson(std::string strJson, std::map &mapTmp) { int intCnt; try { j = nlohmann::json::parse(strJson); + for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) + { + T1 tKey = readJKey(it.key()); + T2 tVal = readJVal(it.value()); + mapTmp[tKey] = tVal; + intCnt++; + } } catch (...) { return -1; } - for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) - { - T1 tKey = readJson(it.key()); - T2 tVal = readJson(it.value()); - mapTmp[tKey] = tVal; - intCnt++; - } return intCnt; } template -int loadJMap(std::string strLoc, std::map> &mapTmp) { +int loadJMap(std::string strLoc, std::map &mapTmp) { std::ifstream fin(strLoc); if (fin) { nlohmann::json j; try { fin >> j; - }catch(...){ - return -1; + for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) + { + T1 tKey = readJKey(it.key()); + T2 tVal = readJVal(it.value()); + mapTmp[tKey] = tVal; + } } - for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) - { - T1 tKey = readJson(it.key()); - std::vector tVal = readJVec(it.value()); - mapTmp[tKey] = tVal; + catch (...) { + fin.close(); + return -1; } - fin.close(); } + fin.close(); return 0; } + template std::string writeJson(typename std::enable_if::value, T>::type strJson) { return GBKtoUTF8(strJson); From d81048a0926d92b374a22004c4303fd10fa9385d Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 2 Jul 2019 21:29:14 +0800 Subject: [PATCH 11/33] =?UTF-8?q?st=E5=8A=9F=E8=83=BD=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 淇ˉ浜嗕笂娆′慨鏀圭殑婕忔礊 --- Dice/DiceEvent.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index cca268cc..5a6ee8fc 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -2728,7 +2728,8 @@ class FromMsg { break; } int intSkillVal = stoi(strSkillVal); - if (SkillDefaultVal.count(strSkillName) && SkillDefaultVal[strSkillName] != intSkillVal)CharacterProp[SourceType(fromQQ, GroupT, fromGroup)][strSkillName] = intSkillVal; + if (!SkillDefaultVal.count(strSkillName) || SkillDefaultVal[strSkillName] != intSkillVal)CharacterProp[SourceType(fromQQ, GroupT, fromGroup)][strSkillName] = intSkillVal; + else if (CharacterProp[SourceType(fromQQ, GroupT, fromGroup)].count(strSkillName))CharacterProp[SourceType(fromQQ, GroupT, fromGroup)].erase(strSkillName); while (isspace(static_cast(strLowerMessage[intMsgCnt])) || strLowerMessage[intMsgCnt] == '|')intMsgCnt++; } if (boolError) From 36a2f7222612366c99b9887bc1557182b53bb762 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 2 Jul 2019 21:48:55 +0800 Subject: [PATCH 12/33] 2.3.8Express8 --- Dice/GlobalVar.cpp | 6 +++--- Dice/app.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index 01d2c42e..be807f53 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -35,8 +35,8 @@ CQ::logger DiceLogger("Dice!"); * 请勿修改Dice_Build, Dice_Ver_Without_Build,DiceRequestHeader以及Dice_Ver常量 * 请修改Dice_Short_Ver或Dice_Full_Ver常量以达到版本自定义 */ -const unsigned short Dice_Build = 544; -const std::string Dice_Ver_Without_Build = "2.3.8Express7"; +const unsigned short Dice_Build = 545; +const std::string Dice_Ver_Without_Build = "2.3.8Express8"; const std::string DiceRequestHeader = "Dice/2.3.8"; const std::string Dice_Ver = Dice_Ver_Without_Build + "(" + std::to_string(Dice_Build) + ")"; const std::string Dice_Short_Ver = "Dice! by 溯洄 Shiki.Ver " + Dice_Ver; @@ -249,7 +249,7 @@ std::map GlobalMsg std::map EditedMsg; std::map HelpDoc = { -{"更新","544:优化好友申请处理\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能\n528:更新.help帮助功能,允许后接参数"}, +{"更新","545:开放自定义deck\n优化好友申请处理\n544:优化好友申请处理\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, {"协议","0.本协议是Shiki(Death、Judgement、The World)的服务协议。如果你看到了这句话,意味着Master应用默认协议,请注意。\n1.邀请骰娘、使用掷骰服务和在群内阅读此协议视为同意并承诺遵守此协议,否则请使用.dismiss移出骰娘。\n2.不允许禁言、移出骰娘或刷屏掷骰等对骰娘的不友善行为,这些行为将会提高骰娘被制裁的风险。开关骰娘响应请使用.bot on/off。\n3.骰娘默认邀请行为已事先得到群内同意,因而会自动同意群邀请。因擅自邀请而使骰娘遭遇不友善行为时,邀请者因未履行预见义务而将承担连带责任。\n4.禁止将骰娘用于赌博及其他违法犯罪行为。\n5.对于设置敏感昵称等无法预见但有可能招致言论审查的行为,骰娘可能会出于自我保护而拒绝提供服务\n6.由于技术以及资金原因,我们无法保证机器人100%的时间稳定运行,可能不定时停机维护或遭遇冻结,但是相应情况会及时通过各种渠道进行通知,敬请谅解。临时停机的骰娘不会有任何响应,故而不会影响群内活动,此状态下仍然禁止不友善行为。\n7.对于违反协议的行为,骰娘将视情况终止对用户和所在群提供服务,并将不良记录共享给其他服务提供方。黑名单相关事宜可以与服务提供方协商,但最终裁定权在服务提供方。\n8.本协议内容随时有可能改动。请注意帮助信息、签名、空间、官方群等处的骰娘动态。\n9.骰娘提供掷骰服务是完全免费的,欢迎投食。\n10.本服务最终解释权归服务提供方所有。"}, {"链接","查看源码:https://github.com/w4123/Dice/tree/Shiki\n插件下载:https://github.com/w4123/Dice/releases\n官方文档:https://www.stringempty.xyz\n跑团记录着色器:https://logpainter.kokona.tech"}, {"设定","Master:()\n.me使用:禁止\n.jrrp使用:允许\n邀请处理:黑名单制,非禁即入\n讨论组使用:允许\n移出反制:拉黑群和操作者\n禁言反制:默认拉黑群和群主\n刷屏反制:警告\n邀请人责任:有限连带\n窥屏可能:有\n其他插件:无\n官方群:941980833\n私骰群:192499947"}, diff --git a/Dice/app.json b/Dice/app.json index 22b87db4..b72412ab 100644 --- a/Dice/app.json +++ b/Dice/app.json @@ -101,7 +101,7 @@ } ], "auth": [ - 20, //鍙栧ソ鍙嬪垪琛 getFriendList + //20, //鍙栧ソ鍙嬪垪琛 getFriendList 101, //鍙戦佺兢娑堟伅 sendGroupMsg 103, //鍙戦佽璁虹粍娑堟伅 sendDiscussMsg 106, //鍙戦佺鑱婃秷鎭 sendPrivateMsg From bd28d9b01f3aac9e2c20fd3e49b174071e7e1de3 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 21:31:01 +0800 Subject: [PATCH 13/33] =?UTF-8?q?=E9=87=8D=E5=AE=9A=E5=90=91=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=88=B0kokona.tech?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/DiceUpdate.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dice/DiceUpdate.cpp b/Dice/DiceUpdate.cpp index 25dc13de..81e0e34e 100644 --- a/Dice/DiceUpdate.cpp +++ b/Dice/DiceUpdate.cpp @@ -32,8 +32,7 @@ EVE_Menu(eventDiceUpdate) { std::string ver; - if (!Network::GET("shiki.stringempty.xyz", "/DiceVer", 80, ver)) - { + if (!Network::GET("api.kokona.tech", "/getExpVer", 5555, ver) && !Network::GET("shiki.stringempty.xyz", "/DiceVer", 80, ver)) { MessageBoxA(nullptr, ("检查更新时遇到错误: \n" + ver).c_str(), "Dice!更新错误", MB_OK | MB_ICONWARNING); return -1; } @@ -67,7 +66,7 @@ EVE_Menu(eventDiceUpdate) filePath = filePath.substr(0, filePath.find_last_of("\\")) + "\\app\\com.w4123.dice.cpk"; std::string fileContent; - if (!Network::GET("shiki.stringempty.xyz", "/download/com.w4123.dice.cpk", 80, fileContent)) + if (!Network::GET("api.kokona.tech", "/getExpDice", 5555, fileContent) && !Network::GET("shiki.stringempty.xyz", "/download/com.w4123.dice.cpk", 80, fileContent)) { MessageBoxA(nullptr, ("新版本文件下载失败! 请检查您的网络状态! 错误信息: " + fileContent).c_str(), "Dice!更新错误", MB_OK | MB_ICONERROR); return -1; From dfb9e1fd2674c6f479c3a5785a4f4b97bbd1463c Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 22:08:12 +0800 Subject: [PATCH 14/33] =?UTF-8?q?=E6=B3=9B=E7=94=A8=E5=8C=96UTF8=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/DiceEvent.h | 6 +++--- Dice/EncodingConvert.h | 8 ++++++++ Dice/GlobalVar.cpp | 2 +- Dice/Jsonio.h | 41 ++++++----------------------------------- 4 files changed, 18 insertions(+), 39 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 5a6ee8fc..19ee9e43 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -610,9 +610,9 @@ class FromMsg { catch (...) { return -1; } - string type = readJVal(jInfo["type"]); - string time = readJVal(jInfo["time"]); - string note = readJVal(jInfo["note"]); + string type = readJKey(jInfo["type"]); + string time = readJKey(jInfo["time"]); + string note = readJKey(jInfo["note"]); long long blackQQ = jInfo["fromQQ"]; long long blackGroup = jInfo["fromGroup"]; if (type != "ban" && type != "kick" || (blackGroup&&BlackGroup.count(blackGroup)) && (blackQQ&&BlackQQ.count(blackQQ))) { diff --git a/Dice/EncodingConvert.h b/Dice/EncodingConvert.h index 70dc30fa..7782a881 100644 --- a/Dice/EncodingConvert.h +++ b/Dice/EncodingConvert.h @@ -27,8 +27,16 @@ #include std::string GBKtoUTF8(const std::string& strGBK); std::vector GBKtoUTF8(const std::vector &strGBK); +template +T GBKtoUTF8(T TGBK) { + return TGBK; +} std::string UTF8toGBK(const std::string& strUTF8); std::vector UTF8toGBK(const std::vector &strUTF8); +template +T UTF8toGBK(T TUTF8) { + return TUTF8; +} std::string UrlEncode(const std::string& str); std::string UrlDecode(const std::string& str); #endif /*DICE_ENCODING_CONVERT*/ diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index be807f53..29e9ad9c 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -249,7 +249,7 @@ std::map GlobalMsg std::map EditedMsg; std::map HelpDoc = { -{"更新","545:开放自定义deck\n优化好友申请处理\n544:优化好友申请处理\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, +{"更新","545:开放自定义deck\n544:后台管理更新\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, {"协议","0.本协议是Shiki(Death、Judgement、The World)的服务协议。如果你看到了这句话,意味着Master应用默认协议,请注意。\n1.邀请骰娘、使用掷骰服务和在群内阅读此协议视为同意并承诺遵守此协议,否则请使用.dismiss移出骰娘。\n2.不允许禁言、移出骰娘或刷屏掷骰等对骰娘的不友善行为,这些行为将会提高骰娘被制裁的风险。开关骰娘响应请使用.bot on/off。\n3.骰娘默认邀请行为已事先得到群内同意,因而会自动同意群邀请。因擅自邀请而使骰娘遭遇不友善行为时,邀请者因未履行预见义务而将承担连带责任。\n4.禁止将骰娘用于赌博及其他违法犯罪行为。\n5.对于设置敏感昵称等无法预见但有可能招致言论审查的行为,骰娘可能会出于自我保护而拒绝提供服务\n6.由于技术以及资金原因,我们无法保证机器人100%的时间稳定运行,可能不定时停机维护或遭遇冻结,但是相应情况会及时通过各种渠道进行通知,敬请谅解。临时停机的骰娘不会有任何响应,故而不会影响群内活动,此状态下仍然禁止不友善行为。\n7.对于违反协议的行为,骰娘将视情况终止对用户和所在群提供服务,并将不良记录共享给其他服务提供方。黑名单相关事宜可以与服务提供方协商,但最终裁定权在服务提供方。\n8.本协议内容随时有可能改动。请注意帮助信息、签名、空间、官方群等处的骰娘动态。\n9.骰娘提供掷骰服务是完全免费的,欢迎投食。\n10.本服务最终解释权归服务提供方所有。"}, {"链接","查看源码:https://github.com/w4123/Dice/tree/Shiki\n插件下载:https://github.com/w4123/Dice/releases\n官方文档:https://www.stringempty.xyz\n跑团记录着色器:https://logpainter.kokona.tech"}, {"设定","Master:()\n.me使用:禁止\n.jrrp使用:允许\n邀请处理:黑名单制,非禁即入\n讨论组使用:允许\n移出反制:拉黑群和操作者\n禁言反制:默认拉黑群和群主\n刷屏反制:警告\n邀请人责任:有限连带\n窥屏可能:有\n其他插件:无\n官方群:941980833\n私骰群:192499947"}, diff --git a/Dice/Jsonio.h b/Dice/Jsonio.h index 56ea0d2d..e3726741 100644 --- a/Dice/Jsonio.h +++ b/Dice/Jsonio.h @@ -9,30 +9,11 @@ template typename std::enable_if::value, T>::type readJKey(std::string strJson) { return UTF8toGBK(strJson); } - template typename std::enable_if::value, T>::type readJKey(std::string strJson) { return stoll(strJson); } -template -typename std::enable_if::value, T>::type readJVal(T strJson) { - return UTF8toGBK(strJson); -} - -template -typename std::enable_if::value, T>::type readJVal(T Json) { - return Json; -} - -template -std::vector readJVec(std::vector vJson) { - std::vector vTmp; - for (auto it : vJson) { - vTmp.push_back(readJVal(it)); - } - return vTmp; -} template int readJson(std::string strJson, std::map &mapTmp) { nlohmann::json j; @@ -42,7 +23,7 @@ int readJson(std::string strJson, std::map &mapTmp) { for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) { T1 tKey = readJKey(it.key()); - T2 tVal = readJVal(it.value()); + T2 tVal = UTF8toGBK(it.value()); mapTmp[tKey] = tVal; intCnt++; } @@ -63,7 +44,7 @@ int loadJMap(std::string strLoc, std::map &mapTmp) { for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) { T1 tKey = readJKey(it.key()); - T2 tVal = readJVal(it.value()); + T2 tVal = UTF8toGBK(it.value()); mapTmp[tKey] = tVal; } } @@ -77,32 +58,22 @@ int loadJMap(std::string strLoc, std::map &mapTmp) { } template -std::string writeJson(typename std::enable_if::value, T>::type strJson) { +std::string writeJKey(typename std::enable_if::value, T>::type strJson) { return GBKtoUTF8(strJson); } - template -std::string writeJson(typename std::enable_if::value, T>::type llJson) { +std::string writeJKey(typename std::enable_if::value, T>::type llJson) { return std::to_string(llJson); } -template -std::vector writeJVec(std::vector vJson) { - std::vector vTmp; - for (auto it : vJson) { - vTmp.push_back(writeJson(it)); - } - return vTmp; -} - template -int saveJMap(std::string strLoc, std::map> mapTmp) { +int saveJMap(std::string strLoc, std::map mapTmp) { if (mapTmp.empty())return 0; std::ofstream fout(strLoc); if (fout) { nlohmann::json j; for (auto it : mapTmp) { - j[writeJson(it.first)] = writeJVec(it.second); + j[writeJKey(it.first)] = GBKtoUTF8(it.second); } fout << j; fout.close(); From d2cf2ef10d607d5822e3d163d80e55b6a6dd519a Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 22:08:37 +0800 Subject: [PATCH 15/33] =?UTF-8?q?=E5=88=A0=E9=99=A4CocXlsxTool?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CocXlsxTool/CocXlsxTool.pro | 46 - CocXlsxTool/icon.ico | Bin 67646 -> 0 bytes CocXlsxTool/icon.qrc | 5 - CocXlsxTool/main.cpp | 16 - CocXlsxTool/mainwindow.cpp | 1566 ----------- CocXlsxTool/mainwindow.h | 37 - CocXlsxTool/mainwindow.ui | 153 - CocXlsxTool/rapidxml.hpp | 2596 ----------------- CocXlsxTool/rapidxml_iterators.hpp | 174 -- CocXlsxTool/rapidxml_print.hpp | 421 --- CocXlsxTool/rapidxml_utils.hpp | 122 - CocXlsxTool/unzip.cpp | 4165 ---------------------------- CocXlsxTool/unzip.h | 214 -- CocXlsxTool/zip.cpp | 2832 ------------------- CocXlsxTool/zip.h | 203 -- 15 files changed, 12550 deletions(-) delete mode 100644 CocXlsxTool/CocXlsxTool.pro delete mode 100644 CocXlsxTool/icon.ico delete mode 100644 CocXlsxTool/icon.qrc delete mode 100644 CocXlsxTool/main.cpp delete mode 100644 CocXlsxTool/mainwindow.cpp delete mode 100644 CocXlsxTool/mainwindow.h delete mode 100644 CocXlsxTool/mainwindow.ui delete mode 100644 CocXlsxTool/rapidxml.hpp delete mode 100644 CocXlsxTool/rapidxml_iterators.hpp delete mode 100644 CocXlsxTool/rapidxml_print.hpp delete mode 100644 CocXlsxTool/rapidxml_utils.hpp delete mode 100644 CocXlsxTool/unzip.cpp delete mode 100644 CocXlsxTool/unzip.h delete mode 100644 CocXlsxTool/zip.cpp delete mode 100644 CocXlsxTool/zip.h diff --git a/CocXlsxTool/CocXlsxTool.pro b/CocXlsxTool/CocXlsxTool.pro deleted file mode 100644 index 7ca812fb..00000000 --- a/CocXlsxTool/CocXlsxTool.pro +++ /dev/null @@ -1,46 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2018-04-10T22:12:33 -# -#------------------------------------------------- - -QT += core gui -RC_ICONS += icon.ico - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = CocXlsxTool -TEMPLATE = app - -# The following define makes your compiler emit warnings if you use -# any feature of Qt which has been marked as deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if you use deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - - -SOURCES += \ - main.cpp \ - mainwindow.cpp \ - unzip.cpp \ - zip.cpp - -HEADERS += \ - mainwindow.h \ - rapidxml.hpp \ - rapidxml_iterators.hpp \ - rapidxml_print.hpp \ - rapidxml_utils.hpp \ - unzip.h \ - zip.h - -FORMS += \ - mainwindow.ui - -RESOURCES += \ - icon.qrc diff --git a/CocXlsxTool/icon.ico b/CocXlsxTool/icon.ico deleted file mode 100644 index bfd5425316505f34acd96b04616c58b24ae8dad4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67646 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

VJ*wT8BSIXCP{b+2|F@rT;z?-=6^| zSq8kO>BRf#_|Q!1X4&}u>}u-h6+ zF7elyMT)x^ok3MD=(F^opM6OOqVh-X%29M&xeAZ!;bT3>U-croFBlzoK0B;4q|6g5 zC!N{??KPlBP5aVLMfCt%aQQ6!8SJ3F0{3t{z0H^CS&cu=9K>mQq+{TCWKUh{8Hvw2 zPrd3oIiEBsaN!SXN|ApRHAEM6D0)(J>;6YE!! z^RX{ZbH{Isd190p51upf0A~7R3U0AKw}<>VoF}e@5pw_J2dSazp7ng@E>Z$ja>Hf8 z-;+-X5VQN3z2WYsQuj&K`WW?_48>4jYK@)p$@OGfiOY@bA}C@JLa0x#UuQ&i5I2T8)@jQH2oS4h6N!$(O zp2BQw(n-0Pc81;KVBe)Utfn0ds+%7CMADzTCzF0$UmFU3-A%83$tQg zfJ5ZLj?_Qc7SFoc0QRHcTP#!K$Q<4z_>}EnK-2huWYQCIgI?zBE@}a{d&&6|lTZ^d z_B7zrT$1P@$ICrW0_$cF^Jjtk(!hP!iTM*tve>VfMGg#3S?+$3yF`jyE*=V z#ffr*`=6Z8Zps2a&PDcM{ - - icon.ico - - diff --git a/CocXlsxTool/main.cpp b/CocXlsxTool/main.cpp deleted file mode 100644 index 07aa4dbe..00000000 --- a/CocXlsxTool/main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "mainwindow.h" -#include - -char* drag_file_path = NULL; - -int main(int argc, char *argv[]) -{ - if (argc >= 2) - drag_file_path = argv[1]; - - QApplication a(argc, argv); - MainWindow w; - w.show(); - - return a.exec(); -} diff --git a/CocXlsxTool/mainwindow.cpp b/CocXlsxTool/mainwindow.cpp deleted file mode 100644 index 2e1a06d8..00000000 --- a/CocXlsxTool/mainwindow.cpp +++ /dev/null @@ -1,1566 +0,0 @@ -锘#include "mainwindow.h" -#include "ui_mainwindow.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "zip.h" -#include "unzip.h" -#include "rapidxml_print.hpp" - -#pragma comment(lib,"shlwapi.lib") - -#define ENABLE_EXPORT_SEPARATELY 0 -#define ENABLE_IMPORT 0 - -extern char* drag_file_path; - -using namespace rapidxml; - -wchar_t* GetErrorTips(); -wchar_t* Utf8ToWchar(char* utf8_str); -char* WcharToUtf8(wchar_t* unicode_str); -int GetPropertyFromXlsx(wchar_t* file_path, Ui::MainWindow *ui); -int SetPropertyToXlsx(wchar_t* file_path, wchar_t* templet_string, Ui::MainWindow *ui); - -wchar_t name[32]; - -const char* name_r = "D3"; - -char property_list_1[][5][16] = { -{ "R3","T3","V3","V4","" }, -{ "R5","T5","V5","V6","" }, -{ "R7","T7","V7","V8","" }, -{ "X3","Z3","AB3","AB4","" }, -{ "X5","Z5","AB5","AB6","" }, -{ "X7","Z7","AB7","AB8","" }, -{ "AD3","AF3","AH3","AH4","" }, -{ "AD5","AF5","AH5","AH6","" }, - -{ "B10","F10","","","" }, -{ "K10","O10","","","" }, -{ "S10","W10","","","" }, -{ "AA10","AE10","","","" }, - -{ "C15","Q15","S15","U15","K15" }, -{ "C16","Q16","S16","U16","K16" }, -{ "C17","Q17","S17","U17","K17" }, -{ "C18","Q18","S18","U18","K18" }, -{ "E19","Q19","S19","U19","K19" }, -{ "E20","Q20","S20","U20","K20" }, -{ "E21","Q21","S21","U21","K21" }, -{ "C22","Q22","S22","U22","K22" }, -{ "C23","Q23","S23","U23","K23" }, -{ "C24","Q24","S24","U24","K24" }, -{ "C25","Q25","S25","U25","K25" }, -{ "C26","Q26","S26","U26","K26" }, -{ "C27","Q27","S27","U27","K27" }, -{ "C28","Q28","S28","U28","K28" }, -{ "C29","Q29","S29","U29","K29" }, -{ "C30","Q30","S30","U30","K30" }, -{ "C31","Q31","S31","U31","K31" }, -{ "C32","Q32","S32","U32","K32" }, -{ "E33","Q33","S33","U33","K33" }, -{ "E34","Q34","S34","U34","K34" }, -{ "E35","Q35","S35","U35","K35" }, -{ "E36","Q36","S36","U36","K36" }, -{ "E37","Q37","S37","U37","K37" }, -{ "E38","Q38","S38","U38","K38" }, -{ "C39","Q39","S39","U39","K39" }, -{ "C40","Q40","S40","U40","K40" }, -{ "C41","Q41","S41","U41","K41" }, -{ "C42","Q42","S42","U42","K42" }, -{ "E43","Q43","S43","U43","K43" }, -{ "E44","Q44","S44","U44","K44" }, -{ "E45","Q45","S45","U45","K45" }, -{ "E46","Q46","S46","U46","K56" }, - -{ "X15","AK15","AM15","AO15","AE15" }, -{ "X16","AK16","AM16","AO16","AE16" }, -{ "X17","AK17","AM17","AO17","AE17" }, -{ "X18","AK18","AM18","AO18","AE18" }, -{ "X19","AK19","AM19","AO19","AE19" }, -{ "X20","AK20","AM20","AO20","AE20" }, -{ "X21","AK21","AM21","AO21","AE21" }, -{ "X22","AK22","AM22","AO22","AE22" }, -{ "X23","AK23","AM23","AO23","AE23" }, -{ "X24","AK24","AM24","AO24","AE24" }, -{ "X25","AK25","AM25","AO25","AE25" }, -{ "Z26","AK26","AM26","AO26","AE26" }, -{ "X27","AK27","AM27","AO27","AE27" }, -{ "X28","AK28","AM28","AO28","AE28" }, -{ "X29","AK29","AM29","AO29","AE29" }, -{ "Z30","AK30","AM30","AO30","AE30" }, -{ "Z31","AK31","AM31","AO31","AE31" }, -{ "Z32","AK32","AM32","AO32","AE32" }, -{ "X33","AK33","AM33","AO33","AE33" }, -{ "X34","AK34","AM34","AO34","AE34" }, -{ "X35","AK35","AM35","AO35","AE35" }, -{ "Z36","AK36","AM36","AO36","AE36" }, -{ "Z37","AK37","AM37","AO37","AE37" }, -{ "X38","AK38","AM38","AO38","AE38" }, -{ "X39","AK39","AM39","AO39","AE39" }, -{ "X40","AK40","AM40","AO40","AE40" }, -{ "Z41","AK41","AM41","AO41","AE41" }, -{ "Z42","AK42","AM42","AO42","AE42" }, -{ "X43","AK43","AM43","AO43","AE43" }, -{ "X44","AK44","AM44","AO44","AE44" }, -{ "X45","AK45","AM45","AO45","AE45" }, -{ "X46","AK46","AM15","AO15","AE15" } -}; - -char property_list_2[][5][16] = { -{ "Q3","S3","U3","U4","" }, -{ "Q5","S5","U5","U6","" }, -{ "Q7","S7","U7","U8","" }, -{ "W3","Y3","AA3","AA4","" }, -{ "W5","Y5","AA5","AA6","" }, -{ "W7","Y7","AA7","AA8","" }, -{ "AC3","AE3","AG3","AG4","" }, -{ "AC5","AE5","AG5","AG6","" }, - -{ "B10","F10","","","" }, -{ "J10","N10","","","" }, -{ "R10","V10","","","" }, -{ "Z10","AD10","","","" }, - -{ "C15","P15","R15","T15","J15" }, -{ "C16","P16","R16","T16","J16" }, -{ "C17","P17","R17","T17","J17" }, -{ "C18","P18","R18","T18","J18" }, -{ "E19","P19","R19","T19","J19" }, -{ "E20","P20","R20","T20","J20" }, -{ "E21","P21","R21","T21","J21" }, -{ "C22","P22","R22","T22","J22" }, -{ "C23","P23","R23","T23","J23" }, -{ "C24","P24","R24","T24","J24" }, -{ "C25","P25","R25","T25","J25" }, -{ "C26","P26","R26","T26","J26" }, -{ "C27","P27","R27","T27","J27" }, -{ "C28","P28","R28","T28","J28" }, -{ "C29","P29","R29","T29","J29" }, -{ "C30","P30","R30","T30","J30" }, -{ "C31","P31","R31","T31","J31" }, -{ "C32","P32","R32","T32","J32" }, -{ "E33","P33","R33","T33","J33" }, -{ "E34","P34","R34","T34","J34" }, -{ "E35","P35","R35","T35","J35" }, -{ "E36","P36","R36","T36","J36" }, -{ "E37","P37","R37","T37","J37" }, -{ "E38","P38","R38","T38","J38" }, -{ "C39","P39","R39","T39","J39" }, -{ "C40","P40","R40","T40","J40" }, -{ "C41","P41","R41","T41","J41" }, -{ "C42","P42","R42","T42","J42" }, -{ "E43","P43","R43","T43","J43" }, -{ "E44","P44","R44","T44","J44" }, -{ "E45","P45","R45","T45","J45" }, -{ "E46","P46","R46","T46","J56" }, - -{ "W15","AJ15","AL15","AN15","AD15" }, -{ "W16","AJ16","AL16","AN16","AD16" }, -{ "W17","AJ17","AL17","AN17","AD17" }, -{ "W18","AJ18","AL18","AN18","AD18" }, -{ "W19","AJ19","AL19","AN19","AD19" }, -{ "W20","AJ20","AL20","AN20","AD20" }, -{ "W21","AJ21","AL21","AN21","AD21" }, -{ "W22","AJ22","AL22","AN22","AD22" }, -{ "W23","AJ23","AL23","AN23","AD23" }, -{ "W24","AJ24","AL24","AN24","AD24" }, -{ "W25","AJ25","AL25","AN25","AD25" }, -{ "Y26","AJ26","AL26","AN26","AD26" }, -{ "W27","AJ27","AL27","AN27","AD27" }, -{ "W28","AJ28","AL28","AN28","AD28" }, -{ "W29","AJ29","AL29","AN29","AD29" }, -{ "Y30","AJ30","AL30","AN30","AD30" }, -{ "Y31","AJ31","AL31","AN31","AD31" }, -{ "Y32","AJ32","AL32","AN32","AD32" }, -{ "W33","AJ33","AL33","AN33","AD33" }, -{ "W34","AJ34","AL34","AN34","AD34" }, -{ "W35","AJ35","AL35","AN35","AD35" }, -{ "Y36","AJ36","AL36","AN36","AD36" }, -{ "W37","AJ37","AL37","AN37","AD37" }, -{ "W38","AJ38","AL38","AN38","AD38" }, -{ "W39","AJ39","AL39","AN39","AD39" }, -{ "Y40","AJ40","AL40","AN40","AD40" }, -{ "W41","AJ41","AL41","AN41","AD41" }, -{ "W42","AJ42","AL42","AN42","AD42" }, -{ "W43","AJ43","AL43","AN43","AD43" }, -{ "W44","AJ44","AL44","AN44","AD44" }, -{ "W45","AJ45","AL45","AN45","AD45" }, -{ "W46","AJ46","AL15","AN15","AD15" } -}; - -typedef struct _PropertyNode -{ - int flag; - char* n_r; - wchar_t name[32]; - char* v_r; - wchar_t value[6]; - char* h_r; - wchar_t hard[6]; - char* d_r; - wchar_t difficult[6]; - char* g_r; - wchar_t grow[6]; -}PropertyNode; - - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow) -{ - ui->setupUi(this); - - this->setWindowTitle(QString::fromWCharArray(L"楠板妯℃澘鏍煎紡鐢熸垚宸ュ叿")); - this->setWindowIcon(QIcon(":/new/prefix1/icon.ico")); - - ui->textEdit->setReadOnly(!FALSE); - ui->textEdit_2->setReadOnly(!FALSE); - ui->textEdit_2->setVisible(FALSE); - ui->pushButton_export->setEnabled(FALSE); - ui->pushButton_import->setEnabled(FALSE); - ui->checkBox->setEnabled(FALSE); - ui->checkBox_2->setEnabled(FALSE); - - - if (drag_file_path) ui->lineEdit->setText(QString::fromLocal8Bit(drag_file_path)); -} - -MainWindow::~MainWindow() -{ - delete ui; -} - -void EnableWidget(Ui::MainWindow *ui, int flag) -{ - ui->lineEdit->setEnabled(flag); - ui->pushButton->setEnabled(flag); - ui->pushButton_export->setEnabled(flag); - ui->textEdit->setEnabled(flag); -#if ENABLE_EXPORT_SEPARATELY - ui->checkBox_2->setEnabled(flag); - ui->textEdit_2->setEnabled(flag); -#endif -#if ENABLE_IMPORT - ui->checkBox->setEnabled(flag); - ui->pushButton_import->setEnabled(flag); -#endif -} - -void MainWindow::on_pushButton_clicked() -{ - QString fileName = QFileDialog::getOpenFileName(this, QString::fromWCharArray(L"鎵撳紑浜虹墿鍗") - , NULL, QString::fromWCharArray(L"浜虹墿琛ㄦ牸 (*.xlsx)")); - ui->lineEdit->setText(fileName); -} - -void MainWindow::on_lineEdit_textChanged(const QString &arg1) -{ - wchar_t* file_path = Utf8ToWchar(arg1.toUtf8().data()); - int flag = FALSE; - - wchar_t* c = wcsrchr(file_path, L'.'); - if (c && !wcsicmp(c, L".xlsx")) - flag = 1; - - if (flag) - flag = PathFileExists(file_path); - free(file_path); - - if (flag) - { - ui->textEdit->clear(); - ui->textEdit_2->clear(); - } - ui->textEdit->setReadOnly(!flag); - ui->pushButton_export->setEnabled(flag); -#if ENABLE_EXPORT_SEPARATELY - ui->checkBox_2->setEnabled(flag); - ui->textEdit_2->setReadOnly(!flag); -#endif -#if ENABLE_IMPORT - ui->pushButton_import->setEnabled(flag); - ui->checkBox->setEnabled(flag); -#endif -} - -void MainWindow::on_pushButton_export_clicked() -{ - EnableWidget(ui, FALSE); - wchar_t* file_path = Utf8ToWchar(ui->lineEdit->text().toUtf8().data()); - ui->textEdit->clear(); - ui->statusBar->setStyleSheet("color:black"); - GetPropertyFromXlsx(file_path, ui); - free(file_path); - EnableWidget(ui, TRUE); -} - -void MainWindow::on_pushButton_import_clicked() -{ - EnableWidget(ui, FALSE); - wchar_t* file_path = Utf8ToWchar(ui->lineEdit->text().toUtf8().data()); - wchar_t* templet_string = Utf8ToWchar(ui->textEdit->toPlainText().toUtf8().data()); - ui->textEdit->clear(); - ui->statusBar->setStyleSheet("color:black"); - ui->checkBox_2->setChecked(FALSE); - SetPropertyToXlsx(file_path, templet_string, ui); - free(templet_string); - free(file_path); - EnableWidget(ui, TRUE); -} - - -void MainWindow::dragEnterEvent(QDragEnterEvent *e) -{ - if (e->mimeData()->hasFormat("text/uri-list")) - e->acceptProposedAction(); -} - -void MainWindow::dropEvent(QDropEvent *e) -{ - QList urls = e->mimeData()->urls(); - if (urls.isEmpty()) - return; - - QString fileName = urls.first().toLocalFile(); - - if (!fileName.isEmpty()) - ui->lineEdit->setText(fileName); -} - - - -int SetPropertyToXlsx(wchar_t* file_path, wchar_t* templet_string, Ui::MainWindow *ui) -{ - - wchar_t info_string[4096]; - - wchar_t* unit_pointer = templet_string; - PropertyNode import_list[128] = {}; - - while (unit_pointer != (wchar_t*)2) - { - wchar_t* unit_separater = wcschr(unit_pointer, '|'); - if (unit_separater) *unit_separater = 0; - unit_separater++; - - wchar_t* unit_value_string = wcschr(unit_pointer, ':'); - if (!unit_value_string) unit_value_string = wcschr(unit_pointer, '锛'); - if (!unit_value_string) { unit_pointer = unit_separater; continue; } - - *unit_value_string = 0; - unit_value_string++; - - wchar_t* unit_name_string = unit_pointer; - while (wchar_t* p = wcschr(unit_name_string, ' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(unit_value_string, ' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - - if (wcslen(unit_name_string) >= 31) { unit_pointer = unit_separater; continue; } - if (wcslen(unit_value_string) >= 31) { unit_pointer = unit_separater; continue; } - - for (int i = 0; i < 128; i++) - { - if (!import_list[i].name[0]) - { - wcscpy_s(import_list[i].name, unit_name_string); - wcscpy_s(import_list[i].value, unit_value_string); - break; - } - } - - unit_pointer = unit_separater; - } - - swprintf_s(info_string, L"姝e湪瑙f瀽 %s", file_path); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - HANDLE handle_file = CreateFile(file_path, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (handle_file == INVALID_HANDLE_VALUE) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"鏃犳硶鎵撳紑 \"%s\" : %s", file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - return 1; - } - - LARGE_INTEGER file_size = {}; - GetFileSizeEx(handle_file, &file_size); - - if (file_size.QuadPart <= 0) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"\"%s\" 鏄┖鐨", file_path); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - CloseHandle(handle_file); - return 1; - } - - void* zip_buf = malloc((size_t)file_size.QuadPart); - - DWORD read_size = 0; - if (!ReadFile(handle_file, zip_buf, (DWORD)file_size.QuadPart, &read_size, NULL) || read_size != file_size.QuadPart) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"鏃犳硶璇诲彇 \"%s\" : %s", file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(zip_buf); - CloseHandle(handle_file); - return 1; - } - - CloseHandle(handle_file); - - HZIP old_hz = OpenZip(zip_buf, read_size, 0); - ZIPENTRY ze; - int index; - - swprintf_s(info_string, L"姝e湪妫鏌ユ枃浠舵纭"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - FindZipItem(old_hz, L"xl/worksheets/sheet1.xml", true, &index, &ze); - if (index == -1) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xlxs瑙f瀽閿欒,娌℃湁鎵惧埌 xl/worksheets/sheet1.xml"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - CloseZip(old_hz); - free(zip_buf); - return 1; - } - char *sheet_xml_buf = (char*)malloc(ze.unc_size + 8); - memset(sheet_xml_buf, 0, ze.unc_size + 8); - UnzipItem(old_hz, index, sheet_xml_buf, ze.unc_size); - - FindZipItem(old_hz, L"xl/sharedStrings.xml", true, &index, &ze); - if (index == -1) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xlxs瑙f瀽閿欒,娌℃湁鎵惧埌 xl/sharedStrings.xml"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - CloseZip(old_hz); - free(sheet_xml_buf); - free(zip_buf); - return 1; - } - char *sharedStrings_xml_buf = (char*)malloc(ze.unc_size + 8); - memset(sharedStrings_xml_buf, 0, ze.unc_size + 8); - UnzipItem(old_hz, index, sharedStrings_xml_buf, ze.unc_size); - - - PropertyNode info[76] = {}; - - xml_document<> sheet_doc; - xml_node<> *worksheet_node = NULL; - xml_node<> *sheetData_node = NULL; - xml_document<> sharedStrings_doc; - xml_node<> *sst_node = NULL; - HZIP new_hz = {}; - - sheet_doc.parse<0>(sheet_xml_buf); - sharedStrings_doc.parse<0>(sharedStrings_xml_buf); - - swprintf_s(info_string, L"姝e湪妫鏌ML姝g‘鎬"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - worksheet_node = sheet_doc.first_node("worksheet"); - if (!worksheet_node) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sheet1->worksheet"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); free(zip_buf); return 1; - } - - sheetData_node = worksheet_node->first_node("sheetData"); - if (!sheetData_node) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sheet1->worksheet->sheetData"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); free(zip_buf); return 1; - } - - if (!sheetData_node->first_node("row")) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sheet1->worksheet->sheetData->row"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); free(zip_buf); return 1; - } - - sst_node = sharedStrings_doc.first_node("sst"); - if (!sheetData_node) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sharedStrings->sst"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); free(zip_buf); return 1; - } - - if (!sst_node->first_node("si")) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sharedStrings->si"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); free(zip_buf); return 1; - } - - - swprintf_s(info_string, L"姝e湪璇嗗埆琛ㄦ牸"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - int use_list_1 = 0; - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - - - if (!strcmp("O59", r_attr->value())) - { - - xml_node<> * v_node = c_node->first_node("v"); - if (!v_node || !v_node->value()) - continue; - - r_attr = c_node->first_attribute("t"); - - if (r_attr && r_attr->value()[0] == 's') - { - - int si_index = 0; - sscanf_s(v_node->value(), "%d", &si_index); - - xml_node<> *si_node = sst_node->first_node("si"); - - for (int i = 0; i < si_index && si_node; i++) - si_node = si_node->next_sibling(); - - - if (si_node) - { - xml_node<> *r_node = si_node->first_node("r"); - - for (xml_node<> *t_node = r_node ? r_node->first_node("t") : si_node->first_node("t"); - t_node; t_node = t_node->next_sibling()) - { - wchar_t* value_string = Utf8ToWchar(t_node->value()); - if (!wcscmp(L"璐у竵:", value_string)) - use_list_1 = 1; - - free(value_string); - } - } - - } - else - { - - wchar_t* value_string = Utf8ToWchar(v_node->value()); - if (!wcscmp(L"璐у竵:", value_string)) - use_list_1 = 1; - - free(value_string); - } - - continue; - } - } - } - - if (use_list_1) - { - for (int i = 0; i < 72; i++) - { - info[i].n_r = property_list_1[i][0]; - info[i].v_r = property_list_1[i][1]; - info[i].h_r = property_list_1[i][2]; - info[i].d_r = property_list_1[i][3]; - info[i].g_r = property_list_1[i][4]; - } - } - else - { - for (int i = 0; i < 72; i++) - { - info[i].n_r = property_list_2[i][0]; - info[i].v_r = property_list_2[i][1]; - info[i].h_r = property_list_2[i][2]; - info[i].d_r = property_list_2[i][3]; - info[i].g_r = property_list_2[i][4]; - } - } - - swprintf_s(info_string, L"姝e湪瑙f瀽XML"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - for (int i = 0; i < 72; i++) - { - if (!strcmp(info[i].n_r, r_attr->value())) - { - - xml_node<> * v_node = c_node->first_node("v"); - if (!v_node || !v_node->value()) - break; - - r_attr = c_node->first_attribute("t"); - - - if (r_attr && r_attr->value()[0] == 's') - { - - int si_index = 0; - sscanf_s(v_node->value(), "%d", &si_index); - - xml_node<> *si_node = sst_node->first_node("si"); - - for (int i = 0; i < si_index && si_node; i++) - si_node = si_node->next_sibling(); - - - if (si_node) - { - xml_node<> *r_node = si_node->first_node("r"); - - for (xml_node<> *t_node = r_node ? r_node->first_node("t") : si_node->first_node("t"); - t_node; t_node = t_node->next_sibling()) - { - wchar_t* value_string = Utf8ToWchar(t_node->value()); - - while (wchar_t* p = wcschr(value_string, L'\r')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'惟')) wcscpy_s(p, wcslen(p) + 1, p + 1); - for (wchar_t* p = value_string; *p; p++) - { - if ((*p >= L'a' && *p <= L'z') || (*p >= L'A' && *p <= L'z')) - { - wcscpy_s(p, wcslen(p) + 1, p + 1); - p--; - } - } - - wcscat_s(info[i].name, value_string); - - free(value_string); - } - } - - } - else - { - - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - while (wchar_t* p = wcschr(value_string, L'\r')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'惟')) wcscpy_s(p, wcslen(p) + 1, p + 1); - for (wchar_t* p = value_string; *p; p++) - { - if ((*p >= L'a' && *p <= L'z') || (*p >= L'A' && *p <= L'z')) - { - wcscpy_s(p, wcslen(p) + 1, p + 1); - p--; - } - } - - wcscpy_s(info[i].name, value_string); - - free(value_string); - } - - for (int j = 0; j < 128; j++) - { - if (!wcscmp(info[i].name, import_list[j].name)) - { - wcscpy_s(info[i].value, import_list[j].value); - int new_value = 0; - swscanf_s(import_list[j].value, L"%d", &new_value); - - swprintf_s(info[i].hard, L"%d", new_value / 2); - swprintf_s(info[i].difficult, L"%d", new_value / 5); - - import_list[j].flag = 1; - break; - } - } - - break; - } - } - } - } - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - for (int i = 0; i < 72; i++) - { - if (!strcmp(info[i].v_r, r_attr->value())) - { - r_attr = c_node->first_attribute("t"); - xml_node<> * v_node = c_node->first_node("v"); - - if (v_node && v_node->value()) - { - for (int j = 0; j < 128; j++) - { - if (!wcscmp(info[i].name, import_list[j].name)) - { - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - wchar_t* decimal_point = wcschr(value_string, L'.'); - if (decimal_point) - *decimal_point = 0; - - int old_value = 0; - int new_value = 0; - - swscanf_s(value_string, L"%d", &old_value); - swscanf_s(import_list[j].value, L"%d", &new_value); - - if (new_value != old_value) - swprintf_s(info[i].grow, L"%d", new_value - old_value); - - free(value_string); - break; - } - } - - } - break; - } - } - } - } - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - for (int i = 0; i < 72; i++) - { - if (!strcmp(info[i].g_r, r_attr->value()) && info[i].grow[0]) - { - r_attr = c_node->first_attribute("t"); - xml_node<> * v_node = c_node->first_node("v"); - - if (v_node && v_node->value()) - { - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - wchar_t* decimal_point = wcschr(value_string, L'.'); - if (decimal_point) - *decimal_point = 0; - - int old_value = 0; - int new_value = 0; - - swscanf_s(value_string, L"%d", &old_value); - swscanf_s(info[i].grow, L"%d", &new_value); - - swprintf_s(info[i].grow, L"%d", new_value + old_value); - - free(value_string); - break; - } - break; - } - } - } - } - - swprintf_s(info_string, L"姝e湪瀵煎叆鏁版嵁"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - for (int i = 0; i < 72; i++) - { - if (!strcmp(info[i].v_r, r_attr->value()) && info[i].value[0]) - { - xml_node<> * v_node = c_node->first_node("v"); - char* value_string = WcharToUtf8(info[i].value); - xml_node<> *new_node = sheet_doc.allocate_node(node_element, sheet_doc.allocate_string("v") - , sheet_doc.allocate_string(value_string)); - - c_node->insert_node(0, new_node); - if (v_node) c_node->remove_node(v_node); - - free(value_string); - break; - } - else if (!strcmp(info[i].h_r, r_attr->value()) && info[i].value[0]) - { - xml_node<> * v_node = c_node->first_node("v"); - char* value_string = WcharToUtf8(info[i].hard); - xml_node<> *new_node = sheet_doc.allocate_node(node_element, sheet_doc.allocate_string("v") - , sheet_doc.allocate_string(value_string)); - - c_node->insert_node(0, new_node); - if (v_node) c_node->remove_node(v_node); - - free(value_string); - break; - } - else if (!strcmp(info[i].d_r, r_attr->value()) && info[i].value[0]) - { - xml_node<> * v_node = c_node->first_node("v"); - char* value_string = WcharToUtf8(info[i].difficult); - xml_node<> *new_node = sheet_doc.allocate_node(node_element, sheet_doc.allocate_string("v") - , sheet_doc.allocate_string(value_string)); - - c_node->insert_node(0, new_node); - if (v_node) c_node->remove_node(v_node); - - free(value_string); - break; - } - else if (!strcmp(info[i].g_r, r_attr->value()) && info[i].value[0] && info[i].grow[0]) - { - xml_node<> * v_node = c_node->first_node("v"); - char* value_string = WcharToUtf8(info[i].grow); - xml_node<> *new_node = sheet_doc.allocate_node(node_element, sheet_doc.allocate_string("v") - , sheet_doc.allocate_string(value_string)); - - c_node->insert_node(0, new_node); - if (v_node) c_node->remove_node(v_node); - - free(value_string); - break; - } - } - } - } - - - swprintf_s(info_string, L"姝e湪鍐欏叆鏂扮殑琛ㄦ牸"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - unsigned long new_zip_size = read_size * 2; - new_hz = CreateZip(0, new_zip_size, 0); - - - char* buffer = (char*)malloc(1024 * 1024); // You are responsible for making the buffer large enough! - char *end = print(buffer, sheet_doc, 0); // end contains pointer to character after last printed character - *end = 0; // Add string terminator after XML - ZipAdd(new_hz, L"xl/worksheets/sheet1.xml", buffer, strlen(buffer)); - free(buffer); - - ze = {}; - GetZipItem(old_hz, -1, &ze); - int numitems = ze.index; - for (int zi = 0; zi < numitems; zi++) - { - ZIPENTRY ze; - GetZipItem(old_hz, zi, &ze); // fetch individual details - - if (!wcscmp(ze.name, L"xl/worksheets/sheet1.xml")) - continue; - - char *ibuf = (char*)malloc(ze.unc_size); - UnzipItem(old_hz, zi, ibuf, ze.unc_size); // e.g. the item's name. - ZipAdd(new_hz, ze.name, ibuf, ze.unc_size); - free(ibuf); - } - - ZipGetMemory(new_hz, (void**)&buffer, &new_zip_size); - - if (ui->checkBox->isChecked()) - { - wchar_t new_file_path[MAX_PATH] = {}; - wcscpy_s(new_file_path, file_path); - wcscat_s(new_file_path, L".bak"); - if (!MoveFile(file_path, new_file_path)) - { - ui->statusBar->setStyleSheet("color:red"); - if (PathFileExists(new_file_path)) - swprintf_s(info_string, L"鏃犳硶绉诲姩 \"%s\" 鑷 \"%s\" : 瀛樺湪澶囦唤鏂囦欢", file_path, new_file_path); - else - swprintf_s(info_string, L"鏃犳硶绉诲姩 \"%s\" 鑷 \"%s\" : %s", file_path, new_file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); return 1; - } - } - else - { - if (!DeleteFile(file_path)) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"鏃犳硶鍒犻櫎 \"%s\" : %s", file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); CloseZip(old_hz); return 1; - } - } - - handle_file = CreateFile(file_path, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); - if (handle_file == INVALID_HANDLE_VALUE) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"鏃犳硶鎵撳紑 \"%s\" : %s", file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); - free(sharedStrings_xml_buf); - CloseZip(old_hz); - CloseZip(new_hz); - return 1; - } - DWORD writ; WriteFile(handle_file, buffer, new_zip_size, &writ, 0); - CloseHandle(handle_file); - - free(sheet_xml_buf); - free(sharedStrings_xml_buf); - - CloseZip(old_hz); - free(zip_buf); - - CloseZip(new_hz); - - for (int i = 0; i < 128; i++) - if (!import_list[i].flag && import_list[i].name[0] && - wcscmp(import_list[i].name, L"鍒濆鐢熷懡") && - wcscmp(import_list[i].name, L"鍒濆鐞嗘櫤") && - wcscmp(import_list[i].name, L"鍒濆骞歌繍") && - wcscmp(import_list[i].name, L"鍒濆榄旀硶")) - { - swprintf_s(info_string, L"[%s]娌℃湁琚鍏,璇风‘璁よ〃鏍间腑瀛樺湪姝ゆ妧鑳", import_list[i].name); - ui->textEdit->append(QString::fromWCharArray(info_string)); - } - - swprintf_s(info_string, L"瀵煎叆瀹屾垚"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - return 0; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - -int GetPropertyFromXlsx(wchar_t* file_path, Ui::MainWindow *ui) -{ - ui->statusBar->setStyleSheet("color:black"); - name[0] = 0; - - wchar_t info_string[4096]; - - swprintf_s(info_string, L"姝e湪瑙f瀽 %s", file_path); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - HANDLE handle_file = CreateFile(file_path, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (handle_file == INVALID_HANDLE_VALUE) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"鏃犳硶鎵撳紑 \"%s\" : %s", file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - return 1; - } - - LARGE_INTEGER file_size = {}; - GetFileSizeEx(handle_file, &file_size); - - if (file_size.QuadPart <= 0) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"\"%s\" 鏄┖鐨", file_path); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - CloseHandle(handle_file); - return 1; - } - - void* zip_buf = malloc((size_t)file_size.QuadPart); - - DWORD read_size = 0; - if (!ReadFile(handle_file, zip_buf, (DWORD)file_size.QuadPart, &read_size, NULL) || read_size != file_size.QuadPart) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"鏃犳硶璇诲彇 \"%s\" : %s", file_path, GetLastError() ? GetErrorTips() : L"鏈煡鍘熷洜."); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(zip_buf); - CloseHandle(handle_file); - return 1; - } - - CloseHandle(handle_file); - - HZIP hz = OpenZip(zip_buf, read_size, 0); - ZIPENTRY ze; - int index; - - - swprintf_s(info_string, L"姝e湪妫鏌ヨ〃鏍兼纭"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - - FindZipItem(hz, L"xl/worksheets/sheet1.xml", true, &index, &ze); - if (index == -1) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xlxs瑙f瀽閿欒,娌℃湁鎵惧埌 xl/worksheets/sheet1.xml"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - CloseZip(hz); - free(zip_buf); - return 1; - } - - char *sheet_xml_buf = (char*)malloc(ze.unc_size + 8); - memset(sheet_xml_buf, 0, ze.unc_size + 8); - UnzipItem(hz, index, sheet_xml_buf, ze.unc_size); - - FindZipItem(hz, L"xl/sharedStrings.xml", true, &index, &ze); - if (index == -1) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xlxs瑙f瀽閿欒,娌℃湁鎵惧埌 xl/sharedStrings.xml"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - CloseZip(hz); - free(sheet_xml_buf); - free(zip_buf); - return 1; - } - char *sharedStrings_xml_buf = (char*)malloc(ze.unc_size + 8); - memset(sharedStrings_xml_buf, 0, ze.unc_size + 8); - UnzipItem(hz, index, sharedStrings_xml_buf, ze.unc_size); - - CloseZip(hz); - free(zip_buf); - - PropertyNode info[76] = {}; - - xml_document<> sheet_doc; - xml_node<> *worksheet_node = NULL; - xml_node<> *sheetData_node = NULL; - xml_document<> sharedStrings_doc; - xml_node<> *sst_node = NULL; - - - sheet_doc.parse<0>(sheet_xml_buf); - sharedStrings_doc.parse<0>(sharedStrings_xml_buf); - - - swprintf_s(info_string, L"姝e湪妫鏌ML姝g‘鎬"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - worksheet_node = sheet_doc.first_node("worksheet"); - if (!worksheet_node) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sheet1->worksheet"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); return 1; - } - - sheetData_node = worksheet_node->first_node("sheetData"); - if (!sheetData_node) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sheet1->worksheet->sheetData"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); return 1; - } - - if (!sheetData_node->first_node("row")) { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sheet1->worksheet->sheetData->row"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); return 1; - } - - sst_node = sharedStrings_doc.first_node("sst"); - if (!sheetData_node) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sharedStrings->sst"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); return 1; - } - - if (!sst_node->first_node("si")) - { - ui->statusBar->setStyleSheet("color:red"); - swprintf_s(info_string, L"xml瑙f瀽閿欒,娌℃湁鎵惧埌 sharedStrings->si"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - free(sheet_xml_buf); free(sharedStrings_xml_buf); return 1; - } - - - swprintf_s(info_string, L"姝e湪璇嗗埆琛ㄦ牸"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - int use_list_1 = 0; - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - - - if (!strcmp("O59", r_attr->value())) - { - - xml_node<> * v_node = c_node->first_node("v"); - if (!v_node || !v_node->value()) - continue; - - r_attr = c_node->first_attribute("t"); - - if (r_attr && r_attr->value()[0] == 's') - { - - int si_index = 0; - sscanf_s(v_node->value(), "%d", &si_index); - - xml_node<> *si_node = sst_node->first_node("si"); - - for (int i = 0; i < si_index && si_node; i++) - si_node = si_node->next_sibling(); - - - if (si_node) - { - xml_node<> *r_node = si_node->first_node("r"); - - for (xml_node<> *t_node = r_node ? r_node->first_node("t") : si_node->first_node("t"); - t_node; t_node = t_node->next_sibling()) - { - wchar_t* value_string = Utf8ToWchar(t_node->value()); - - if (!wcscmp(L"璐у竵:", value_string)) - use_list_1 = 1; - - free(value_string); - } - } - - } - else - { - - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - if (!wcscmp(L"璐у竵:", value_string)) - use_list_1 = 1; - - free(value_string); - } - - continue; - } - } - } - - if (use_list_1) - { - for (int i = 0; i < 72; i++) - { - info[i].n_r = property_list_1[i][0]; - info[i].v_r = property_list_1[i][1]; - } - } - else - { - for (int i = 0; i < 72; i++) - { - info[i].n_r = property_list_2[i][0]; - info[i].v_r = property_list_2[i][1]; - } - } - - - - - swprintf_s(info_string, L"姝e湪瑙f瀽XML"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - for (xml_node<> * row_node = sheetData_node->first_node("row"); row_node; row_node = row_node->next_sibling()) - { - for (xml_node<> * c_node = row_node->first_node("c"); c_node; c_node = c_node->next_sibling()) - { - xml_attribute<> * r_attr = c_node->first_attribute("r"); - - - if (!strcmp(name_r, r_attr->value())) - { - - xml_node<> * v_node = c_node->first_node("v"); - if (!v_node || !v_node->value()) - continue; - - r_attr = c_node->first_attribute("t"); - - if (r_attr && r_attr->value()[0] == 's') - { - - int si_index = 0; - sscanf_s(v_node->value(), "%d", &si_index); - - xml_node<> *si_node = sst_node->first_node("si"); - - for (int i = 0; i < si_index && si_node; i++) - si_node = si_node->next_sibling(); - - - if (si_node) - { - xml_node<> *r_node = si_node->first_node("r"); - - for (xml_node<> *t_node = r_node ? r_node->first_node("t") : si_node->first_node("t"); - t_node; t_node = t_node->next_sibling()) - { - wchar_t* value_string = Utf8ToWchar(t_node->value()); - - while (wchar_t* p = wcschr(value_string, L'\r')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'惟')) wcscpy_s(p, wcslen(p) + 1, p + 1); - for (wchar_t* p = value_string; *p; p++) - { - if ((*p >= L'a' && *p <= L'z') || (*p >= L'A' && *p <= L'z')) - { - wcscpy_s(p, wcslen(p) + 1, p + 1); - p--; - } - } - - wcscat_s(name, value_string); - - free(value_string); - } - } - - } - else - { - - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - while (wchar_t* p = wcschr(value_string, L'\r')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'惟')) wcscpy_s(p, wcslen(p) + 1, p + 1); - for (wchar_t* p = value_string; *p; p++) - { - if ((*p >= L'a' && *p <= L'z') || (*p >= L'A' && *p <= L'z')) - { - wcscpy_s(p, wcslen(p) + 1, p + 1); - p--; - } - } - - wcscpy_s(name, value_string); - - free(value_string); - } - - continue; - } - - for (int i = 0; i < 72; i++) - { - if (!strcmp(info[i].n_r, r_attr->value())) - { - - xml_node<> * v_node = c_node->first_node("v"); - if (!v_node || !v_node->value()) - break; - - r_attr = c_node->first_attribute("t"); - - - if (r_attr && r_attr->value()[0] == 's') - { - - int si_index = 0; - sscanf_s(v_node->value(), "%d", &si_index); - - xml_node<> *si_node = sst_node->first_node("si"); - - for (int i = 0; i < si_index && si_node; i++) - si_node = si_node->next_sibling(); - - - if (si_node) - { - xml_node<> *r_node = si_node->first_node("r"); - - for (xml_node<> *t_node = r_node ? r_node->first_node("t") : si_node->first_node("t"); - t_node; t_node = t_node->next_sibling()) - { - wchar_t* value_string = Utf8ToWchar(t_node->value()); - - while (wchar_t* p = wcschr(value_string, L'\r')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'惟')) wcscpy_s(p, wcslen(p) + 1, p + 1); - for (wchar_t* p = value_string; *p; p++) - { - if ((*p >= L'a' && *p <= L'z') || (*p >= L'A' && *p <= L'z')) - { - wcscpy_s(p, wcslen(p) + 1, p + 1); - p--; - } - } - - wcscat_s(info[i].name, value_string); - - free(value_string); - } - } - - } - else - { - - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - while (wchar_t* p = wcschr(value_string, L'\r')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L' ')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(value_string, L'惟')) wcscpy_s(p, wcslen(p) + 1, p + 1); - for (wchar_t* p = value_string; *p; p++) - { - if ((*p >= L'a' && *p <= L'z') || (*p >= L'A' && *p <= L'z')) - { - wcscpy_s(p, wcslen(p) + 1, p + 1); - p--; - } - } - - wcscpy_s(info[i].name, value_string); - - free(value_string); - } - - break; - } - else if (!strcmp(info[i].v_r, r_attr->value())) - { - r_attr = c_node->first_attribute("t"); - xml_node<> * v_node = c_node->first_node("v"); - - if (v_node && v_node->value()) - { - wchar_t* value_string = Utf8ToWchar(v_node->value()); - - wchar_t* decimal_point = wcschr(value_string, L'.'); - if (decimal_point) - *decimal_point = 0; - - wcscpy_s(info[i].value, value_string); - - free(value_string); - } - break; - } - } - - - } - } - - free(sheet_xml_buf); - free(sharedStrings_xml_buf); - - - swprintf_s(info_string, L"姝e湪瀵煎嚭鏁版嵁"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - wcscpy_s(info[72].name, L"鍒濆鐢熷懡"); - for (int i = 0; i < 72; i++) - if (!wcscmp(info[i].name, L"鐢熷懡")) - wcscpy_s(info[72].value, info[i].value); - - wcscpy_s(info[73].name, L"鍒濆鐞嗘櫤"); - for (int i = 0; i < 72; i++) - if (!wcscmp(info[i].name, L"鐞嗘櫤")) - wcscpy_s(info[73].value, info[i].value); - - wcscpy_s(info[74].name, L"鍒濆骞歌繍"); - for (int i = 0; i < 72; i++) - if (!wcscmp(info[i].name, L"骞歌繍")) - wcscpy_s(info[74].value, info[i].value); - - wcscpy_s(info[75].name, L"鍒濆榄旀硶"); - for (int i = 0; i < 72; i++) - if (!wcscmp(info[i].name, L"榄旀硶")) - wcscpy_s(info[75].value, info[i].value); - - if (!ui->checkBox_2->isChecked()) - { - int separater_flag = 0; - for (int i = 0; i < 76; i++) - { - if (info[i].name[0] != 0 && info->value[0] != 0) - { - if (!separater_flag) - { - swprintf_s(info_string, L".st "); - ui->textEdit->moveCursor(QTextCursor::End); - ui->textEdit->insertPlainText(QString::fromWCharArray(info_string)); - separater_flag = 1; - } - else - { - swprintf_s(info_string, L"|"); - ui->textEdit->moveCursor(QTextCursor::End); - ui->textEdit->insertPlainText(QString::fromWCharArray(info_string)); - } - swprintf_s(info_string, L"%s:%s", info[i].name, info[i].value); - ui->textEdit->moveCursor(QTextCursor::End); - ui->textEdit->insertPlainText(QString::fromWCharArray(info_string)); - } - } - } - else - { - int separater_flag = 0; - for (int i = 0; i < 38; i++) - { - if (info[i].name[0] != 0 && info->value[0] != 0) - { - if (!separater_flag) - { - swprintf_s(info_string, L".st "); - ui->textEdit->moveCursor(QTextCursor::End); - ui->textEdit->insertPlainText(QString::fromWCharArray(info_string)); - separater_flag = 1; - } - else - { - swprintf_s(info_string, L"|"); - ui->textEdit->moveCursor(QTextCursor::End); - ui->textEdit->insertPlainText(QString::fromWCharArray(info_string)); - } - swprintf_s(info_string, L"%s:%s", info[i].name, info[i].value); - ui->textEdit->moveCursor(QTextCursor::End); - ui->textEdit->insertPlainText(QString::fromWCharArray(info_string)); - } - } - separater_flag = 0; - for (int i = 38; i < 76; i++) - { - if (info[i].name[0] != 0 && info->value[0] != 0) - { - if (!separater_flag) - { - swprintf_s(info_string, L".st "); - ui->textEdit_2->moveCursor(QTextCursor::End); - ui->textEdit_2->insertPlainText(QString::fromWCharArray(info_string)); - separater_flag = 1; - } - else - { - swprintf_s(info_string, L"|"); - ui->textEdit_2->moveCursor(QTextCursor::End); - ui->textEdit_2->insertPlainText(QString::fromWCharArray(info_string)); - } - swprintf_s(info_string, L"%s:%s", info[i].name, info[i].value); - ui->textEdit_2->moveCursor(QTextCursor::End); - ui->textEdit_2->insertPlainText(QString::fromWCharArray(info_string)); - } - } - } - - swprintf_s(info_string, L"瑙f瀽瀹屾垚"); - ui->statusBar->showMessage(QString::fromWCharArray(info_string)); - - return 0; - -} - - -wchar_t* GetErrorTips() -{ - void* err_msg = NULL; - static wchar_t ret_info[256]; - - int langid = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED); - - if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), langid, (wchar_t*)&err_msg, 0, NULL)) return NULL; - wcscpy_s(ret_info, _countof(ret_info), (wchar_t*)err_msg); - LocalFree(err_msg); - - while (wchar_t* p = wcschr(ret_info, L'\r'))wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(ret_info, L'\n')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(ret_info, L'.')) wcscpy_s(p, wcslen(p) + 1, p + 1); - while (wchar_t* p = wcschr(ret_info, L':')) wcscpy_s(p, wcslen(p) + 1, p + 1); - - return ret_info; - -} - - -wchar_t* Utf8ToWchar(char* utf8_str) -{ - int wchar_len = MultiByteToWideChar(CP_UTF8, NULL, utf8_str, -1, NULL, 0); - wchar_t* unicode_str = (wchar_t*)malloc(sizeof(wchar_t)*wchar_len); - MultiByteToWideChar(CP_UTF8, NULL, utf8_str, -1, unicode_str, wchar_len);; - return unicode_str; -} - -char* WcharToUtf8(wchar_t* unicode_str) -{ - int utf8_len = WideCharToMultiByte(CP_UTF8, NULL, unicode_str, -1, NULL, 0, NULL, NULL); - char *utf8_str = (char*)malloc(sizeof(char)*utf8_len); - WideCharToMultiByte(CP_UTF8, NULL, unicode_str, -1, utf8_str, utf8_len, NULL, NULL); - return utf8_str; -} - -void MainWindow::on_checkBox_2_clicked(bool checked) -{ - ui->textEdit_2->setVisible(checked); - ui->textEdit->clear(); - ui->textEdit_2->clear(); - ui->pushButton_import->setEnabled(!checked); -} diff --git a/CocXlsxTool/mainwindow.h b/CocXlsxTool/mainwindow.h deleted file mode 100644 index 90e748bb..00000000 --- a/CocXlsxTool/mainwindow.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - -protected: - void dragEnterEvent(QDragEnterEvent *e); - void dropEvent(QDropEvent *e); - -private slots: - void on_pushButton_clicked(); - - void on_lineEdit_textChanged(const QString &arg1); - - void on_pushButton_export_clicked(); - - void on_pushButton_import_clicked(); - - void on_checkBox_2_clicked(bool checked); - -private: - Ui::MainWindow *ui; -}; - -#endif // MAINWINDOW_H diff --git a/CocXlsxTool/mainwindow.ui b/CocXlsxTool/mainwindow.ui deleted file mode 100644 index e7865a02..00000000 --- a/CocXlsxTool/mainwindow.ui +++ /dev/null @@ -1,153 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 537 - 498 - - - - true - - - MainWindow - - - - - - - 浠庤〃鏍煎鍑 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 瀵煎叆鑷宠〃鏍 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - - - - - - 澶囦唤琛ㄦ牸 - - - true - - - - - - - 鍒嗘瀵煎叆 - - - - - - - - - 鎵撳紑琛ㄦ牸: - - - - - - - false - - - - - - - 閫夋嫨鏂囦欢 - - - - - - - - - - - - - - - - diff --git a/CocXlsxTool/rapidxml.hpp b/CocXlsxTool/rapidxml.hpp deleted file mode 100644 index ae91e081..00000000 --- a/CocXlsxTool/rapidxml.hpp +++ /dev/null @@ -1,2596 +0,0 @@ -#ifndef RAPIDXML_HPP_INCLUDED -#define RAPIDXML_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation - -// If standard library is disabled, user must provide implementations of required functions and typedefs -#if !defined(RAPIDXML_NO_STDLIB) - #include // For std::size_t - #include // For assert - #include // For placement new -#endif - -// On MSVC, disable "conditional expression is constant" warning (level 4). -// This warning is almost impossible to avoid with certain types of templated code -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4127) // Conditional expression is constant -#endif - -/////////////////////////////////////////////////////////////////////////// -// RAPIDXML_PARSE_ERROR - -#if defined(RAPIDXML_NO_EXCEPTIONS) - -#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } - -namespace rapidxml -{ - //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, - //! this function is called to notify user about the error. - //! It must be defined by the user. - //!

- //! This function cannot return. If it does, the results are undefined. - //!

- //! A very simple definition might look like that: - //!

-    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
-    //! {
-    //!     std::cout << "Parse error: " << what << "\n";
-    //!     std::abort();
-    //! }
-    //! 
- //! \param what Human readable description of the error. - //! \param where Pointer to character data where error was detected. - void parse_error_handler(const char *what, void *where); -} - -#else - -#include // For std::exception - -#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) - -namespace rapidxml -{ - - //! Parse error exception. - //! This exception is thrown by the parser when an error occurs. - //! Use what() function to get human-readable error message. - //! Use where() function to get a pointer to position within source text where error was detected. - //!

- //! If throwing exceptions by the parser is undesirable, - //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. - //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. - //! This function must be defined by the user. - //!

- //! This class derives from std::exception class. - class parse_error: public std::exception - { - - public: - - //! Constructs parse error - parse_error(const char *what, void *where) - : m_what(what) - , m_where(where) - { - } - - //! Gets human readable description of error. - //! \return Pointer to null terminated description of the error. - virtual const char *what() const throw() - { - return m_what; - } - - //! Gets pointer to character data where error happened. - //! Ch should be the same as char type of xml_document that produced the error. - //! \return Pointer to location within the parsed string where error occured. - template - Ch *where() const - { - return reinterpret_cast(m_where); - } - - private: - - const char *m_what; - void *m_where; - - }; -} - -#endif - -/////////////////////////////////////////////////////////////////////////// -// Pool sizes - -#ifndef RAPIDXML_STATIC_POOL_SIZE - // Size of static memory block of memory_pool. - // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. - // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. - #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) -#endif - -#ifndef RAPIDXML_DYNAMIC_POOL_SIZE - // Size of dynamic memory block of memory_pool. - // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. - // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. - #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) -#endif - -#ifndef RAPIDXML_ALIGNMENT - // Memory allocation alignment. - // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. - // All memory allocations for nodes, attributes and strings will be aligned to this value. - // This must be a power of 2 and at least 1, otherwise memory_pool will not work. - #define RAPIDXML_ALIGNMENT sizeof(void *) -#endif - -namespace rapidxml -{ - // Forward declarations - template class xml_node; - template class xml_attribute; - template class xml_document; - - //! Enumeration listing all node types produced by the parser. - //! Use xml_node::type() function to query node type. - enum node_type - { - node_document, //!< A document node. Name and value are empty. - node_element, //!< An element node. Name contains element name. Value contains text of first data node. - node_data, //!< A data node. Name is empty. Value contains data text. - node_cdata, //!< A CDATA node. Name is empty. Value contains data text. - node_comment, //!< A comment node. Name is empty. Value contains comment text. - node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. - node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. - node_pi //!< A PI node. Name contains target. Value contains instructions. - }; - - /////////////////////////////////////////////////////////////////////// - // Parsing flags - - //! Parse flag instructing the parser to not create data nodes. - //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_data_nodes = 0x1; - - //! Parse flag instructing the parser to not use text of first data node as a value of parent element. - //! Can be combined with other flags by use of | operator. - //! Note that child data nodes of element node take precendence over its value when printing. - //! That is, if element has one or more child data nodes and a value, the value will be ignored. - //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. - //!

- //! See xml_document::parse() function. - const int parse_no_element_values = 0x2; - - //! Parse flag instructing the parser to not place zero terminators after strings in the source text. - //! By default zero terminators are placed, modifying source text. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_string_terminators = 0x4; - - //! Parse flag instructing the parser to not translate entities in the source text. - //! By default entities are translated, modifying source text. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_entity_translation = 0x8; - - //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. - //! By default, UTF-8 handling is enabled. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_no_utf8 = 0x10; - - //! Parse flag instructing the parser to create XML declaration node. - //! By default, declaration node is not created. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_declaration_node = 0x20; - - //! Parse flag instructing the parser to create comments nodes. - //! By default, comment nodes are not created. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_comment_nodes = 0x40; - - //! Parse flag instructing the parser to create DOCTYPE node. - //! By default, doctype node is not created. - //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_doctype_node = 0x80; - - //! Parse flag instructing the parser to create PI nodes. - //! By default, PI nodes are not created. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_pi_nodes = 0x100; - - //! Parse flag instructing the parser to validate closing tag names. - //! If not set, name inside closing tag is irrelevant to the parser. - //! By default, closing tags are not validated. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_validate_closing_tags = 0x200; - - //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. - //! By default, whitespace is not trimmed. - //! This flag does not cause the parser to modify source text. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_trim_whitespace = 0x400; - - //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. - //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. - //! By default, whitespace is not normalized. - //! If this flag is specified, source text will be modified. - //! Can be combined with other flags by use of | operator. - //!

- //! See xml_document::parse() function. - const int parse_normalize_whitespace = 0x800; - - // Compound flags - - //! Parse flags which represent default behaviour of the parser. - //! This is always equal to 0, so that all other flags can be simply ored together. - //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. - //! This also means that meaning of each flag is a negation of the default setting. - //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, - //! and using the flag will disable it. - //!

- //! See xml_document::parse() function. - const int parse_default = 0; - - //! A combination of parse flags that forbids any modifications of the source text. - //! This also results in faster parsing. However, note that the following will occur: - //!
    - //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • - //!
  • entities will not be translated
  • - //!
  • whitespace will not be normalized
  • - //!
- //! See xml_document::parse() function. - const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; - - //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. - //!

- //! See xml_document::parse() function. - const int parse_fastest = parse_non_destructive | parse_no_data_nodes; - - //! A combination of parse flags resulting in largest amount of data being extracted. - //! This usually results in slowest parsing. - //!

- //! See xml_document::parse() function. - const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; - - /////////////////////////////////////////////////////////////////////// - // Internals - - //! \cond internal - namespace internal - { - - // Struct that contains lookup tables for the parser - // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). - template - struct lookup_tables - { - static const unsigned char lookup_whitespace[256]; // Whitespace table - static const unsigned char lookup_node_name[256]; // Node name table - static const unsigned char lookup_text[256]; // Text table - static const unsigned char lookup_text_pure_no_ws[256]; // Text table - static const unsigned char lookup_text_pure_with_ws[256]; // Text table - static const unsigned char lookup_attribute_name[256]; // Attribute name table - static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote - static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote - static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes - static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes - static const unsigned char lookup_digits[256]; // Digits - static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters - }; - - // Find length of the string - template - inline std::size_t measure(const Ch *p) - { - const Ch *tmp = p; - while (*tmp) - ++tmp; - return tmp - p; - } - - // Compare strings for equality - template - inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) - { - if (size1 != size2) - return false; - if (case_sensitive) - { - for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) - if (*p1 != *p2) - return false; - } - else - { - for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) - if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) - return false; - } - return true; - } - } - //! \endcond - - /////////////////////////////////////////////////////////////////////// - // Memory pool - - //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. - //! In most cases, you will not need to use this class directly. - //! However, if you need to create nodes manually or modify names/values of nodes, - //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. - //! Not only is this faster than allocating them by using new operator, - //! but also their lifetime will be tied to the lifetime of document, - //! possibly simplyfing memory management. - //!

- //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. - //! You can also call allocate_string() function to allocate strings. - //! Such strings can then be used as names or values of nodes without worrying about their lifetime. - //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, - //! or when the pool is destroyed. - //!

- //! It is also possible to create a standalone memory_pool, and use it - //! to allocate nodes, whose lifetime will not be tied to any document. - //!

- //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. - //! Until static memory is exhausted, no dynamic memory allocations are done. - //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, - //! by using global new[] and delete[] operators. - //! This behaviour can be changed by setting custom allocation routines. - //! Use set_allocator() function to set them. - //!

- //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. - //! This value defaults to the size of pointer on target architecture. - //!

- //! To obtain absolutely top performance from the parser, - //! it is important that all nodes are allocated from a single, contiguous block of memory. - //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. - //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT - //! to obtain best wasted memory to performance compromise. - //! To do it, define their values before rapidxml.hpp file is included. - //! \param Ch Character type of created nodes. - template - class memory_pool - { - - public: - - //! \cond internal - typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory - typedef void (free_func)(void *); // Type of user-defined function used to free memory - //! \endcond - - //! Constructs empty pool with default allocator functions. - memory_pool() - : m_alloc_func(0) - , m_free_func(0) - { - init(); - } - - //! Destroys pool and frees all the memory. - //! This causes memory occupied by nodes allocated by the pool to be freed. - //! Nodes allocated from the pool are no longer valid. - ~memory_pool() - { - clear(); - } - - //! Allocates a new node from the pool, and optionally assigns name and value to it. - //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. - //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function - //! will call rapidxml::parse_error_handler() function. - //! \param type Type of node to create. - //! \param name Name to assign to the node, or 0 to assign no name. - //! \param value Value to assign to the node, or 0 to assign no value. - //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. - //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. - //! \return Pointer to allocated node. This pointer will never be NULL. - xml_node *allocate_node(node_type type, - const Ch *name = 0, const Ch *value = 0, - std::size_t name_size = 0, std::size_t value_size = 0) - { - void *memory = allocate_aligned(sizeof(xml_node)); - xml_node *node = new(memory) xml_node(type); - if (name) - { - if (name_size > 0) - node->name(name, name_size); - else - node->name(name); - } - if (value) - { - if (value_size > 0) - node->value(value, value_size); - else - node->value(value); - } - return node; - } - - //! Allocates a new attribute from the pool, and optionally assigns name and value to it. - //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. - //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function - //! will call rapidxml::parse_error_handler() function. - //! \param name Name to assign to the attribute, or 0 to assign no name. - //! \param value Value to assign to the attribute, or 0 to assign no value. - //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. - //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. - //! \return Pointer to allocated attribute. This pointer will never be NULL. - xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, - std::size_t name_size = 0, std::size_t value_size = 0) - { - void *memory = allocate_aligned(sizeof(xml_attribute)); - xml_attribute *attribute = new(memory) xml_attribute; - if (name) - { - if (name_size > 0) - attribute->name(name, name_size); - else - attribute->name(name); - } - if (value) - { - if (value_size > 0) - attribute->value(value, value_size); - else - attribute->value(value); - } - return attribute; - } - - //! Allocates a char array of given size from the pool, and optionally copies a given string to it. - //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. - //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function - //! will call rapidxml::parse_error_handler() function. - //! \param source String to initialize the allocated memory with, or 0 to not initialize it. - //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. - //! \return Pointer to allocated char array. This pointer will never be NULL. - Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) - { - assert(source || size); // Either source or size (or both) must be specified - if (size == 0) - size = internal::measure(source) + 1; - Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); - if (source) - for (std::size_t i = 0; i < size; ++i) - result[i] = source[i]; - return result; - } - - //! Clones an xml_node and its hierarchy of child nodes and attributes. - //! Nodes and attributes are allocated from this memory pool. - //! Names and values are not cloned, they are shared between the clone and the source. - //! Result node can be optionally specified as a second parameter, - //! in which case its contents will be replaced with cloned source node. - //! This is useful when you want to clone entire document. - //! \param source Node to clone. - //! \param result Node to put results in, or 0 to automatically allocate result node - //! \return Pointer to cloned node. This pointer will never be NULL. - xml_node *clone_node(const xml_node *source, xml_node *result = 0) - { - // Prepare result node - if (result) - { - result->remove_all_attributes(); - result->remove_all_nodes(); - result->type(source->type()); - } - else - result = allocate_node(source->type()); - - // Clone name and value - result->name(source->name(), source->name_size()); - result->value(source->value(), source->value_size()); - - // Clone child nodes and attributes - for (xml_node *child = source->first_node(); child; child = child->next_sibling()) - result->append_node(clone_node(child)); - for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) - result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); - - return result; - } - - //! Clears the pool. - //! This causes memory occupied by nodes allocated by the pool to be freed. - //! Any nodes or strings allocated from the pool will no longer be valid. - void clear() - { - while (m_begin != m_static_memory) - { - char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; - if (m_free_func) - m_free_func(m_begin); - else - delete[] m_begin; - m_begin = previous_begin; - } - init(); - } - - //! Sets or resets the user-defined memory allocation functions for the pool. - //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. - //! Allocation function must not return invalid pointer on failure. It should either throw, - //! stop the program, or use longjmp() function to pass control to other place of program. - //! If it returns invalid pointer, results are undefined. - //!

- //! User defined allocation functions must have the following forms: - //!
- //!
void *allocate(std::size_t size); - //!
void free(void *pointer); - //!

- //! \param af Allocation function, or 0 to restore default function - //! \param ff Free function, or 0 to restore default function - void set_allocator(alloc_func *af, free_func *ff) - { - assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet - m_alloc_func = af; - m_free_func = ff; - } - - private: - - struct header - { - char *previous_begin; - }; - - void init() - { - m_begin = m_static_memory; - m_ptr = align(m_begin); - m_end = m_static_memory + sizeof(m_static_memory); - } - - char *align(char *ptr) - { - std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); - return ptr + alignment; - } - - char *allocate_raw(std::size_t size) - { - // Allocate - void *memory; - if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] - { - memory = m_alloc_func(size); - assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp - } - else - { - memory = new char[size]; -#ifdef RAPIDXML_NO_EXCEPTIONS - if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc - RAPIDXML_PARSE_ERROR("out of memory", 0); -#endif - } - return static_cast(memory); - } - - void *allocate_aligned(std::size_t size) - { - // Calculate aligned pointer - char *result = align(m_ptr); - - // If not enough memory left in current pool, allocate a new pool - if (result + size > m_end) - { - // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) - std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; - if (pool_size < size) - pool_size = size; - - // Allocate - std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation - char *raw_memory = allocate_raw(alloc_size); - - // Setup new pool in allocated memory - char *pool = align(raw_memory); - header *new_header = reinterpret_cast
(pool); - new_header->previous_begin = m_begin; - m_begin = raw_memory; - m_ptr = pool + sizeof(header); - m_end = raw_memory + alloc_size; - - // Calculate aligned pointer again using new pool - result = align(m_ptr); - } - - // Update pool and return aligned pointer - m_ptr = result + size; - return result; - } - - char *m_begin; // Start of raw memory making up current pool - char *m_ptr; // First free byte in current pool - char *m_end; // One past last available byte in current pool - char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory - alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used - free_func *m_free_func; // Free function, or 0 if default is to be used - }; - - /////////////////////////////////////////////////////////////////////////// - // XML base - - //! Base class for xml_node and xml_attribute implementing common functions: - //! name(), name_size(), value(), value_size() and parent(). - //! \param Ch Character type to use - template - class xml_base - { - - public: - - /////////////////////////////////////////////////////////////////////////// - // Construction & destruction - - // Construct a base with empty name, value and parent - xml_base() - : m_name(0) - , m_value(0) - , m_parent(0) - { - } - - /////////////////////////////////////////////////////////////////////////// - // Node data access - - //! Gets name of the node. - //! Interpretation of name depends on type of node. - //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. - //!

- //! Use name_size() function to determine length of the name. - //! \return Name of node, or empty string if node has no name. - Ch *name() const - { - return m_name ? m_name : nullstr(); - } - - //! Gets size of node name, not including terminator character. - //! This function works correctly irrespective of whether name is or is not zero terminated. - //! \return Size of node name, in characters. - std::size_t name_size() const - { - return m_name ? m_name_size : 0; - } - - //! Gets value of node. - //! Interpretation of value depends on type of node. - //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. - //!

- //! Use value_size() function to determine length of the value. - //! \return Value of node, or empty string if node has no value. - Ch *value() const - { - return m_value ? m_value : nullstr(); - } - - //! Gets size of node value, not including terminator character. - //! This function works correctly irrespective of whether value is or is not zero terminated. - //! \return Size of node value, in characters. - std::size_t value_size() const - { - return m_value ? m_value_size : 0; - } - - /////////////////////////////////////////////////////////////////////////// - // Node modification - - //! Sets name of node to a non zero-terminated string. - //! See \ref ownership_of_strings. - //!

- //! Note that node does not own its name or value, it only stores a pointer to it. - //! It will not delete or otherwise free the pointer on destruction. - //! It is reponsibility of the user to properly manage lifetime of the string. - //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - - //! on destruction of the document the string will be automatically freed. - //!

- //! Size of name must be specified separately, because name does not have to be zero terminated. - //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). - //! \param name Name of node to set. Does not have to be zero terminated. - //! \param size Size of name, in characters. This does not include zero terminator, if one is present. - void name(const Ch *name, std::size_t size) - { - m_name = const_cast(name); - m_name_size = size; - } - - //! Sets name of node to a zero-terminated string. - //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). - //! \param name Name of node to set. Must be zero terminated. - void name(const Ch *name) - { - this->name(name, internal::measure(name)); - } - - //! Sets value of node to a non zero-terminated string. - //! See \ref ownership_of_strings. - //!

- //! Note that node does not own its name or value, it only stores a pointer to it. - //! It will not delete or otherwise free the pointer on destruction. - //! It is reponsibility of the user to properly manage lifetime of the string. - //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - - //! on destruction of the document the string will be automatically freed. - //!

- //! Size of value must be specified separately, because it does not have to be zero terminated. - //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). - //!

- //! If an element has a child node of type node_data, it will take precedence over element value when printing. - //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. - //! \param value value of node to set. Does not have to be zero terminated. - //! \param size Size of value, in characters. This does not include zero terminator, if one is present. - void value(const Ch *value, std::size_t size) - { - m_value = const_cast(value); - m_value_size = size; - } - - //! Sets value of node to a zero-terminated string. - //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). - //! \param value Vame of node to set. Must be zero terminated. - void value(const Ch *value) - { - this->value(value, internal::measure(value)); - } - - /////////////////////////////////////////////////////////////////////////// - // Related nodes access - - //! Gets node parent. - //! \return Pointer to parent node, or 0 if there is no parent. - xml_node *parent() const - { - return m_parent; - } - - protected: - - // Return empty string - static Ch *nullstr() - { - static Ch zero = Ch('\0'); - return &zero; - } - - Ch *m_name; // Name of node, or 0 if no name - Ch *m_value; // Value of node, or 0 if no value - std::size_t m_name_size; // Length of node name, or undefined of no name - std::size_t m_value_size; // Length of node value, or undefined if no value - xml_node *m_parent; // Pointer to parent node, or 0 if none - - }; - - //! Class representing attribute node of XML document. - //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). - //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. - //! Thus, this text must persist in memory for the lifetime of attribute. - //! \param Ch Character type to use. - template - class xml_attribute: public xml_base - { - - friend class xml_node; - - public: - - /////////////////////////////////////////////////////////////////////////// - // Construction & destruction - - //! Constructs an empty attribute with the specified type. - //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. - xml_attribute() - { - } - - /////////////////////////////////////////////////////////////////////////// - // Related nodes access - - //! Gets document of which attribute is a child. - //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. - xml_document *document() const - { - if (xml_node *node = this->parent()) - { - while (node->parent()) - node = node->parent(); - return node->type() == node_document ? static_cast *>(node) : 0; - } - else - return 0; - } - - //! Gets previous attribute, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return this->m_parent ? m_prev_attribute : 0; - } - - //! Gets next attribute, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return this->m_parent ? m_next_attribute : 0; - } - - private: - - xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero - xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero - - }; - - /////////////////////////////////////////////////////////////////////////// - // XML node - - //! Class representing a node of XML document. - //! Each node may have associated name and value strings, which are available through name() and value() functions. - //! Interpretation of name and value depends on type of the node. - //! Type of node can be determined by using type() function. - //!

- //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. - //! Thus, this text must persist in the memory for the lifetime of node. - //! \param Ch Character type to use. - template - class xml_node: public xml_base - { - - public: - - /////////////////////////////////////////////////////////////////////////// - // Construction & destruction - - //! Constructs an empty node with the specified type. - //! Consider using memory_pool of appropriate document to allocate nodes manually. - //! \param type Type of node to construct. - xml_node(node_type type) - : m_type(type) - , m_first_node(0) - , m_first_attribute(0) - { - } - - /////////////////////////////////////////////////////////////////////////// - // Node data access - - //! Gets type of node. - //! \return Type of node. - node_type type() const - { - return m_type; - } - - /////////////////////////////////////////////////////////////////////////// - // Related nodes access - - //! Gets document of which node is a child. - //! \return Pointer to document that contains this node, or 0 if there is no parent document. - xml_document *document() const - { - xml_node *node = const_cast *>(this); - while (node->parent()) - node = node->parent(); - return node->type() == node_document ? static_cast *>(node) : 0; - } - - //! Gets first child node, optionally matching node name. - //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found child, or 0 if not found. - xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *child = m_first_node; child; child = child->next_sibling()) - if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) - return child; - return 0; - } - else - return m_first_node; - } - - //! Gets last child node, optionally matching node name. - //! Behaviour is undefined if node has no children. - //! Use first_node() to test if node has children. - //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found child, or 0 if not found. - xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - assert(m_first_node); // Cannot query for last child if node has no children - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *child = m_last_node; child; child = child->previous_sibling()) - if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) - return child; - return 0; - } - else - return m_last_node; - } - - //! Gets previous sibling node, optionally matching node name. - //! Behaviour is undefined if node has no parent. - //! Use parent() to test if node has a parent. - //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found sibling, or 0 if not found. - xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - assert(this->m_parent); // Cannot query for siblings if node has no parent - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) - if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) - return sibling; - return 0; - } - else - return m_prev_sibling; - } - - //! Gets next sibling node, optionally matching node name. - //! Behaviour is undefined if node has no parent. - //! Use parent() to test if node has a parent. - //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found sibling, or 0 if not found. - xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - assert(this->m_parent); // Cannot query for siblings if node has no parent - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) - if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) - return sibling; - return 0; - } - else - return m_next_sibling; - } - - //! Gets first attribute of node, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return m_first_attribute; - } - - //! Gets last attribute of node, optionally matching attribute name. - //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero - //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string - //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters - //! \return Pointer to found attribute, or 0 if not found. - xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const - { - if (name) - { - if (name_size == 0) - name_size = internal::measure(name); - for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) - if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) - return attribute; - return 0; - } - else - return m_first_attribute ? m_last_attribute : 0; - } - - /////////////////////////////////////////////////////////////////////////// - // Node modification - - //! Sets type of node. - //! \param type Type of node to set. - void type(node_type type) - { - m_type = type; - } - - /////////////////////////////////////////////////////////////////////////// - // Node manipulation - - //! Prepends a new child node. - //! The prepended child becomes the first child, and all existing children are moved one position back. - //! \param child Node to prepend. - void prepend_node(xml_node *child) - { - assert(child && !child->parent() && child->type() != node_document); - if (first_node()) - { - child->m_next_sibling = m_first_node; - m_first_node->m_prev_sibling = child; - } - else - { - child->m_next_sibling = 0; - m_last_node = child; - } - m_first_node = child; - child->m_parent = this; - child->m_prev_sibling = 0; - } - - //! Appends a new child node. - //! The appended child becomes the last child. - //! \param child Node to append. - void append_node(xml_node *child) - { - assert(child && !child->parent() && child->type() != node_document); - if (first_node()) - { - child->m_prev_sibling = m_last_node; - m_last_node->m_next_sibling = child; - } - else - { - child->m_prev_sibling = 0; - m_first_node = child; - } - m_last_node = child; - child->m_parent = this; - child->m_next_sibling = 0; - } - - //! Inserts a new child node at specified place inside the node. - //! All children after and including the specified node are moved one position back. - //! \param where Place where to insert the child, or 0 to insert at the back. - //! \param child Node to insert. - void insert_node(xml_node *where, xml_node *child) - { - assert(!where || where->parent() == this); - assert(child && !child->parent() && child->type() != node_document); - if (where == m_first_node) - prepend_node(child); - else if (where == 0) - append_node(child); - else - { - child->m_prev_sibling = where->m_prev_sibling; - child->m_next_sibling = where; - where->m_prev_sibling->m_next_sibling = child; - where->m_prev_sibling = child; - child->m_parent = this; - } - } - - //! Removes first child node. - //! If node has no children, behaviour is undefined. - //! Use first_node() to test if node has children. - void remove_first_node() - { - assert(first_node()); - xml_node *child = m_first_node; - m_first_node = child->m_next_sibling; - if (child->m_next_sibling) - child->m_next_sibling->m_prev_sibling = 0; - else - m_last_node = 0; - child->m_parent = 0; - } - - //! Removes last child of the node. - //! If node has no children, behaviour is undefined. - //! Use first_node() to test if node has children. - void remove_last_node() - { - assert(first_node()); - xml_node *child = m_last_node; - if (child->m_prev_sibling) - { - m_last_node = child->m_prev_sibling; - child->m_prev_sibling->m_next_sibling = 0; - } - else - m_first_node = 0; - child->m_parent = 0; - } - - //! Removes specified child from the node - // \param where Pointer to child to be removed. - void remove_node(xml_node *where) - { - assert(where && where->parent() == this); - assert(first_node()); - if (where == m_first_node) - remove_first_node(); - else if (where == m_last_node) - remove_last_node(); - else - { - where->m_prev_sibling->m_next_sibling = where->m_next_sibling; - where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; - where->m_parent = 0; - } - } - - //! Removes all child nodes (but not attributes). - void remove_all_nodes() - { - for (xml_node *node = first_node(); node; node = node->m_next_sibling) - node->m_parent = 0; - m_first_node = 0; - } - - //! Prepends a new attribute to the node. - //! \param attribute Attribute to prepend. - void prepend_attribute(xml_attribute *attribute) - { - assert(attribute && !attribute->parent()); - if (first_attribute()) - { - attribute->m_next_attribute = m_first_attribute; - m_first_attribute->m_prev_attribute = attribute; - } - else - { - attribute->m_next_attribute = 0; - m_last_attribute = attribute; - } - m_first_attribute = attribute; - attribute->m_parent = this; - attribute->m_prev_attribute = 0; - } - - //! Appends a new attribute to the node. - //! \param attribute Attribute to append. - void append_attribute(xml_attribute *attribute) - { - assert(attribute && !attribute->parent()); - if (first_attribute()) - { - attribute->m_prev_attribute = m_last_attribute; - m_last_attribute->m_next_attribute = attribute; - } - else - { - attribute->m_prev_attribute = 0; - m_first_attribute = attribute; - } - m_last_attribute = attribute; - attribute->m_parent = this; - attribute->m_next_attribute = 0; - } - - //! Inserts a new attribute at specified place inside the node. - //! All attributes after and including the specified attribute are moved one position back. - //! \param where Place where to insert the attribute, or 0 to insert at the back. - //! \param attribute Attribute to insert. - void insert_attribute(xml_attribute *where, xml_attribute *attribute) - { - assert(!where || where->parent() == this); - assert(attribute && !attribute->parent()); - if (where == m_first_attribute) - prepend_attribute(attribute); - else if (where == 0) - append_attribute(attribute); - else - { - attribute->m_prev_attribute = where->m_prev_attribute; - attribute->m_next_attribute = where; - where->m_prev_attribute->m_next_attribute = attribute; - where->m_prev_attribute = attribute; - attribute->m_parent = this; - } - } - - //! Removes first attribute of the node. - //! If node has no attributes, behaviour is undefined. - //! Use first_attribute() to test if node has attributes. - void remove_first_attribute() - { - assert(first_attribute()); - xml_attribute *attribute = m_first_attribute; - if (attribute->m_next_attribute) - { - attribute->m_next_attribute->m_prev_attribute = 0; - } - else - m_last_attribute = 0; - attribute->m_parent = 0; - m_first_attribute = attribute->m_next_attribute; - } - - //! Removes last attribute of the node. - //! If node has no attributes, behaviour is undefined. - //! Use first_attribute() to test if node has attributes. - void remove_last_attribute() - { - assert(first_attribute()); - xml_attribute *attribute = m_last_attribute; - if (attribute->m_prev_attribute) - { - attribute->m_prev_attribute->m_next_attribute = 0; - m_last_attribute = attribute->m_prev_attribute; - } - else - m_first_attribute = 0; - attribute->m_parent = 0; - } - - //! Removes specified attribute from node. - //! \param where Pointer to attribute to be removed. - void remove_attribute(xml_attribute *where) - { - assert(first_attribute() && where->parent() == this); - if (where == m_first_attribute) - remove_first_attribute(); - else if (where == m_last_attribute) - remove_last_attribute(); - else - { - where->m_prev_attribute->m_next_attribute = where->m_next_attribute; - where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; - where->m_parent = 0; - } - } - - //! Removes all attributes of node. - void remove_all_attributes() - { - for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) - attribute->m_parent = 0; - m_first_attribute = 0; - } - - private: - - /////////////////////////////////////////////////////////////////////////// - // Restrictions - - // No copying - xml_node(const xml_node &); - void operator =(const xml_node &); - - /////////////////////////////////////////////////////////////////////////// - // Data members - - // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. - // This is required for maximum performance, as it allows the parser to omit initialization of - // unneded/redundant values. - // - // The rules are as follows: - // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively - // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage - // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage - - node_type m_type; // Type of node; always valid - xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid - xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero - xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid - xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero - xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero - xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero - - }; - - /////////////////////////////////////////////////////////////////////////// - // XML document - - //! This class represents root of the DOM hierarchy. - //! It is also an xml_node and a memory_pool through public inheritance. - //! Use parse() function to build a DOM tree from a zero-terminated XML text string. - //! parse() function allocates memory for nodes and attributes by using functions of xml_document, - //! which are inherited from memory_pool. - //! To access root node of the document, use the document itself, as if it was an xml_node. - //! \param Ch Character type to use. - template - class xml_document: public xml_node, public memory_pool - { - - public: - - //! Constructs empty XML document - xml_document() - : xml_node(node_document) - { - } - - //! Parses zero-terminated XML string according to given flags. - //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. - //! The string must persist for the lifetime of the document. - //! In case of error, rapidxml::parse_error exception will be thrown. - //!

- //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. - //! Make sure that data is zero-terminated. - //!

- //! Document can be parsed into multiple times. - //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. - //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. - template - void parse(Ch *text) - { - assert(text); - - // Remove current contents - this->remove_all_nodes(); - this->remove_all_attributes(); - - // Parse BOM, if any - parse_bom(text); - - // Parse children - while (1) - { - // Skip whitespace before node - skip(text); - if (*text == 0) - break; - - // Parse and append new child - if (*text == Ch('<')) - { - ++text; // Skip '<' - if (xml_node *node = parse_node(text)) - this->append_node(node); - } - else - RAPIDXML_PARSE_ERROR("expected <", text); - } - - } - - //! Clears the document by deleting all nodes and clearing the memory pool. - //! All nodes owned by document pool are destroyed. - void clear() - { - this->remove_all_nodes(); - this->remove_all_attributes(); - memory_pool::clear(); - } - - private: - - /////////////////////////////////////////////////////////////////////// - // Internal character utility functions - - // Detect whitespace character - struct whitespace_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; - } - }; - - // Detect node name character - struct node_name_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; - } - }; - - // Detect attribute name character - struct attribute_name_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; - } - }; - - // Detect text character (PCDATA) - struct text_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; - } - }; - - // Detect text character (PCDATA) that does not require processing - struct text_pure_no_ws_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; - } - }; - - // Detect text character (PCDATA) that does not require processing - struct text_pure_with_ws_pred - { - static unsigned char test(Ch ch) - { - return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; - } - }; - - // Detect attribute value character - template - struct attribute_value_pred - { - static unsigned char test(Ch ch) - { - if (Quote == Ch('\'')) - return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; - if (Quote == Ch('\"')) - return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; - return 0; // Should never be executed, to avoid warnings on Comeau - } - }; - - // Detect attribute value character - template - struct attribute_value_pure_pred - { - static unsigned char test(Ch ch) - { - if (Quote == Ch('\'')) - return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; - if (Quote == Ch('\"')) - return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; - return 0; // Should never be executed, to avoid warnings on Comeau - } - }; - - // Insert coded character, using UTF8 or 8-bit ASCII - template - static void insert_coded_character(Ch *&text, unsigned long code) - { - if (Flags & parse_no_utf8) - { - // Insert 8-bit ASCII character - // Todo: possibly verify that code is less than 256 and use replacement char otherwise? - text[0] = static_cast(code); - text += 1; - } - else - { - // Insert UTF8 sequence - if (code < 0x80) // 1 byte sequence - { - text[0] = static_cast(code); - text += 1; - } - else if (code < 0x800) // 2 byte sequence - { - text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[0] = static_cast(code | 0xC0); - text += 2; - } - else if (code < 0x10000) // 3 byte sequence - { - text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[0] = static_cast(code | 0xE0); - text += 3; - } - else if (code < 0x110000) // 4 byte sequence - { - text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; - text[0] = static_cast(code | 0xF0); - text += 4; - } - else // Invalid, only codes up to 0x10FFFF are allowed in Unicode - { - RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); - } - } - } - - // Skip characters until predicate evaluates to true - template - static void skip(Ch *&text) - { - Ch *tmp = text; - while (StopPred::test(*tmp)) - ++tmp; - text = tmp; - } - - // Skip characters until predicate evaluates to true while doing the following: - // - replacing XML character entity references with proper characters (' & " < > &#...;) - // - condensing whitespace sequences to single space character - template - static Ch *skip_and_expand_character_refs(Ch *&text) - { - // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip - if (Flags & parse_no_entity_translation && - !(Flags & parse_normalize_whitespace) && - !(Flags & parse_trim_whitespace)) - { - skip(text); - return text; - } - - // Use simple skip until first modification is detected - skip(text); - - // Use translation skip - Ch *src = text; - Ch *dest = src; - while (StopPred::test(*src)) - { - // If entity translation is enabled - if (!(Flags & parse_no_entity_translation)) - { - // Test if replacement is needed - if (src[0] == Ch('&')) - { - switch (src[1]) - { - - // & ' - case Ch('a'): - if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) - { - *dest = Ch('&'); - ++dest; - src += 5; - continue; - } - if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) - { - *dest = Ch('\''); - ++dest; - src += 6; - continue; - } - break; - - // " - case Ch('q'): - if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) - { - *dest = Ch('"'); - ++dest; - src += 6; - continue; - } - break; - - // > - case Ch('g'): - if (src[2] == Ch('t') && src[3] == Ch(';')) - { - *dest = Ch('>'); - ++dest; - src += 4; - continue; - } - break; - - // < - case Ch('l'): - if (src[2] == Ch('t') && src[3] == Ch(';')) - { - *dest = Ch('<'); - ++dest; - src += 4; - continue; - } - break; - - // &#...; - assumes ASCII - case Ch('#'): - if (src[2] == Ch('x')) - { - unsigned long code = 0; - src += 3; // Skip &#x - while (1) - { - unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; - if (digit == 0xFF) - break; - code = code * 16 + digit; - ++src; - } - insert_coded_character(dest, code); // Put character in output - } - else - { - unsigned long code = 0; - src += 2; // Skip &# - while (1) - { - unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; - if (digit == 0xFF) - break; - code = code * 10 + digit; - ++src; - } - insert_coded_character(dest, code); // Put character in output - } - if (*src == Ch(';')) - ++src; - else - RAPIDXML_PARSE_ERROR("expected ;", src); - continue; - - // Something else - default: - // Ignore, just copy '&' verbatim - break; - - } - } - } - - // If whitespace condensing is enabled - if (Flags & parse_normalize_whitespace) - { - // Test if condensing is needed - if (whitespace_pred::test(*src)) - { - *dest = Ch(' '); ++dest; // Put single space in dest - ++src; // Skip first whitespace char - // Skip remaining whitespace chars - while (whitespace_pred::test(*src)) - ++src; - continue; - } - } - - // No replacement, only copy character - *dest++ = *src++; - - } - - // Return new end - text = src; - return dest; - - } - - /////////////////////////////////////////////////////////////////////// - // Internal parsing functions - - // Parse BOM, if any - template - void parse_bom(Ch *&text) - { - // UTF-8? - if (static_cast(text[0]) == 0xEF && - static_cast(text[1]) == 0xBB && - static_cast(text[2]) == 0xBF) - { - text += 3; // Skup utf-8 bom - } - } - - // Parse XML declaration ( - xml_node *parse_xml_declaration(Ch *&text) - { - // If parsing of declaration is disabled - if (!(Flags & parse_declaration_node)) - { - // Skip until end of declaration - while (text[0] != Ch('?') || text[1] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - text += 2; // Skip '?>' - return 0; - } - - // Create declaration - xml_node *declaration = this->allocate_node(node_declaration); - - // Skip whitespace before attributes or ?> - skip(text); - - // Parse declaration attributes - parse_node_attributes(text, declaration); - - // Skip ?> - if (text[0] != Ch('?') || text[1] != Ch('>')) - RAPIDXML_PARSE_ERROR("expected ?>", text); - text += 2; - - return declaration; - } - - // Parse XML comment (' - return 0; // Do not produce comment node - } - - // Remember value start - Ch *value = text; - - // Skip until end of comment - while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - - // Create comment node - xml_node *comment = this->allocate_node(node_comment); - comment->value(value, text - value); - - // Place zero terminator after comment value - if (!(Flags & parse_no_string_terminators)) - *text = Ch('\0'); - - text += 3; // Skip '-->' - return comment; - } - - // Parse DOCTYPE - template - xml_node *parse_doctype(Ch *&text) - { - // Remember value start - Ch *value = text; - - // Skip to > - while (*text != Ch('>')) - { - // Determine character type - switch (*text) - { - - // If '[' encountered, scan for matching ending ']' using naive algorithm with depth - // This works for all W3C test files except for 2 most wicked - case Ch('['): - { - ++text; // Skip '[' - int depth = 1; - while (depth > 0) - { - switch (*text) - { - case Ch('['): ++depth; break; - case Ch(']'): --depth; break; - case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); - } - ++text; - } - break; - } - - // Error on end of text - case Ch('\0'): - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - - // Other character, skip it - default: - ++text; - - } - } - - // If DOCTYPE nodes enabled - if (Flags & parse_doctype_node) - { - // Create a new doctype node - xml_node *doctype = this->allocate_node(node_doctype); - doctype->value(value, text - value); - - // Place zero terminator after value - if (!(Flags & parse_no_string_terminators)) - *text = Ch('\0'); - - text += 1; // skip '>' - return doctype; - } - else - { - text += 1; // skip '>' - return 0; - } - - } - - // Parse PI - template - xml_node *parse_pi(Ch *&text) - { - // If creation of PI nodes is enabled - if (Flags & parse_pi_nodes) - { - // Create pi node - xml_node *pi = this->allocate_node(node_pi); - - // Extract PI target name - Ch *name = text; - skip(text); - if (text == name) - RAPIDXML_PARSE_ERROR("expected PI target", text); - pi->name(name, text - name); - - // Skip whitespace between pi target and pi - skip(text); - - // Remember start of pi - Ch *value = text; - - // Skip to '?>' - while (text[0] != Ch('?') || text[1] != Ch('>')) - { - if (*text == Ch('\0')) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - - // Set pi value (verbatim, no entity expansion or whitespace normalization) - pi->value(value, text - value); - - // Place zero terminator after name and value - if (!(Flags & parse_no_string_terminators)) - { - pi->name()[pi->name_size()] = Ch('\0'); - pi->value()[pi->value_size()] = Ch('\0'); - } - - text += 2; // Skip '?>' - return pi; - } - else - { - // Skip to '?>' - while (text[0] != Ch('?') || text[1] != Ch('>')) - { - if (*text == Ch('\0')) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - text += 2; // Skip '?>' - return 0; - } - } - - // Parse and append data - // Return character that ends data. - // This is necessary because this character might have been overwritten by a terminating 0 - template - Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) - { - // Backup to contents start if whitespace trimming is disabled - if (!(Flags & parse_trim_whitespace)) - text = contents_start; - - // Skip until end of data - Ch *value = text, *end; - if (Flags & parse_normalize_whitespace) - end = skip_and_expand_character_refs(text); - else - end = skip_and_expand_character_refs(text); - - // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > - if (Flags & parse_trim_whitespace) - { - if (Flags & parse_normalize_whitespace) - { - // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end - if (*(end - 1) == Ch(' ')) - --end; - } - else - { - // Backup until non-whitespace character is found - while (whitespace_pred::test(*(end - 1))) - --end; - } - } - - // If characters are still left between end and value (this test is only necessary if normalization is enabled) - // Create new data node - if (!(Flags & parse_no_data_nodes)) - { - xml_node *data = this->allocate_node(node_data); - data->value(value, end - value); - node->append_node(data); - } - - // Add data to parent node if no data exists yet - if (!(Flags & parse_no_element_values)) - if (*node->value() == Ch('\0')) - node->value(value, end - value); - - // Place zero terminator after value - if (!(Flags & parse_no_string_terminators)) - { - Ch ch = *text; - *end = Ch('\0'); - return ch; // Return character that ends data; this is required because zero terminator overwritten it - } - - // Return character that ends data - return *text; - } - - // Parse CDATA - template - xml_node *parse_cdata(Ch *&text) - { - // If CDATA is disabled - if (Flags & parse_no_data_nodes) - { - // Skip until end of cdata - while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - text += 3; // Skip ]]> - return 0; // Do not produce CDATA node - } - - // Skip until end of cdata - Ch *value = text; - while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) - { - if (!text[0]) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - - // Create new cdata node - xml_node *cdata = this->allocate_node(node_cdata); - cdata->value(value, text - value); - - // Place zero terminator after value - if (!(Flags & parse_no_string_terminators)) - *text = Ch('\0'); - - text += 3; // Skip ]]> - return cdata; - } - - // Parse element node - template - xml_node *parse_element(Ch *&text) - { - // Create element node - xml_node *element = this->allocate_node(node_element); - - // Extract element name - Ch *name = text; - skip(text); - if (text == name) - RAPIDXML_PARSE_ERROR("expected element name", text); - element->name(name, text - name); - - // Skip whitespace between element name and attributes or > - skip(text); - - // Parse attributes, if any - parse_node_attributes(text, element); - - // Determine ending type - if (*text == Ch('>')) - { - ++text; - parse_node_contents(text, element); - } - else if (*text == Ch('/')) - { - ++text; - if (*text != Ch('>')) - RAPIDXML_PARSE_ERROR("expected >", text); - ++text; - } - else - RAPIDXML_PARSE_ERROR("expected >", text); - - // Place zero terminator after name - if (!(Flags & parse_no_string_terminators)) - element->name()[element->name_size()] = Ch('\0'); - - // Return parsed element - return element; - } - - // Determine node type, and parse it - template - xml_node *parse_node(Ch *&text) - { - // Parse proper node type - switch (text[0]) - { - - // <... - default: - // Parse and append element node - return parse_element(text); - - // (text); - } - else - { - // Parse PI - return parse_pi(text); - } - - // (text); - } - break; - - // (text); - } - break; - - // (text); - } - - } // switch - - // Attempt to skip other, unrecognized node types starting with ')) - { - if (*text == 0) - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - ++text; - } - ++text; // Skip '>' - return 0; // No node recognized - - } - } - - // Parse contents of the node - children, data etc. - template - void parse_node_contents(Ch *&text, xml_node *node) - { - // For all children and text - while (1) - { - // Skip whitespace between > and node contents - Ch *contents_start = text; // Store start of node contents before whitespace is skipped - skip(text); - Ch next_char = *text; - - // After data nodes, instead of continuing the loop, control jumps here. - // This is because zero termination inside parse_and_append_data() function - // would wreak havoc with the above code. - // Also, skipping whitespace after data nodes is unnecessary. - after_data_node: - - // Determine what comes next: node closing, child node, data node, or 0? - switch (next_char) - { - - // Node closing or child node - case Ch('<'): - if (text[1] == Ch('/')) - { - // Node closing - text += 2; // Skip '(text); - if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) - RAPIDXML_PARSE_ERROR("invalid closing tag name", text); - } - else - { - // No validation, just skip name - skip(text); - } - // Skip remaining whitespace after node name - skip(text); - if (*text != Ch('>')) - RAPIDXML_PARSE_ERROR("expected >", text); - ++text; // Skip '>' - return; // Node closed, finished parsing contents - } - else - { - // Child node - ++text; // Skip '<' - if (xml_node *child = parse_node(text)) - node->append_node(child); - } - break; - - // End of data - error - case Ch('\0'): - RAPIDXML_PARSE_ERROR("unexpected end of data", text); - - // Data node - default: - next_char = parse_and_append_data(node, text, contents_start); - goto after_data_node; // Bypass regular processing after data nodes - - } - } - } - - // Parse XML attributes of the node - template - void parse_node_attributes(Ch *&text, xml_node *node) - { - // For all attributes - while (attribute_name_pred::test(*text)) - { - // Extract attribute name - Ch *name = text; - ++text; // Skip first character of attribute name - skip(text); - if (text == name) - RAPIDXML_PARSE_ERROR("expected attribute name", name); - - // Create new attribute - xml_attribute *attribute = this->allocate_attribute(); - attribute->name(name, text - name); - node->append_attribute(attribute); - - // Skip whitespace after attribute name - skip(text); - - // Skip = - if (*text != Ch('=')) - RAPIDXML_PARSE_ERROR("expected =", text); - ++text; - - // Add terminating zero after name - if (!(Flags & parse_no_string_terminators)) - attribute->name()[attribute->name_size()] = 0; - - // Skip whitespace after = - skip(text); - - // Skip quote and remember if it was ' or " - Ch quote = *text; - if (quote != Ch('\'') && quote != Ch('"')) - RAPIDXML_PARSE_ERROR("expected ' or \"", text); - ++text; - - // Extract attribute value and expand char refs in it - Ch *value = text, *end; - const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes - if (quote == Ch('\'')) - end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); - else - end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); - - // Set attribute value - attribute->value(value, end - value); - - // Make sure that end quote is present - if (*text != quote) - RAPIDXML_PARSE_ERROR("expected ' or \"", text); - ++text; // Skip quote - - // Add terminating zero after value - if (!(Flags & parse_no_string_terminators)) - attribute->value()[attribute->value_size()] = 0; - - // Skip whitespace after attribute value - skip(text); - } - } - - }; - - //! \cond internal - namespace internal - { - - // Whitespace (space \n \r \t) - template - const unsigned char lookup_tables::lookup_whitespace[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F - }; - - // Node name (anything but space \n \r \t / > ? \0) - template - const unsigned char lookup_tables::lookup_node_name[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Text (i.e. PCDATA) (anything but < \0) - template - const unsigned char lookup_tables::lookup_text[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled - // (anything but < \0 &) - template - const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled - // (anything but < \0 & space \n \r \t) - template - const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute name (anything but space \n \r \t / < > = ? ! \0) - template - const unsigned char lookup_tables::lookup_attribute_name[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with single quote (anything but ' \0) - template - const unsigned char lookup_tables::lookup_attribute_data_1[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with single quote that does not require processing (anything but ' \0 &) - template - const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with double quote (anything but " \0) - template - const unsigned char lookup_tables::lookup_attribute_data_2[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Attribute data with double quote that does not require processing (anything but " \0 &) - template - const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F - }; - - // Digits (dec and hex, 255 denotes end of numeric character reference) - template - const unsigned char lookup_tables::lookup_digits[256] = - { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 - 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 - 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F - }; - - // Upper case conversion - template - const unsigned char lookup_tables::lookup_upcase[256] = - { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 - 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F - }; - } - //! \endcond - -} - -// Undefine internal macros -#undef RAPIDXML_PARSE_ERROR - -// On MSVC, restore warnings state -#ifdef _MSC_VER - #pragma warning(pop) -#endif - -#endif diff --git a/CocXlsxTool/rapidxml_iterators.hpp b/CocXlsxTool/rapidxml_iterators.hpp deleted file mode 100644 index 52ebc298..00000000 --- a/CocXlsxTool/rapidxml_iterators.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED -#define RAPIDXML_ITERATORS_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml_iterators.hpp This file contains rapidxml iterators - -#include "rapidxml.hpp" - -namespace rapidxml -{ - - //! Iterator of child nodes of xml_node - template - class node_iterator - { - - public: - - typedef typename xml_node value_type; - typedef typename xml_node &reference; - typedef typename xml_node *pointer; - typedef std::ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - node_iterator() - : m_node(0) - { - } - - node_iterator(xml_node *node) - : m_node(node->first_node()) - { - } - - reference operator *() const - { - assert(m_node); - return *m_node; - } - - pointer operator->() const - { - assert(m_node); - return m_node; - } - - node_iterator& operator++() - { - assert(m_node); - m_node = m_node->next_sibling(); - return *this; - } - - node_iterator operator++(int) - { - node_iterator tmp = *this; - ++this; - return tmp; - } - - node_iterator& operator--() - { - assert(m_node && m_node->previous_sibling()); - m_node = m_node->previous_sibling(); - return *this; - } - - node_iterator operator--(int) - { - node_iterator tmp = *this; - ++this; - return tmp; - } - - bool operator ==(const node_iterator &rhs) - { - return m_node == rhs.m_node; - } - - bool operator !=(const node_iterator &rhs) - { - return m_node != rhs.m_node; - } - - private: - - xml_node *m_node; - - }; - - //! Iterator of child attributes of xml_node - template - class attribute_iterator - { - - public: - - typedef typename xml_attribute value_type; - typedef typename xml_attribute &reference; - typedef typename xml_attribute *pointer; - typedef std::ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - attribute_iterator() - : m_attribute(0) - { - } - - attribute_iterator(xml_node *node) - : m_attribute(node->first_attribute()) - { - } - - reference operator *() const - { - assert(m_attribute); - return *m_attribute; - } - - pointer operator->() const - { - assert(m_attribute); - return m_attribute; - } - - attribute_iterator& operator++() - { - assert(m_attribute); - m_attribute = m_attribute->next_attribute(); - return *this; - } - - attribute_iterator operator++(int) - { - attribute_iterator tmp = *this; - ++this; - return tmp; - } - - attribute_iterator& operator--() - { - assert(m_attribute && m_attribute->previous_attribute()); - m_attribute = m_attribute->previous_attribute(); - return *this; - } - - attribute_iterator operator--(int) - { - attribute_iterator tmp = *this; - ++this; - return tmp; - } - - bool operator ==(const attribute_iterator &rhs) - { - return m_attribute == rhs.m_attribute; - } - - bool operator !=(const attribute_iterator &rhs) - { - return m_attribute != rhs.m_attribute; - } - - private: - - xml_attribute *m_attribute; - - }; - -} - -#endif diff --git a/CocXlsxTool/rapidxml_print.hpp b/CocXlsxTool/rapidxml_print.hpp deleted file mode 100644 index 7a6ac51c..00000000 --- a/CocXlsxTool/rapidxml_print.hpp +++ /dev/null @@ -1,421 +0,0 @@ -#ifndef RAPIDXML_PRINT_HPP_INCLUDED -#define RAPIDXML_PRINT_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml_print.hpp This file contains rapidxml printer implementation - -#include "rapidxml.hpp" - -// Only include streams if not disabled -#ifndef RAPIDXML_NO_STREAMS - #include - #include -#endif - -namespace rapidxml -{ - - /////////////////////////////////////////////////////////////////////// - // Printing flags - - const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. - - /////////////////////////////////////////////////////////////////////// - // Internal - - //! \cond internal - namespace internal - { - - /////////////////////////////////////////////////////////////////////////// - // Internal character operations - - // Copy characters from given range to given output iterator - template - inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) - { - while (begin != end) - *out++ = *begin++; - return out; - } - - // Copy characters from given range to given output iterator and expand - // characters into references (< > ' " &) - template - inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) - { - while (begin != end) - { - if (*begin == noexpand) - { - *out++ = *begin; // No expansion, copy character - } - else - { - switch (*begin) - { - case Ch('<'): - *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); - break; - case Ch('>'): - *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); - break; - case Ch('\''): - *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); - break; - case Ch('"'): - *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); - break; - case Ch('&'): - *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); - break; - default: - *out++ = *begin; // No expansion, copy character - } - } - ++begin; // Step to next character - } - return out; - } - - // Fill given output iterator with repetitions of the same character - template - inline OutIt fill_chars(OutIt out, int n, Ch ch) - { - for (int i = 0; i < n; ++i) - *out++ = ch; - return out; - } - - // Find character - template - inline bool find_char(const Ch *begin, const Ch *end) - { - while (begin != end) - if (*begin++ == ch) - return true; - return false; - } - - /////////////////////////////////////////////////////////////////////////// - // Internal printing operations - - // Print node - template - inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) - { - // Print proper node type - switch (node->type()) - { - - // Document - case node_document: - out = print_children(out, node, flags, indent); - break; - - // Element - case node_element: - out = print_element_node(out, node, flags, indent); - break; - - // Data - case node_data: - out = print_data_node(out, node, flags, indent); - break; - - // CDATA - case node_cdata: - out = print_cdata_node(out, node, flags, indent); - break; - - // Declaration - case node_declaration: - out = print_declaration_node(out, node, flags, indent); - break; - - // Comment - case node_comment: - out = print_comment_node(out, node, flags, indent); - break; - - // Doctype - case node_doctype: - out = print_doctype_node(out, node, flags, indent); - break; - - // Pi - case node_pi: - out = print_pi_node(out, node, flags, indent); - break; - - // Unknown - default: - assert(0); - break; - } - - // If indenting not disabled, add line break after node - if (!(flags & print_no_indenting)) - *out = Ch('\n'), ++out; - - // Return modified iterator - return out; - } - - // Print children of the node - template - inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) - { - for (xml_node *child = node->first_node(); child; child = child->next_sibling()) - out = print_node(out, child, flags, indent); - return out; - } - - // Print attributes of the node - template - inline OutIt print_attributes(OutIt out, const xml_node *node) - { - for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) - { - if (attribute->name() && attribute->value()) - { - // Print attribute name - *out = Ch(' '), ++out; - out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); - *out = Ch('='), ++out; - // Print attribute value using appropriate quote type - if (find_char(attribute->value(), attribute->value() + attribute->value_size())) - { - *out = Ch('\''), ++out; - out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); - *out = Ch('\''), ++out; - } - else - { - *out = Ch('"'), ++out; - out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); - *out = Ch('"'), ++out; - } - } - } - return out; - } - - // Print data node - template - inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_data); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); - return out; - } - - // Print data node - template - inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_cdata); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'); ++out; - *out = Ch('!'); ++out; - *out = Ch('['); ++out; - *out = Ch('C'); ++out; - *out = Ch('D'); ++out; - *out = Ch('A'); ++out; - *out = Ch('T'); ++out; - *out = Ch('A'); ++out; - *out = Ch('['); ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch(']'); ++out; - *out = Ch(']'); ++out; - *out = Ch('>'); ++out; - return out; - } - - // Print element node - template - inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_element); - - // Print element name and attributes, if any - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - out = copy_chars(node->name(), node->name() + node->name_size(), out); - out = print_attributes(out, node); - - // If node is childless - if (node->value_size() == 0 && !node->first_node()) - { - // Print childless node tag ending - *out = Ch('/'), ++out; - *out = Ch('>'), ++out; - } - else - { - // Print normal node tag ending - *out = Ch('>'), ++out; - - // Test if node contains a single data node only (and no other nodes) - xml_node *child = node->first_node(); - if (!child) - { - // If node has no children, only print its value without indenting - out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); - } - else if (child->next_sibling() == 0 && child->type() == node_data) - { - // If node has a sole data child, only print its value without indenting - out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); - } - else - { - // Print all children with full indenting - if (!(flags & print_no_indenting)) - *out = Ch('\n'), ++out; - out = print_children(out, node, flags, indent + 1); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - } - - // Print node end - *out = Ch('<'), ++out; - *out = Ch('/'), ++out; - out = copy_chars(node->name(), node->name() + node->name_size(), out); - *out = Ch('>'), ++out; - } - return out; - } - - // Print declaration node - template - inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) - { - // Print declaration start - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('?'), ++out; - *out = Ch('x'), ++out; - *out = Ch('m'), ++out; - *out = Ch('l'), ++out; - - // Print attributes - out = print_attributes(out, node); - - // Print declaration end - *out = Ch('?'), ++out; - *out = Ch('>'), ++out; - - return out; - } - - // Print comment node - template - inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_comment); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('!'), ++out; - *out = Ch('-'), ++out; - *out = Ch('-'), ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch('-'), ++out; - *out = Ch('-'), ++out; - *out = Ch('>'), ++out; - return out; - } - - // Print doctype node - template - inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_doctype); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('!'), ++out; - *out = Ch('D'), ++out; - *out = Ch('O'), ++out; - *out = Ch('C'), ++out; - *out = Ch('T'), ++out; - *out = Ch('Y'), ++out; - *out = Ch('P'), ++out; - *out = Ch('E'), ++out; - *out = Ch(' '), ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch('>'), ++out; - return out; - } - - // Print pi node - template - inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) - { - assert(node->type() == node_pi); - if (!(flags & print_no_indenting)) - out = fill_chars(out, indent, Ch('\t')); - *out = Ch('<'), ++out; - *out = Ch('?'), ++out; - out = copy_chars(node->name(), node->name() + node->name_size(), out); - *out = Ch(' '), ++out; - out = copy_chars(node->value(), node->value() + node->value_size(), out); - *out = Ch('?'), ++out; - *out = Ch('>'), ++out; - return out; - } - - } - //! \endcond - - /////////////////////////////////////////////////////////////////////////// - // Printing - - //! Prints XML to given output iterator. - //! \param out Output iterator to print to. - //! \param node Node to be printed. Pass xml_document to print entire document. - //! \param flags Flags controlling how XML is printed. - //! \return Output iterator pointing to position immediately after last character of printed text. - template - inline OutIt print(OutIt out, const xml_node &node, int flags = 0) - { - return internal::print_node(out, &node, flags, 0); - } - -#ifndef RAPIDXML_NO_STREAMS - - //! Prints XML to given output stream. - //! \param out Output stream to print to. - //! \param node Node to be printed. Pass xml_document to print entire document. - //! \param flags Flags controlling how XML is printed. - //! \return Output stream. - template - inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) - { - print(std::ostream_iterator(out), node, flags); - return out; - } - - //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. - //! \param out Output stream to print to. - //! \param node Node to be printed. - //! \return Output stream. - template - inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) - { - return print(out, node); - } - -#endif - -} - -#endif diff --git a/CocXlsxTool/rapidxml_utils.hpp b/CocXlsxTool/rapidxml_utils.hpp deleted file mode 100644 index 37c29535..00000000 --- a/CocXlsxTool/rapidxml_utils.hpp +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef RAPIDXML_UTILS_HPP_INCLUDED -#define RAPIDXML_UTILS_HPP_INCLUDED - -// Copyright (C) 2006, 2009 Marcin Kalicinski -// Version 1.13 -// Revision $DateTime: 2009/05/13 01:46:17 $ -//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful -//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. - -#include "rapidxml.hpp" -#include -#include -#include -#include - -namespace rapidxml -{ - - //! Represents data loaded from a file - template - class file - { - - public: - - //! Loads file into the memory. Data will be automatically destroyed by the destructor. - //! \param filename Filename to load. - file(const char *filename) - { - using namespace std; - - // Open stream - basic_ifstream stream(filename, ios::binary); - if (!stream) - throw runtime_error(string("cannot open file ") + filename); - stream.unsetf(ios::skipws); - - // Determine stream size - stream.seekg(0, ios::end); - size_t size = stream.tellg(); - stream.seekg(0); - - // Load data and add terminating 0 - m_data.resize(size + 1); - stream.read(&m_data.front(), static_cast(size)); - m_data[size] = 0; - } - - //! Loads file into the memory. Data will be automatically destroyed by the destructor - //! \param stream Stream to load from - file(std::basic_istream &stream) - { - using namespace std; - - // Load data and add terminating 0 - stream.unsetf(ios::skipws); - m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); - if (stream.fail() || stream.bad()) - throw runtime_error("error reading stream"); - m_data.push_back(0); - } - - //! Gets file data. - //! \return Pointer to data of file. - Ch *data() - { - return &m_data.front(); - } - - //! Gets file data. - //! \return Pointer to data of file. - const Ch *data() const - { - return &m_data.front(); - } - - //! Gets file data size. - //! \return Size of file data, in characters. - std::size_t size() const - { - return m_data.size(); - } - - private: - - std::vector m_data; // File data - - }; - - //! Counts children of node. Time complexity is O(n). - //! \return Number of children of node - template - inline std::size_t count_children(xml_node *node) - { - xml_node *child = node->first_node(); - std::size_t count = 0; - while (child) - { - ++count; - child = child->next_sibling(); - } - return count; - } - - //! Counts attributes of node. Time complexity is O(n). - //! \return Number of attributes of node - template - inline std::size_t count_attributes(xml_node *node) - { - xml_attribute *attr = node->first_attribute(); - std::size_t count = 0; - while (attr) - { - ++count; - attr = attr->next_attribute(); - } - return count; - } - -} - -#endif diff --git a/CocXlsxTool/unzip.cpp b/CocXlsxTool/unzip.cpp deleted file mode 100644 index b9e32c50..00000000 --- a/CocXlsxTool/unzip.cpp +++ /dev/null @@ -1,4165 +0,0 @@ -#define _CRT_SECURE_NO_WARNINGS - -#include -#include -#include -#include -#include -#include "unzip.h" - - -// THIS FILE is almost entirely based upon code by Jean-loup Gailly -// and Mark Adler. It has been modified by Lucian Wischik. -// The modifications were: incorporate the bugfixes of 1.1.4, allow -// unzipping to/from handles/pipes/files/memory, encryption, unicode, -// a windowsish api, and putting everything into a single .cpp file. -// The original code may be found at http://www.gzip.org/zlib/ -// The original copyright text follows. -// -// -// -// zlib.h -- interface of the 'zlib' general purpose compression library -// version 1.1.3, July 9th, 1998 -// -// Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. -// -// Jean-loup Gailly Mark Adler -// jloup@gzip.org madler@alumni.caltech.edu -// -// -// The data format used by the zlib library is described by RFCs (Request for -// Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt -// (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -// -// -// The 'zlib' compression library provides in-memory compression and -// decompression functions, including integrity checks of the uncompressed -// data. This version of the library supports only one compression method -// (deflation) but other algorithms will be added later and will have the same -// stream interface. -// -// Compression can be done in a single step if the buffers are large -// enough (for example if an input file is mmap'ed), or can be done by -// repeated calls of the compression function. In the latter case, the -// application must provide more input and/or consume the output -// (providing more output space) before each call. -// -// The library also supports reading and writing files in gzip (.gz) format -// with an interface similar to that of stdio. -// -// The library does not install any signal handler. The decoder checks -// the consistency of the compressed data, so the library should never -// crash even in case of corrupted input. -// -// for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip -// PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip - -#define ZIP_HANDLE 1 -#define ZIP_FILENAME 2 -#define ZIP_MEMORY 3 - - -#define zmalloc(len) malloc(len) - -#define zfree(p) free(p) - -/* -void *zmalloc(unsigned int len) -{ char *buf = new char[len+32]; - for (int i=0; i<16; i++) - { buf[i]=i; - buf[len+31-i]=i; - } - *((unsigned int*)buf) = len; - char c[1000]; wsprintf(c,"malloc 0x%lx - %lu",buf+16,len); - OutputDebugString(c); - return buf+16; -} - -void zfree(void *buf) -{ char c[1000]; wsprintf(c,"free 0x%lx",buf); - OutputDebugString(c); - char *p = ((char*)buf)-16; - unsigned int len = *((unsigned int*)p); - bool blown=false; - for (int i=0; i<16; i++) - { char lo = p[i]; - char hi = p[len+31-i]; - if (hi!=i || (lo!=i && i>4)) blown=true; - } - if (blown) - { OutputDebugString("BLOWN!!!"); - } - delete[] p; -} -*/ - - -typedef struct tm_unz_s -{ unsigned int tm_sec; // seconds after the minute - [0,59] - unsigned int tm_min; // minutes after the hour - [0,59] - unsigned int tm_hour; // hours since midnight - [0,23] - unsigned int tm_mday; // day of the month - [1,31] - unsigned int tm_mon; // months since January - [0,11] - unsigned int tm_year; // years - [1980..2044] -} tm_unz; - - -// unz_global_info structure contain global data about the ZIPfile -typedef struct unz_global_info_s -{ unsigned long number_entry; // total number of entries in the central dir on this disk - unsigned long size_comment; // size of the global comment of the zipfile -} unz_global_info; - -// unz_file_info contain information about a file in the zipfile -typedef struct unz_file_info_s -{ unsigned long version; // version made by 2 bytes - unsigned long version_needed; // version needed to extract 2 bytes - unsigned long flag; // general purpose bit flag 2 bytes - unsigned long compression_method; // compression method 2 bytes - unsigned long dosDate; // last mod file date in Dos fmt 4 bytes - unsigned long crc; // crc-32 4 bytes - unsigned long compressed_size; // compressed size 4 bytes - unsigned long uncompressed_size; // uncompressed size 4 bytes - unsigned long size_filename; // filename length 2 bytes - unsigned long size_file_extra; // extra field length 2 bytes - unsigned long size_file_comment; // file comment length 2 bytes - unsigned long disk_num_start; // disk number start 2 bytes - unsigned long internal_fa; // internal file attributes 2 bytes - unsigned long external_fa; // external file attributes 4 bytes - tm_unz tmu_date; -} unz_file_info; - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) -#define UNZ_PASSWORD (-106) - - - - - - - -#define ZLIB_VERSION "1.1.3" - - -// Allowed flush values; see deflate() for details -#define Z_NO_FLUSH 0 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 - - -// compression levels -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) - -// compression strategy; see deflateInit2() for details -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 - -// Possible values of the data_type field -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 - -// The deflate compression method (the only one supported in this version) -#define Z_DEFLATED 8 - -// for initializing zalloc, zfree, opaque -#define Z_NULL 0 - -// case sensitivity when searching for filenames -#define CASE_SENSITIVE 1 -#define CASE_INSENSITIVE 2 - - -// Return codes for the compression/decompression functions. Negative -// values are errors, positive values are used for special but normal events. -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) - - - -// Basic data types -typedef unsigned char Byte; // 8 bits -typedef unsigned int uInt; // 16 bits or more -typedef unsigned long uLong; // 32 bits or more -typedef void *voidpf; -typedef void *voidp; -typedef long z_off_t; - - - - - - - - - - - - -typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size); -typedef void (*free_func) (voidpf opaque, voidpf address); - -struct internal_state; - -typedef struct z_stream_s { - Byte *next_in; // next input byte - uInt avail_in; // number of bytes available at next_in - uLong total_in; // total nb of input bytes read so far - - Byte *next_out; // next output byte should be put there - uInt avail_out; // remaining free space at next_out - uLong total_out; // total nb of bytes output so far - - char *msg; // last error message, NULL if no error - struct internal_state *state; // not visible by applications - - alloc_func zalloc; // used to allocate the internal state - free_func zfree; // used to free the internal state - voidpf opaque; // private data object passed to zalloc and zfree - - int data_type; // best guess about the data type: ascii or binary - uLong adler; // adler32 value of the uncompressed data - uLong reserved; // reserved for future use -} z_stream; - -typedef z_stream *z_streamp; - - -// The application must update next_in and avail_in when avail_in has -// dropped to zero. It must update next_out and avail_out when avail_out -// has dropped to zero. The application must initialize zalloc, zfree and -// opaque before calling the init function. All other fields are set by the -// compression library and must not be updated by the application. -// -// The opaque value provided by the application will be passed as the first -// parameter for calls of zalloc and zfree. This can be useful for custom -// memory management. The compression library attaches no meaning to the -// opaque value. -// -// zalloc must return Z_NULL if there is not enough memory for the object. -// If zlib is used in a multi-threaded application, zalloc and zfree must be -// thread safe. -// -// The fields total_in and total_out can be used for statistics or -// progress reports. After compression, total_in holds the total size of -// the uncompressed data and may be saved for use in the decompressor -// (particularly if the decompressor wants to decompress everything in -// a single step). -// - - -// basic functions - -const char *zlibVersion (); -// The application can compare zlibVersion and ZLIB_VERSION for consistency. -// If the first character differs, the library code actually used is -// not compatible with the zlib.h header file used by the application. -// This check is automatically made by inflateInit. - - - - - - -int inflate (z_streamp strm, int flush); -// -// inflate decompresses as much data as possible, and stops when the input -// buffer becomes empty or the output buffer becomes full. It may some -// introduce some output latency (reading input without producing any output) -// except when forced to flush. -// -// The detailed semantics are as follows. inflate performs one or both of the -// following actions: -// -// - Decompress more input starting at next_in and update next_in and avail_in -// accordingly. If not all input can be processed (because there is not -// enough room in the output buffer), next_in is updated and processing -// will resume at this point for the next call of inflate(). -// -// - Provide more output starting at next_out and update next_out and avail_out -// accordingly. inflate() provides as much output as possible, until there -// is no more input data or no more space in the output buffer (see below -// about the flush parameter). -// -// Before the call of inflate(), the application should ensure that at least -// one of the actions is possible, by providing more input and/or consuming -// more output, and updating the next_* and avail_* values accordingly. -// The application can consume the uncompressed output when it wants, for -// example when the output buffer is full (avail_out == 0), or after each -// call of inflate(). If inflate returns Z_OK and with zero avail_out, it -// must be called again after making room in the output buffer because there -// might be more output pending. -// -// If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much -// output as possible to the output buffer. The flushing behavior of inflate is -// not specified for values of the flush parameter other than Z_SYNC_FLUSH -// and Z_FINISH, but the current implementation actually flushes as much output -// as possible anyway. -// -// inflate() should normally be called until it returns Z_STREAM_END or an -// error. However if all decompression is to be performed in a single step -// (a single call of inflate), the parameter flush should be set to -// Z_FINISH. In this case all pending input is processed and all pending -// output is flushed; avail_out must be large enough to hold all the -// uncompressed data. (The size of the uncompressed data may have been saved -// by the compressor for this purpose.) The next operation on this stream must -// be inflateEnd to deallocate the decompression state. The use of Z_FINISH -// is never required, but can be used to inform inflate that a faster routine -// may be used for the single inflate() call. -// -// If a preset dictionary is needed at this point (see inflateSetDictionary -// below), inflate sets strm-adler to the adler32 checksum of the -// dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise -// it sets strm->adler to the adler32 checksum of all output produced -// so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or -// an error code as described below. At the end of the stream, inflate() -// checks that its computed adler32 checksum is equal to that saved by the -// compressor and returns Z_STREAM_END only if the checksum is correct. -// -// inflate() returns Z_OK if some progress has been made (more input processed -// or more output produced), Z_STREAM_END if the end of the compressed data has -// been reached and all uncompressed output has been produced, Z_NEED_DICT if a -// preset dictionary is needed at this point, Z_DATA_ERROR if the input data was -// corrupted (input stream not conforming to the zlib format or incorrect -// adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent -// (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not -// enough memory, Z_BUF_ERROR if no progress is possible or if there was not -// enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR -// case, the application may then call inflateSync to look for a good -// compression block. -// - - -int inflateEnd (z_streamp strm); -// -// All dynamically allocated data structures for this stream are freed. -// This function discards any unprocessed input and does not flush any -// pending output. -// -// inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state -// was inconsistent. In the error case, msg may be set but then points to a -// static string (which must not be deallocated). - - // Advanced functions - -// The following functions are needed only in some special applications. - - - - - -int inflateSetDictionary (z_streamp strm, - const Byte *dictionary, - uInt dictLength); -// -// Initializes the decompression dictionary from the given uncompressed byte -// sequence. This function must be called immediately after a call of inflate -// if this call returned Z_NEED_DICT. The dictionary chosen by the compressor -// can be determined from the Adler32 value returned by this call of -// inflate. The compressor and decompressor must use exactly the same -// dictionary. -// -// inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a -// parameter is invalid (such as NULL dictionary) or the stream state is -// inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the -// expected one (incorrect Adler32 value). inflateSetDictionary does not -// perform any decompression: this will be done by subsequent calls of -// inflate(). - - -int inflateSync (z_streamp strm); -// -// Skips invalid compressed data until a full flush point can be found, or until all -// available input is skipped. No output is provided. -// -// inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR -// if no more input was provided, Z_DATA_ERROR if no flush point has been found, -// or Z_STREAM_ERROR if the stream structure was inconsistent. In the success -// case, the application may save the current current value of total_in which -// indicates where valid compressed data was found. In the error case, the -// application may repeatedly call inflateSync, providing more input each time, -// until success or end of the input data. - - -int inflateReset (z_streamp strm); -// This function is equivalent to inflateEnd followed by inflateInit, -// but does not free and reallocate all the internal decompression state. -// The stream will keep attributes that may have been set by inflateInit2. -// -// inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source -// stream state was inconsistent (such as zalloc or state being NULL). -// - - - -// checksum functions -// These functions are not related to compression but are exported -// anyway because they might be useful in applications using the -// compression library. - -uLong adler32 (uLong adler, const Byte *buf, uInt len); -// Update a running Adler-32 checksum with the bytes buf[0..len-1] and -// return the updated checksum. If buf is NULL, this function returns -// the required initial value for the checksum. -// An Adler-32 checksum is almost as reliable as a CRC32 but can be computed -// much faster. Usage example: -// -// uLong adler = adler32(0L, Z_NULL, 0); -// -// while (read_buffer(buffer, length) != EOF) { -// adler = adler32(adler, buffer, length); -// } -// if (adler != original_adler) error(); - -uLong ucrc32 (uLong crc, const Byte *buf, uInt len); -// Update a running crc with the bytes buf[0..len-1] and return the updated -// crc. If buf is NULL, this function returns the required initial value -// for the crc. Pre- and post-conditioning (one's complement) is performed -// within this function so it shouldn't be done by the application. -// Usage example: -// -// uLong crc = crc32(0L, Z_NULL, 0); -// -// while (read_buffer(buffer, length) != EOF) { -// crc = crc32(crc, buffer, length); -// } -// if (crc != original_crc) error(); - - - - -const char *zError (int err); -int inflateSyncPoint (z_streamp z); -const uLong *get_crc_table (void); - - - -typedef unsigned char uch; -typedef uch uchf; -typedef unsigned short ush; -typedef ush ushf; -typedef unsigned long ulg; - - - -const char * const z_errmsg[10] = { // indexed by 2-zlib_error -"need dictionary", // Z_NEED_DICT 2 -"stream end", // Z_STREAM_END 1 -"", // Z_OK 0 -"file error", // Z_ERRNO (-1) -"stream error", // Z_STREAM_ERROR (-2) -"data error", // Z_DATA_ERROR (-3) -"insufficient memory", // Z_MEM_ERROR (-4) -"buffer error", // Z_BUF_ERROR (-5) -"incompatible version",// Z_VERSION_ERROR (-6) -""}; - - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -// To be used only when the state is known to be valid - - // common constants - - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -// The three kinds of block type - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -// The minimum and maximum match lengths - -#define PRESET_DICT 0x20 // preset dictionary flag in zlib header - - // target dependencies - -#define OS_CODE 0x0b // Window 95 & Windows NT - - - - // functions - -#define zmemzero(dest, len) memset(dest, 0, len) - -// Diagnostic functions -#define LuAssert(cond,msg) -#define LuTrace(x) -#define LuTracev(x) -#define LuTracevv(x) -#define LuTracec(c,x) -#define LuTracecv(c,x) - - -typedef uLong (*check_func) (uLong check, const Byte *buf, uInt len); -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size); -void zcfree (voidpf opaque, voidpf ptr); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) - -//void ZFREE(z_streamp strm,voidpf addr) -//{ *((strm)->zfree))((strm)->opaque, addr); -//} - -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - - - - -// Huffman code lookup table entry--this entry is four bytes for machines -// that have 16-bit pointers (e.g. PC's in the small or medium model). - - -typedef struct inflate_huft_s inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; // number of extra bits or operation - Byte Bits; // number of bits in this code or subcode - } what; - uInt pad; // pad structure to a power of 2 (4 bytes for - } word; // 16-bit, 8 bytes for 32-bit int's) - uInt base; // literal, length base, distance base, or table offset -}; - -// Maximum size of dynamic tree. The maximum found in a long but non- -// exhaustive search was 1004 huft structures (850 for length/literals -// and 154 for distances, the latter actually the result of an -// exhaustive search). The actual maximum is not known, but the -// value below is more than safe. -#define MANY 1440 - -int inflate_trees_bits ( - uInt *, // 19 code lengths - uInt *, // bits tree desired/actual depth - inflate_huft * *, // bits tree result - inflate_huft *, // space for trees - z_streamp); // for messages - -int inflate_trees_dynamic ( - uInt, // number of literal/length codes - uInt, // number of distance codes - uInt *, // that many (total) code lengths - uInt *, // literal desired/actual bit depth - uInt *, // distance desired/actual bit depth - inflate_huft * *, // literal/length tree result - inflate_huft * *, // distance tree result - inflate_huft *, // space for trees - z_streamp); // for messages - -int inflate_trees_fixed ( - uInt *, // literal desired/actual bit depth - uInt *, // distance desired/actual bit depth - const inflate_huft * *, // literal/length tree result - const inflate_huft * *, // distance tree result - z_streamp); // for memory allocation - - - - - -struct inflate_blocks_state; -typedef struct inflate_blocks_state inflate_blocks_statef; - -inflate_blocks_statef * inflate_blocks_new ( - z_streamp z, - check_func c, // check function - uInt w); // window size - -int inflate_blocks ( - inflate_blocks_statef *, - z_streamp , - int); // initial return code - -void inflate_blocks_reset ( - inflate_blocks_statef *, - z_streamp , - uLong *); // check value on output - -int inflate_blocks_free ( - inflate_blocks_statef *, - z_streamp); - -void inflate_set_dictionary ( - inflate_blocks_statef *s, - const Byte *d, // dictionary - uInt n); // dictionary length - -int inflate_blocks_sync_point ( - inflate_blocks_statef *s); - - - - -struct inflate_codes_state; -typedef struct inflate_codes_state inflate_codes_statef; - -inflate_codes_statef *inflate_codes_new ( - uInt, uInt, - const inflate_huft *, const inflate_huft *, - z_streamp ); - -int inflate_codes ( - inflate_blocks_statef *, - z_streamp , - int); - -void inflate_codes_free ( - inflate_codes_statef *, - z_streamp ); - - - - -typedef enum { - IBM_TYPE, // get type bits (3, including end bit) - IBM_LENS, // get lengths for stored - IBM_STORED, // processing stored block - IBM_TABLE, // get table lengths - IBM_BTREE, // get bit lengths tree for a dynamic block - IBM_DTREE, // get length, distance trees for a dynamic block - IBM_CODES, // processing fixed or dynamic block - IBM_DRY, // output remaining window bytes - IBM_DONE, // finished last block, done - IBM_BAD} // got a data error--stuck here -inflate_block_mode; - -// inflate blocks semi-private state -struct inflate_blocks_state { - - // mode - inflate_block_mode mode; // current inflate_block mode - - // mode dependent information - union { - uInt left; // if STORED, bytes left to copy - struct { - uInt table; // table lengths (14 bits) - uInt index; // index into blens (or border) - uInt *blens; // bit lengths of codes - uInt bb; // bit length tree depth - inflate_huft *tb; // bit length decoding tree - } trees; // if DTREE, decoding info for trees - struct { - inflate_codes_statef - *codes; - } decode; // if CODES, current state - } sub; // submode - uInt last; // true if this block is the last block - - // mode independent information - uInt bitk; // bits in bit buffer - uLong bitb; // bit buffer - inflate_huft *hufts; // single malloc for tree space - Byte *window; // sliding window - Byte *end; // one byte after sliding window - Byte *read; // window read pointer - Byte *write; // window write pointer - check_func checkfn; // check function - uLong check; // check on output - -}; - - -// defines for inflate input/output -// update pointers and return -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -// get bytes and bits -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -// output bytes -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;m;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -// load local pointers -#define LOAD {LOADIN LOADOUT} - -// masks for lower bits (size given to avoid silly warnings with Visual C++) -// And'ing with mask[n] masks the lower n bits -const uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -// copy as much as possible from the sliding window to the output area -int inflate_flush (inflate_blocks_statef *, z_streamp, int); - -int inflate_fast (uInt, uInt, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp ); - - - -const uInt fixed_bl = 9; -const uInt fixed_bd = 5; -const inflate_huft fixed_tl[] = { - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} - }; -const inflate_huft fixed_td[] = { - {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, - {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, - {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, - {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, - {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, - {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, - {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, - {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} - }; - - - - - - - -// copy as much as possible from the sliding window to the output area -int inflate_flush(inflate_blocks_statef *s,z_streamp z,int r) -{ - uInt n; - Byte *p; - Byte *q; - - // local copies of source and destination pointers - p = z->next_out; - q = s->read; - - // compute number of bytes to copy as far as end of window - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - // update counters - z->avail_out -= n; - z->total_out += n; - - // update check information - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - // copy as far as end of window - if (n!=0) // check for n!=0 to avoid waking up CodeGuard - { memcpy(p, q, n); - p += n; - q += n; - } - - // see if more to copy at beginning of window - if (q == s->end) - { - // wrap pointers - q = s->window; - if (s->write == s->end) - s->write = s->window; - - // compute bytes to copy - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - // update counters - z->avail_out -= n; - z->total_out += n; - - // update check information - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - // copy - if (n!=0) {memcpy(p,q,n); p+=n; q+=n;} - } - - // update pointers - z->next_out = p; - s->read = q; - - // done - return r; -} - - - - - - -// simplify the use of the inflate_huft type with some defines -#define exop word.what.Exop -#define bits word.what.Bits - -typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing - START, // x: set up for LEN - LEN, // i: get length/literal/eob next - LENEXT, // i: getting length extra (have base) - DIST, // i: get distance next - DISTEXT, // i: getting distance extra - COPY, // o: copying bytes in window, waiting for space - LIT, // o: got literal, waiting for output space - WASH, // o: got eob, possibly still output waiting - END, // x: got eob and all data flushed - BADCODE} // x: got error -inflate_codes_mode; - -// inflate codes private state -struct inflate_codes_state { - - // mode - inflate_codes_mode mode; // current inflate_codes mode - - // mode dependent information - uInt len; - union { - struct { - const inflate_huft *tree; // pointer into tree - uInt need; // bits needed - } code; // if LEN or DIST, where in tree - uInt lit; // if LIT, literal - struct { - uInt get; // bits to get for extra - uInt dist; // distance back to copy from - } copy; // if EXT or COPY, where and how much - } sub; // submode - - // mode independent information - Byte lbits; // ltree bits decoded per branch - Byte dbits; // dtree bits decoder per branch - const inflate_huft *ltree; // literal/length/eob tree - const inflate_huft *dtree; // distance tree - -}; - - -inflate_codes_statef *inflate_codes_new( -uInt bl, uInt bd, -const inflate_huft *tl, -const inflate_huft *td, // need separate declaration for Borland C++ -z_streamp z) -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - LuTracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt j; // temporary storage - const inflate_huft *t; // temporary pointer - uInt e; // extra bits or operation - uLong b; // bit buffer - uInt k; // bits in bit buffer - Byte *p; // input data pointer - uInt n; // bytes available there - Byte *q; // output window write pointer - uInt m; // bytes to end of window or read pointer - Byte *f; // pointer to copy strings from - inflate_codes_statef *c = s->sub.decode.codes; // codes state - - // copy input/output information to locals (UPDATE macro restores) - LOAD - - // process input and output based on current state - for(;;) switch (c->mode) - { // waiting for "i:"=input, "o:"=output, "x:"=nothing - case START: // x: set up for LEN -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif // !SLOW - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: // i: get length/literal/eob next - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) // literal - { - c->sub.lit = t->base; - LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) // length - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) // next table - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) // end of block - { - LuTracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; // invalid code - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: // i: getting length extra (have base) - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - LuTracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: // i: get distance next - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) // distance - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) // next table - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; // invalid code - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: // i: getting distance extra - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - LuTracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: // o: copying bytes in window, waiting for space - f = q - c->sub.copy.dist; - while (f < s->window) // modulo window size-"while" instead - f += s->end - s->window; // of "if" handles invalid distances - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: // o: got literal, waiting for output space - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: // o: got eob, possibly more output - if (k > 7) // return unused byte, if any - { - //Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; // can always return one - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: // x: got error - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -void inflate_codes_free(inflate_codes_statef *c,z_streamp z) -{ ZFREE(z, c); - LuTracev((stderr, "inflate: codes free\n")); -} - - - -// infblock.c -- interpret and process block types to last block -// Copyright (C) 1995-1998 Mark Adler -// For conditions of distribution and use, see copyright notice in zlib.h - -//struct inflate_codes_state {int dummy;}; // for buggy compilers - - - -// Table for deflate from PKZIP's appnote.txt. -const uInt border[] = { // Order of the bit length code lengths - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -// -// Notes beyond the 1.93a appnote.txt: -// -// 1. Distance pointers never point before the beginning of the output stream. -// 2. Distance pointers can point back across blocks, up to 32k away. -// 3. There is an implied maximum of 7 bits for the bit length table and -// 15 bits for the actual data. -// 4. If only one code exists, then it is encoded using one bit. (Zero -// would be more efficient, but perhaps a little confusing.) If two -// codes exist, they are coded using one bit each (0 and 1). -// 5. There is no way of sending zero distance codes--a dummy must be -// sent if there are none. (History: a pre 2.0 version of PKZIP would -// store blocks with no distance codes, but this was discovered to be -// too harsh a criterion.) Valid only for 1.93a. 2.04c does allow -// zero distance codes, which is sent as one code of zero bits in -// length. -// 6. There are up to 286 literal/length codes. Code 256 represents the -// end-of-block. Note however that the static length tree defines -// 288 codes just to fill out the Huffman codes. Codes 286 and 287 -// cannot be used though, since there is no length base or extra bits -// defined for them. Similarily, there are up to 30 distance codes. -// However, static trees define 32 codes (all 5 bits) to fill out the -// Huffman codes, but the last two had better not show up in the data. -// 7. Unzip can check dynamic Huffman blocks for complete code sets. -// The exception is that a single code would not be complete (see #4). -// 8. The five bits following the block type is really the number of -// literal codes sent minus 257. -// 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits -// (1+6+6). Therefore, to output three times the length, you output -// three codes (1+1+1), whereas to output four times the same length, -// you only need two codes (1+3). Hmm. -//10. In the tree reconstruction algorithm, Code = Code + Increment -// only if BitLength(i) is not zero. (Pretty obvious.) -//11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) -//12. Note: length code 284 can represent 227-258, but length code 285 -// really is 258. The last length deserves its own, short code -// since it gets used a lot in very redundant files. The length -// 258 is special since 258 - 3 (the min match length) is 255. -//13. The literal/length and distance code bit lengths are read as a -// single stream of lengths. It is possible (and advantageous) for -// a repeat code (16, 17, or 18) to go across the boundary between -// the two sets of lengths. - - -void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) -{ - if (c != Z_NULL) - *c = s->check; - if (s->mode == IBM_BTREE || s->mode == IBM_DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == IBM_CODES) - inflate_codes_free(s->sub.decode.codes, z); - s->mode = IBM_TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); - LuTracev((stderr, "inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->hufts = - (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s->hufts); - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = IBM_TYPE; - LuTracev((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, Z_NULL); - return s; -} - - -int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt t; // temporary storage - uLong b; // bit buffer - uInt k; // bits in bit buffer - Byte *p; // input data pointer - uInt n; // bytes available there - Byte *q; // output window write pointer - uInt m; // bytes to end of window or read pointer - - // copy input/output information to locals (UPDATE macro restores) - LOAD - - // process input based on current state - for(;;) switch (s->mode) - { - case IBM_TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: // stored - LuTracev((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; // go to byte boundary - DUMPBITS(t) - s->mode = IBM_LENS; // get length of stored block - break; - case 1: // fixed - LuTracev((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - const inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = IBM_CODES; - break; - case 2: // dynamic - LuTracev((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = IBM_TABLE; - break; - case 3: // illegal - DUMPBITS(3) - s->mode = IBM_BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case IBM_LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = IBM_BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; // dump bits - LuTracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE); - break; - case IBM_STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - memcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - LuTracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? IBM_DRY : IBM_TYPE; - break; - case IBM_TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; - // remove this section to workaround bug in pkzip - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = IBM_BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } - // end remove - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - LuTracev((stderr, "inflate: table sizes ok\n")); - s->mode = IBM_BTREE; - case IBM_BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - { - ZFREE(z, s->sub.trees.blens); - s->mode = IBM_BAD; - } - LEAVE - } - s->sub.trees.index = 0; - LuTracev((stderr, "inflate: bits tree ok\n")); - s->mode = IBM_DTREE; - case IBM_DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else // c == 16..18 - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - ZFREE(z, s->sub.trees.blens); - s->mode = IBM_BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; // must be <= 9 for lookahead assumptions - bd = 6; // must be <= 9 for lookahead assumptions - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - { - ZFREE(z, s->sub.trees.blens); - s->mode = IBM_BAD; - } - r = t; - LEAVE - } - LuTracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - ZFREE(z, s->sub.trees.blens); - s->mode = IBM_CODES; - case IBM_CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - LOAD - LuTracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = IBM_TYPE; - break; - } - s->mode = IBM_DRY; - case IBM_DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = IBM_DONE; - case IBM_DONE: - r = Z_STREAM_END; - LEAVE - case IBM_BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) -{ - inflate_blocks_reset(s, z, Z_NULL); - ZFREE(z, s->window); - ZFREE(z, s->hufts); - ZFREE(z, s); - LuTracev((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - - - -// inftrees.c -- generate Huffman trees for efficient decoding -// Copyright (C) 1995-1998 Mark Adler -// For conditions of distribution and use, see copyright notice in zlib.h -// - - - -extern const char inflate_copyright[] = - " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; -// If you use the zlib library in a product, an acknowledgment is welcome -// in the documentation of your product. If for some reason you cannot -// include such an acknowledgment, I would appreciate that you keep this -// copyright string in the executable of your product. - - - -int huft_build ( - uInt *, // code lengths in bits - uInt, // number of codes - uInt, // number of "simple" codes - const uInt *, // list of base values for non-simple codes - const uInt *, // list of extra bits for non-simple codes - inflate_huft **,// result: starting table - uInt *, // maximum lookup bits (returns actual) - inflate_huft *, // space for trees - uInt *, // hufts used in space - uInt * ); // space for values - -// Tables for deflate from PKZIP's appnote.txt. -const uInt cplens[31] = { // Copy lengths for literal codes 257..285 - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - // see note #13 above about 258 -const uInt cplext[31] = { // Extra bits for literal codes 257..285 - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid -const uInt cpdist[30] = { // Copy offsets for distance codes 0..29 - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -const uInt cpdext[30] = { // Extra bits for distance codes - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -// -// Huffman code decoding is performed using a multi-level table lookup. -// The fastest way to decode is to simply build a lookup table whose -// size is determined by the longest code. However, the time it takes -// to build this table can also be a factor if the data being decoded -// is not very long. The most common codes are necessarily the -// shortest codes, so those codes dominate the decoding time, and hence -// the speed. The idea is you can have a shorter table that decodes the -// shorter, more probable codes, and then point to subsidiary tables for -// the longer codes. The time it costs to decode the longer codes is -// then traded against the time it takes to make longer tables. -// -// This results of this trade are in the variables lbits and dbits -// below. lbits is the number of bits the first level table for literal/ -// length codes can decode in one step, and dbits is the same thing for -// the distance codes. Subsequent tables are also less than or equal to -// those sizes. These values may be adjusted either when all of the -// codes are shorter than that, in which case the longest code length in -// bits is used, or when the shortest code is *longer* than the requested -// table size, in which case the length of the shortest code in bits is -// used. -// -// There are two different values for the two tables, since they code a -// different number of possibilities each. The literal/length table -// codes 286 possible values, or in a flat code, a little over eight -// bits. The distance table codes 30 possible values, or a little less -// than five bits, flat. The optimum values for speed end up being -// about one bit more than those, so lbits is 8+1 and dbits is 5+1. -// The optimum values may differ though from machine to machine, and -// possibly even between compilers. Your mileage may vary. -// - - -// If BMAX needs to be larger than 16, then h and x[] should be uLong. -#define BMAX 15 // maximum bit length of any code - -int huft_build( -uInt *b, // code lengths in bits (all assumed <= BMAX) -uInt n, // number of codes (assumed <= 288) -uInt s, // number of simple-valued codes (0..s-1) -const uInt *d, // list of base values for non-simple codes -const uInt *e, // list of extra bits for non-simple codes -inflate_huft * *t, // result: starting table -uInt *m, // maximum lookup bits, returns actual -inflate_huft *hp, // space for trees -uInt *hn, // hufts used in space -uInt *v) // working area: values in order of bit length -// Given a list of code lengths and a maximum table size, make a set of -// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR -// if the given code set is incomplete (the tables are still built in this -// case), or Z_DATA_ERROR if the input is invalid. -{ - - uInt a; // counter for codes of length k - uInt c[BMAX+1]; // bit length count table - uInt f; // i repeats in table every f entries - int g; // maximum code length - int h; // table level - register uInt i; // counter, current code - register uInt j; // counter - register int k; // number of bits in current code - int l; // bits per table (returned in m) - uInt mask; // (1 << w) - 1, to avoid cc -O bug on HP - register uInt *p; // pointer into c[], b[], or v[] - inflate_huft *q; // points to current table - struct inflate_huft_s r; // table entry for structure assignment - inflate_huft *u[BMAX]; // table stack - register int w; // bits before this table == (l * h) - uInt x[BMAX+1]; // bit offsets, then code stack - uInt *xp; // pointer into x - int y; // number of dummy codes added - uInt z; // number of entries in current table - - - // Generate counts for each bit length - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4; p; // clear c[]--assume BMAX+1 is 16 - p = b; i = n; - do { - c[*p++]++; // assume all entries <= BMAX - } while (--i); - if (c[0] == n) // null input--all zero length codes - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - // Find minimum and maximum length, bound *m by those - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; // minimum code length - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; // maximum code length - if ((uInt)l > i) - l = i; - *m = l; - - - // Adjust last length count to fill out codes, if needed - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - // Generate starting offsets into the value table for each length - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { // note that i == g from above - *xp++ = (j += *p++); - } - - - // Make a table of values in order of bit lengths - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; // set n to length of v - - - // Generate the Huffman codes and for each, make the table entries - x[0] = i = 0; // first Huffman code is zero - p = v; // grab values in bit order - h = -1; // no tables yet--level -1 - w = -l; // bits decoded == (l * h) - u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy - q = (inflate_huft *)Z_NULL; // ditto - z = 0; // ditto - - // go through the bit lengths (k already is bits in shortest code) - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - // here i is the Huffman code of length k bits for value *p - // make tables up to required level - while (k > w + l) - { - h++; - w += l; // previous table always l bits - - // compute minimum size table less than or equal to l bits - z = g - w; - z = z > (uInt)l ? l : z; // table size upper limit - if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table - { // too few codes for k-w bit table - f -= a + 1; // deduct codes from patterns left - xp = c + k; - if (j < z) - while (++j < z) // try smaller tables up to z bits - { - if ((f <<= 1) <= *++xp) - break; // enough codes to use up j bits - f -= *xp; // else deduct codes from patterns - } - } - z = 1 << j; // table entries for j-bit table - - // allocate new table - if (*hn + z > MANY) // (note: doesn't matter for fixed) - return Z_DATA_ERROR; // overflow of MANY - u[h] = q = hp + *hn; - *hn += z; - - // connect to last table, if there is one - if (h) - { - x[h] = i; // save pattern for backing up - r.bits = (Byte)l; // bits to dump before this table - r.exop = (Byte)j; // bits in this table - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); // offset to this table - u[h-1][j] = r; // connect to last table - } - else - *t = q; // first table is returned result - } - - // set up table entry in r - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; // out of values--invalid code - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block - r.base = *p++; // simple code is just the value - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);// non-simple--look up in lists - r.base = d[*p++ - s]; - } - - // fill code-like entries with r - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - // backwards increment the k-bit code i - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - // backup over finished tables - mask = (1 << w) - 1; // needed on HP, cc -O bug - while ((i & mask) != x[h]) - { - h--; // don't need to update q - w -= l; - mask = (1 << w) - 1; - } - } - } - - - // Return Z_BUF_ERROR if we were given an incomplete table - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits( -uInt *c, // 19 code lengths -uInt *bb, // bits tree desired/actual depth -inflate_huft * *tb, // bits tree result -inflate_huft *hp, // space for trees -z_streamp z) // for messages -{ - int r; - uInt hn = 0; // hufts used in space - uInt *v; // work area for huft_build - - if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, - tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -} - - -int inflate_trees_dynamic( -uInt nl, // number of literal/length codes -uInt nd, // number of distance codes -uInt *c, // that many (total) code lengths -uInt *bl, // literal desired/actual bit depth -uInt *bd, // distance desired/actual bit depth -inflate_huft * *tl, // literal/length tree result -inflate_huft * *td, // distance tree result -inflate_huft *hp, // space for trees -z_streamp z) // for messages -{ - int r; - uInt hn = 0; // hufts used in space - uInt *v; // work area for huft_build - - // allocate work area - if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - - // build literal/length tree - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - // build distance tree - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - // done - ZFREE(z, v); - return Z_OK; -} - - - - - -int inflate_trees_fixed( -uInt *bl, // literal desired/actual bit depth -uInt *bd, // distance desired/actual bit depth -const inflate_huft * * tl, // literal/length tree result -const inflate_huft * *td, // distance tree result -z_streamp ) // for memory allocation -{ - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -// inffast.c -- process literals and length/distance pairs fast -// Copyright (C) 1995-1998 Mark Adler -// For conditions of distribution and use, see copyright notice in zlib.h -// - - -//struct inflate_codes_state {int dummy;}; // for buggy compilers - - -// macros for bit input with no checking and for returning unused bytes -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} - -// Called with number of bytes left to write in window at least 258 -// (the maximum string length) and number of input bytes available -// at least ten. The ten bytes are six bytes for the longest length/ -// distance pair plus four bytes for overloading the bit buffer. - -int inflate_fast( -uInt bl, uInt bd, -const inflate_huft *tl, -const inflate_huft *td, // need separate declaration for Borland C++ -inflate_blocks_statef *s, -z_streamp z) -{ - const inflate_huft *t; // temporary pointer - uInt e; // extra bits or operation - uLong b; // bit buffer - uInt k; // bits in bit buffer - Byte *p; // input data pointer - uInt n; // bytes available there - Byte *q; // output window write pointer - uInt m; // bytes to end of window or read pointer - uInt ml; // mask for literal/length tree - uInt md; // mask for distance tree - uInt c; // bytes to copy - uInt d; // distance back to copy from - Byte *r; // copy source pointer - - // load input, output, bit values - LOAD - - // initialize masks - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - // do until not enough input or output space for fast loop - do { // assume called with m >= 258 && n >= 10 - // get literal/length code - GRABBITS(20) // max bits for literal/length code - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - for (;;) { - DUMPBITS(t->bits) - if (e & 16) - { - // get extra bits for length - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - LuTracevv((stderr, "inflate: * length %u\n", c)); - - // decode distance base of block to copy - GRABBITS(15); // max bits for distance code - e = (t = td + ((uInt)b & md))->exop; - for (;;) { - DUMPBITS(t->bits) - if (e & 16) - { - // get extra bits to add to distance base - e &= 15; - GRABBITS(e) // get extra bits (up to 13) - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - LuTracevv((stderr, "inflate: * distance %u\n", d)); - - // do the copy - m -= c; - r = q - d; - if (r < s->window) // wrap if needed - { - do { - r += s->end - s->window; // force pointer in window - } while (r < s->window); // covers invalid distances - e = (uInt) (s->end - r); - if (c > e) - { - c -= e; // wrapped copy - do { - *q++ = *r++; - } while (--e); - r = s->window; - do { - *q++ = *r++; - } while (--c); - } - else // normal copy - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); - } - } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); - } - break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - }; - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - LuTracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - }; - } while (m >= 258 && n >= 10); - - // not enough input or output--restore pointers and return - UNGRAB - UPDATE - return Z_OK; -} - - - - - - -// crc32.c -- compute the CRC-32 of a data stream -// Copyright (C) 1995-1998 Mark Adler -// For conditions of distribution and use, see copyright notice in zlib.h - -// @(#) $Id$ - - - - - - -// Table of CRC-32's of all single-byte values (made by make_crc_table) -const uLong crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - -const uLong * get_crc_table() -{ return (const uLong *)crc_table; -} - -#define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define CRC_DO2(buf) CRC_DO1(buf); CRC_DO1(buf); -#define CRC_DO4(buf) CRC_DO2(buf); CRC_DO2(buf); -#define CRC_DO8(buf) CRC_DO4(buf); CRC_DO4(buf); - -uLong ucrc32(uLong crc, const Byte *buf, uInt len) -{ if (buf == Z_NULL) return 0L; - crc = crc ^ 0xffffffffL; - while (len >= 8) {CRC_DO8(buf); len -= 8;} - if (len) do {CRC_DO1(buf);} while (--len); - return crc ^ 0xffffffffL; -} - - - -// ============================================================= -// some decryption routines -#define CRC32(c, b) (crc_table[((int)(c)^(b))&0xff]^((c)>>8)) -void Uupdate_keys(unsigned long *keys, char c) -{ keys[0] = CRC32(keys[0],c); - keys[1] += keys[0] & 0xFF; - keys[1] = keys[1]*134775813L +1; - keys[2] = CRC32(keys[2], keys[1] >> 24); -} -char Udecrypt_byte(unsigned long *keys) -{ unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; - return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); -} -char zdecode(unsigned long *keys, char c) -{ c^=Udecrypt_byte(keys); - Uupdate_keys(keys,c); - return c; -} - - - -// adler32.c -- compute the Adler-32 checksum of a data stream -// Copyright (C) 1995-1998 Mark Adler -// For conditions of distribution and use, see copyright notice in zlib.h - -// @(#) $Id$ - - -#define BASE 65521L // largest prime smaller than 65536 -#define NMAX 5552 -// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 - -#define AD_DO1(buf,i) {s1 += buf[i]; s2 += s1;} -#define AD_DO2(buf,i) AD_DO1(buf,i); AD_DO1(buf,i+1); -#define AD_DO4(buf,i) AD_DO2(buf,i); AD_DO2(buf,i+2); -#define AD_DO8(buf,i) AD_DO4(buf,i); AD_DO4(buf,i+4); -#define AD_DO16(buf) AD_DO8(buf,0); AD_DO8(buf,8); - -// ========================================================================= -uLong adler32(uLong adler, const Byte *buf, uInt len) -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - AD_DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} - - - -// zutil.c -- target dependent utility functions for the compression library -// Copyright (C) 1995-1998 Jean-loup Gailly. -// For conditions of distribution and use, see copyright notice in zlib.h -// @(#) $Id$ - - - - - - -const char * zlibVersion() -{ - return ZLIB_VERSION; -} - -// exported to allow conversion of error code to string for compress() and -// uncompress() -const char * zError(int err) -{ return ERR_MSG(err); -} - - - - -voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - if (opaque) items += size - size; // make compiler happy - return (voidpf)calloc(items, size); -} - -void zcfree (voidpf opaque, voidpf ptr) -{ - zfree(ptr); - if (opaque) return; // make compiler happy -} - - - -// inflate.c -- zlib interface to inflate modules -// Copyright (C) 1995-1998 Mark Adler -// For conditions of distribution and use, see copyright notice in zlib.h - -//struct inflate_blocks_state {int dummy;}; // for buggy compilers - -typedef enum { - IM_METHOD, // waiting for method byte - IM_FLAG, // waiting for flag byte - IM_DICT4, // four dictionary check bytes to go - IM_DICT3, // three dictionary check bytes to go - IM_DICT2, // two dictionary check bytes to go - IM_DICT1, // one dictionary check byte to go - IM_DICT0, // waiting for inflateSetDictionary - IM_BLOCKS, // decompressing blocks - IM_CHECK4, // four check bytes to go - IM_CHECK3, // three check bytes to go - IM_CHECK2, // two check bytes to go - IM_CHECK1, // one check byte to go - IM_DONE, // finished check, done - IM_BAD} // got an error--stay here -inflate_mode; - -// inflate private state -struct internal_state { - - // mode - inflate_mode mode; // current inflate mode - - // mode dependent information - union { - uInt method; // if IM_FLAGS, method byte - struct { - uLong was; // computed check value - uLong need; // stream check value - } check; // if CHECK, check values to compare - uInt marker; // if IM_BAD, inflateSync's marker bytes count - } sub; // submode - - // mode independent information - int nowrap; // flag for no wrapper - uInt wbits; // log2(window size) (8..15, defaults to 15) - inflate_blocks_statef - *blocks; // current inflate_blocks state - -}; - -int inflateReset(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); - LuTracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int inflateEnd(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); - ZFREE(z, z->state); - z->state = Z_NULL; - LuTracev((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2(z_streamp z) -{ const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream); - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; - - int w = -15; // MAX_WBITS: 32K LZ77 window. - // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files created by gzip. - // The memory requirements for deflate are (in bytes): - // (1 << (windowBits+2)) + (1 << (memLevel+9)) - // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - // plus a few kilobytes for small objects. For example, if you want to reduce - // the default memory requirements from 256K to 128K, compile with - // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - // Of course this will generally degrade compression (there's no free lunch). - // - // The memory requirements for inflate are (in bytes) 1 << windowBits - // that is, 32K for windowBits=15 (default value) plus a few kilobytes - // for small objects. - - // initialize state - if (z == Z_NULL) return Z_STREAM_ERROR; - z->msg = Z_NULL; - if (z->zalloc == Z_NULL) - { - z->zalloc = zcalloc; - z->opaque = (voidpf)0; - } - if (z->zfree == Z_NULL) z->zfree = zcfree; - if ((z->state = (struct internal_state *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - // handle undocumented nowrap option (no zlib header or check) - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - // set window size - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - // create inflate_blocks state - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - LuTracev((stderr, "inflate: allocated\n")); - - // reset state - inflateReset(z); - return Z_OK; -} - - - -#define IM_NEEDBYTE {if(z->avail_in==0)return r;r=f;} -#define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z_streamp z, int f) -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - for (;;) switch (z->state->mode) - { - case IM_METHOD: - IM_NEEDBYTE - if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = IM_BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; // can't try inflateSync - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = IM_BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; // can't try inflateSync - break; - } - z->state->mode = IM_FLAG; - case IM_FLAG: - IM_NEEDBYTE - b = IM_NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = IM_BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; // can't try inflateSync - break; - } - LuTracev((stderr, "inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = IM_BLOCKS; - break; - } - z->state->mode = IM_DICT4; - case IM_DICT4: - IM_NEEDBYTE - z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; - z->state->mode = IM_DICT3; - case IM_DICT3: - IM_NEEDBYTE - z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; - z->state->mode = IM_DICT2; - case IM_DICT2: - IM_NEEDBYTE - z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; - z->state->mode = IM_DICT1; - case IM_DICT1: - IM_NEEDBYTE; r; - z->state->sub.check.need += (uLong)IM_NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = IM_DICT0; - return Z_NEED_DICT; - case IM_DICT0: - z->state->mode = IM_BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; // can try inflateSync - return Z_STREAM_ERROR; - case IM_BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (r == Z_DATA_ERROR) - { - z->state->mode = IM_BAD; - z->state->sub.marker = 0; // can try inflateSync - break; - } - if (r == Z_OK) - r = f; - if (r != Z_STREAM_END) - return r; - r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = IM_DONE; - break; - } - z->state->mode = IM_CHECK4; - case IM_CHECK4: - IM_NEEDBYTE - z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; - z->state->mode = IM_CHECK3; - case IM_CHECK3: - IM_NEEDBYTE - z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; - z->state->mode = IM_CHECK2; - case IM_CHECK2: - IM_NEEDBYTE - z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; - z->state->mode = IM_CHECK1; - case IM_CHECK1: - IM_NEEDBYTE - z->state->sub.check.need += (uLong)IM_NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = IM_BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; // can't try inflateSync - break; - } - LuTracev((stderr, "inflate: zlib check ok\n")); - z->state->mode = IM_DONE; - case IM_DONE: - return Z_STREAM_END; - case IM_BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } -} - - - - - -// unzip.c -- IO on .zip files using zlib -// Version 0.15 beta, Mar 19th, 1998, -// Read unzip.h for more info - - - - -#define UNZ_BUFSIZE (16384) -#define UNZ_MAXFILENAMEINZIP (256) -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - - - -const char unz_copyright[] = " unzip 0.15 Copyright 1998 Gilles Vollant "; - -// unz_file_info_interntal contain internal info about a file in zipfile -typedef struct unz_file_info_internal_s -{ - uLong offset_curfile;// relative offset of local header 4 bytes -} unz_file_info_internal; - - -typedef struct -{ bool is_handle; // either a handle or memory - bool canseek; - // for handles: - HANDLE h; bool herr; unsigned long initial_offset; bool mustclosehandle; - // for memory: - void *buf; unsigned int len,pos; // if it's a memory block -} LUFILE; - - -LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) -{ if (flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) {*err=ZR_ARGS; return NULL;} - // - HANDLE h=0; bool canseek=false; *err=ZR_OK; - bool mustclosehandle=false; - if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) - { if (flags==ZIP_HANDLE) - { HANDLE hf = z; - h=hf; mustclosehandle=false; -#ifdef DuplicateHandle - BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS); - if (!res) mustclosehandle=true; -#endif - } - else - { h=CreateFile((const TCHAR*)z,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); - if (h==INVALID_HANDLE_VALUE) {*err=ZR_NOFILE; return NULL;} - mustclosehandle=true; - } - // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. - DWORD res = SetFilePointer(h,0,0,FILE_CURRENT); - canseek = (res!=0xFFFFFFFF); - } - LUFILE *lf = new LUFILE; - if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) - { lf->is_handle=true; lf->mustclosehandle=mustclosehandle; - lf->canseek=canseek; - lf->h=h; lf->herr=false; - lf->initial_offset=0; - if (canseek) lf->initial_offset = SetFilePointer(h,0,NULL,FILE_CURRENT); - } - else - { lf->is_handle=false; - lf->canseek=true; - lf->mustclosehandle=false; - lf->buf=z; lf->len=len; lf->pos=0; lf->initial_offset=0; - } - *err=ZR_OK; - return lf; -} - - -int lufclose(LUFILE *stream) -{ if (stream==NULL) return EOF; - if (stream->mustclosehandle) CloseHandle(stream->h); - delete stream; - return 0; -} - -int luferror(LUFILE *stream) -{ if (stream->is_handle && stream->herr) return 1; - else return 0; -} - -long int luftell(LUFILE *stream) -{ if (stream->is_handle && stream->canseek) return SetFilePointer(stream->h,0,NULL,FILE_CURRENT)-stream->initial_offset; - else if (stream->is_handle) return 0; - else return stream->pos; -} - -int lufseek(LUFILE *stream, long offset, int whence) -{ if (stream->is_handle && stream->canseek) - { if (whence==SEEK_SET) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN); - else if (whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT); - else if (whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END); - else return 19; // EINVAL - return 0; - } - else if (stream->is_handle) return 29; // ESPIPE - else - { if (whence==SEEK_SET) stream->pos=offset; - else if (whence==SEEK_CUR) stream->pos+=offset; - else if (whence==SEEK_END) stream->pos=stream->len+offset; - return 0; - } -} - - -size_t lufread(void *ptr,size_t size,size_t n,LUFILE *stream) -{ unsigned int toread = (unsigned int)(size*n); - if (stream->is_handle) - { DWORD red; BOOL res = ReadFile(stream->h,ptr,toread,&red,NULL); - if (!res) stream->herr=true; - return red/size; - } - if (stream->pos+toread > stream->len) toread = stream->len-stream->pos; - memcpy(ptr, (char*)stream->buf + stream->pos, toread); DWORD red = toread; - stream->pos += red; - return red/size; -} - - - - -// file_in_zip_read_info_s contain internal information about a file in zipfile, -// when reading and decompress it -typedef struct -{ - char *read_buffer; // internal buffer for compressed data - z_stream stream; // zLib stream structure for inflate - - uLong pos_in_zipfile; // position in byte on the zipfile, for fseek - uLong stream_initialised; // flag set if stream structure is initialised - - uLong offset_local_extrafield;// offset of the local extra field - uInt size_local_extrafield;// size of the local extra field - uLong pos_local_extrafield; // position in the local extra field in read - - uLong crc32; // crc32 of all data uncompressed - uLong crc32_wait; // crc32 we must obtain after decompress all - uLong rest_read_compressed; // number of byte to be decompressed - uLong rest_read_uncompressed;//number of byte to be obtained after decomp - LUFILE* file; // io structore of the zipfile - uLong compression_method; // compression method (0==store) - uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) - bool encrypted; // is it encrypted? - unsigned long keys[3]; // decryption keys, initialized by unzOpenCurrentFile - int encheadleft; // the first call(s) to unzReadCurrentFile will read this many encryption-header bytes first - char crcenctest; // if encrypted, we'll check the encryption buffer against this -} file_in_zip_read_info_s; - - -// unz_s contain internal information about the zipfile -typedef struct -{ - LUFILE* file; // io structore of the zipfile - unz_global_info gi; // public global information - uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) - uLong num_file; // number of the current file in the zipfile - uLong pos_in_central_dir; // pos of the current file in the central dir - uLong current_file_ok; // flag about the usability of the current file - uLong central_pos; // position of the beginning of the central dir - - uLong size_central_dir; // size of the central directory - uLong offset_central_dir; // offset of start of central directory with respect to the starting disk number - - unz_file_info cur_file_info; // public info about the current file in zip - unz_file_info_internal cur_file_info_internal; // private info about it - file_in_zip_read_info_s* pfile_in_zip_read; // structure about the current file if we are decompressing it -} unz_s, *unzFile; - - -int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity); -// Compare two filename (fileName1,fileName2). - -z_off_t unztell (unzFile file); -// Give the current position in uncompressed data - -int unzeof (unzFile file); -// return 1 if the end of file was reached, 0 elsewhere - -int unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len); -// Read extra field from the current file (opened by unzOpenCurrentFile) -// This is the local-header version of the extra field (sometimes, there is -// more info in the local-header version than in the central-header) -// -// if buf==NULL, it return the size of the local extra field -// -// if buf!=NULL, len is the size of the buffer, the extra header is copied in -// buf. -// the return value is the number of bytes copied in buf, or (if <0) -// the error code - - - -// =========================================================================== -// Read a byte from a gz_stream; update next_in and avail_in. Return EOF -// for end of file. -// IN assertion: the stream s has been sucessfully opened for reading. - -int unzlocal_getByte(LUFILE *fin,int *pi) -{ unsigned char c; - int err = (int)lufread(&c, 1, 1, fin); - if (err==1) - { *pi = (int)c; - return UNZ_OK; - } - else - { if (luferror(fin)) return UNZ_ERRNO; - else return UNZ_EOF; - } -} - - -// =========================================================================== -// Reads a long in LSB order from the given gz_stream. Sets -int unzlocal_getShort (LUFILE *fin,uLong *pX) -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -int unzlocal_getLong (LUFILE *fin,uLong *pX) -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - - -// My own strcmpi / strcasecmp -int strcmpcasenosensitive_internal (const char* fileName1,const char *fileName2) -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= (char)0x20; - if ((c2>='a') && (c2<='z')) - c2 -= (char)0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - - - -// -// Compare two filename (fileName1,fileName2). -// If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) -// If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) -// -int unzStringFileNameCompare (const char*fileName1,const char*fileName2,int iCaseSensitivity) -{ if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); - else return strcmpcasenosensitive_internal(fileName1,fileName2); -} - -#define BUFREADCOMMENT (0x400) - - -// Locate the Central directory of a zipfile (at the end, just before -// the global comment). Lu bugfix 2005.07.26 - returns 0xFFFFFFFF if not found, -// rather than 0, since 0 is a valid central-dir-location for an empty zipfile. -uLong unzlocal_SearchCentralDir(LUFILE *fin) -{ if (lufseek(fin,0,SEEK_END) != 0) return 0xFFFFFFFF; - uLong uSizeFile = luftell(fin); - - uLong uMaxBack=0xffff; // maximum size of global comment - if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; - - unsigned char *buf = (unsigned char*)zmalloc(BUFREADCOMMENT+4); - if (buf==NULL) return 0xFFFFFFFF; - uLong uPosFound=0xFFFFFFFF; - - uLong uBackRead = 4; - while (uBackReaduMaxBack) uBackRead = uMaxBack; - else uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (lufseek(fin,uReadPos,SEEK_SET)!=0) break; - if (lufread(buf,(uInt)uReadSize,1,fin)!=1) break; - for (i=(int)uReadSize-3; (i--)>=0;) - { if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { uPosFound = uReadPos+i; break; - } - } - if (uPosFound!=0) break; - } - if (buf) zfree(buf); - return uPosFound; -} - - -int unzGoToFirstFile (unzFile file); -int unzCloseCurrentFile (unzFile file); - -// Open a Zip file. -// If the zipfile cannot be opened (file don't exist or in not valid), return NULL. -// Otherwise, the return value is a unzFile Handle, usable with other unzip functions -unzFile unzOpenInternal(LUFILE *fin) -{ if (fin==NULL) return NULL; - if (unz_copyright[0]!=' ') {lufclose(fin); return NULL;} - - int err=UNZ_OK; - unz_s us; - uLong central_pos,uL; - central_pos = unzlocal_SearchCentralDir(fin); - if (central_pos==0xFFFFFFFF) err=UNZ_ERRNO; - if (lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO; - // the signature, already checked - if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; - // number of this disk - uLong number_disk; // number of the current dist, used for spanning ZIP, unsupported, always 0 - if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; - // number of the disk with the start of the central directory - uLong number_disk_with_CD; // number the the disk with central dir, used for spaning ZIP, unsupported, always 0 - if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; - // total number of entries in the central dir on this disk - if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; - // total number of entries in the central dir - uLong number_entry_CD; // total number of entries in the central dir (same than number_entry on nospan) - if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; - if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; - // size of the central directory - if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; - // offset of start of central directory with respect to the starting disk number - if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; - // zipfile comment length - if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; - if ((central_pos+fin->initial_offsetinitial_offset - (us.offset_central_dir+us.size_central_dir); - us.central_pos = central_pos; - us.pfile_in_zip_read = NULL; - fin->initial_offset = 0; // since the zipfile itself is expected to handle this - - unz_s *s = (unz_s*)zmalloc(sizeof(unz_s)); - *s=us; - unzGoToFirstFile((unzFile)s); - return (unzFile)s; -} - - - -// Close a ZipFile opened with unzipOpen. -// If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), -// these files MUST be closed with unzipCloseCurrentFile before call unzipClose. -// return UNZ_OK if there is no problem. -int unzClose (unzFile file) -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - if (s->pfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - lufclose(s->file); - if (s) zfree(s); // unused s=0; - return UNZ_OK; -} - - -// Write info about the ZipFile in the *pglobal_info structure. -// No preparation of the structure is needed -// return UNZ_OK if there is no problem. -int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -// Translate date/time from Dos format to tm_unz (readable more easilty) -void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -// Get Info about the current file in the zipfile, with internal only info -int unzlocal_GetCurrentFileInfoInternal (unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize); - -int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, - unz_file_info_internal *pfile_info_internal, char *szFileName, - uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, - char *szComment, uLong commentBufferSize) -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - long lSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) - err=UNZ_ERRNO; - - - // we check the magic - if (err==UNZ_OK) - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (lufread(szFileName,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (lufread(extraField,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek += file_info.size_file_extra - uSizeRead; - } - else - lSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) - {} // unused lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (lufread(szComment,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - //unused lSeek+=file_info.size_file_comment - uSizeRead; - } - else {} //unused lSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -// Write info about the ZipFile in the *pglobal_info structure. -// No preparation of the structure is needed -// return UNZ_OK if there is no problem. -int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, - char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, - char *szComment, uLong commentBufferSize) -{ return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, szComment,commentBufferSize); -} - - -// Set the current file of the zipfile to the first file. -// return UNZ_OK if there is no problem -int unzGoToFirstFile (unzFile file) -{ - int err; - unz_s* s; - if (file==NULL) return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -// Set the current file of the zipfile to the next file. -// return UNZ_OK if there is no problem -// return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -int unzGoToNextFile (unzFile file) -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -// Try locate the file szFileName in the zipfile. -// For the iCaseSensitivity signification, see unzStringFileNameCompare -// return value : -// UNZ_OK if the file is found. It becomes the current file. -// UNZ_END_OF_LIST_OF_FILE if the file is not found -int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) -{ - unz_s* s; - int err; - - - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (unzStringFileNameCompare(szCurrentFileName,szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - return err; -} - - -// Read the local header of the current zipfile -// Check the coherency of the local header and info in the end of central -// directory about this file -// store in *piSizeVar the size of extra info in local header -// (filename and size of extra field data) -int unzlocal_CheckCurrentFileCoherencyHeader (unz_s *s,uInt *piSizeVar, - uLong *poffset_local_extrafield, uInt *psize_local_extrafield) -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; -// else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) -// err=UNZ_BADZIPFILE; - if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size compr - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - - - - - -// Open for reading data the current file in the zipfile. -// If there is no error and the file is opened, the return value is UNZ_OK. -int unzOpenCurrentFile (unzFile file, const char *password) -{ - int err; - int Store; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; // offset of the local extra field - uInt size_local_extrafield; // size of the local extra field - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*)zmalloc(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)zmalloc(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); //unused pfile_in_zip_read_info=0; - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) - { // unused err=UNZ_BADZIPFILE; - } - Store = s->cur_file_info.compression_method==0; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; - pfile_in_zip_read_info->file=s->file; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if (!Store) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - - err=inflateInit2(&pfile_in_zip_read_info->stream); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - // windowBits is passed < 0 to tell that there is no zlib header. - // Note that in this case inflate *requires* an extra "dummy" byte - // after the compressed stream in order to complete decompression and - // return Z_STREAM_END. - // In unzip, i don't wait absolutely Z_STREAM_END because I known the - // size of both compressed and uncompressed data - } - pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; - pfile_in_zip_read_info->encrypted = (s->cur_file_info.flag&1)!=0; - bool extlochead = (s->cur_file_info.flag&8)!=0; - if (extlochead) pfile_in_zip_read_info->crcenctest = (char)((s->cur_file_info.dosDate>>8)&0xff); - else pfile_in_zip_read_info->crcenctest = (char)(s->cur_file_info.crc >> 24); - pfile_in_zip_read_info->encheadleft = (pfile_in_zip_read_info->encrypted?12:0); - pfile_in_zip_read_info->keys[0] = 305419896L; - pfile_in_zip_read_info->keys[1] = 591751049L; - pfile_in_zip_read_info->keys[2] = 878082192L; - for (const char *cp=password; cp!=0 && *cp!=0; cp++) Uupdate_keys(pfile_in_zip_read_info->keys,*cp); - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - s->pfile_in_zip_read = pfile_in_zip_read_info; - - return UNZ_OK; -} - - -// Read bytes from the current file. -// buf contain buffer where data must be copied -// len the size of buf. -// return the number of byte copied if somes bytes are copied (and also sets *reached_eof) -// return 0 if the end of file was reached. (and also sets *reached_eof). -// return <0 with error code if there is an error. (in which case *reached_eof is meaningless) -// (UNZ_ERRNO for IO error, or zLib error for uncompress error) -int unzReadCurrentFile (unzFile file, voidp buf, unsigned len, bool *reached_eof) -{ int err=UNZ_OK; - uInt iRead = 0; - if (reached_eof!=0) *reached_eof=false; - - unz_s *s = (unz_s*)file; - if (s==NULL) return UNZ_PARAMERROR; - - file_in_zip_read_info_s* pfile_in_zip_read_info = s->pfile_in_zip_read; - if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; - if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE; - if (len==0) return 0; - - pfile_in_zip_read_info->stream.next_out = (Byte*)buf; - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if (len>pfile_in_zip_read_info->rest_read_uncompressed) - { pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - } - - while (pfile_in_zip_read_info->stream.avail_out>0) - { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) - { uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) {if (reached_eof!=0) *reached_eof=true; return UNZ_EOF;} - if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; - if (lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - pfile_in_zip_read_info->stream.next_in = (Byte*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - // - if (pfile_in_zip_read_info->encrypted) - { char *buf = (char*)pfile_in_zip_read_info->stream.next_in; - for (unsigned int i=0; ikeys,buf[i]); - } - } - - unsigned int uDoEncHead = pfile_in_zip_read_info->encheadleft; - if (uDoEncHead>pfile_in_zip_read_info->stream.avail_in) uDoEncHead=pfile_in_zip_read_info->stream.avail_in; - if (uDoEncHead>0) - { char bufcrc=pfile_in_zip_read_info->stream.next_in[uDoEncHead-1]; - pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead; - pfile_in_zip_read_info->stream.avail_in -= uDoEncHead; - pfile_in_zip_read_info->stream.next_in += uDoEncHead; - pfile_in_zip_read_info->encheadleft -= uDoEncHead; - if (pfile_in_zip_read_info->encheadleft==0) - { if (bufcrc!=pfile_in_zip_read_info->crcenctest) return UNZ_PASSWORD; - } - } - - if (pfile_in_zip_read_info->compression_method==0) - { uInt uDoCopy,i ; - if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) - { uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - } - else - { uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - } - for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); - pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,pfile_in_zip_read_info->stream.next_out,uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - if (pfile_in_zip_read_info->rest_read_uncompressed==0) {if (reached_eof!=0) *reached_eof=true;} - } - else - { uLong uTotalOutBefore,uTotalOutAfter; - const Byte *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - // - err=inflate(&pfile_in_zip_read_info->stream,flush); - // - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,bufBefore,(uInt)(uOutThis)); - pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - if (err==Z_STREAM_END || pfile_in_zip_read_info->rest_read_uncompressed==0) - { if (reached_eof!=0) *reached_eof=true; - return iRead; - } - if (err!=Z_OK) break; - } - } - - if (err==Z_OK) return iRead; - return err; -} - - -// Give the current position in uncompressed data -z_off_t unztell (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - - -// return 1 if the end of file was reached, 0 elsewhere -int unzeof (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -// Read extra field from the current file (opened by unzOpenCurrentFile) -// This is the local-header version of the extra field (sometimes, there is -// more info in the local-header version than in the central-header) -// if buf==NULL, it return the size of the local extra field that can be read -// if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. -// the return value is the number of bytes copied in buf, or (if <0) the error code -int unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (lufread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - - return (int)read_now; -} - -// Close the file in zip opened with unzipOpenCurrentFile -// Return UNZ_CRCERROR if all the file was read but the CRC is not good -int unzCloseCurrentFile (unzFile file) -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - if (pfile_in_zip_read_info->read_buffer!=0) - { void *buf = pfile_in_zip_read_info->read_buffer; - zfree(buf); - pfile_in_zip_read_info->read_buffer=0; - } - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; - - s->pfile_in_zip_read=NULL; - - return err; -} - - -// Get the global comment string of the ZipFile, in the szComment buffer. -// uSizeBuf is the size of the szComment buffer. -// return the number of byte copied or an error code <0 -int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) -{ //int err=UNZ_OK; - unz_s* s; - uLong uReadThis ; - if (file==NULL) return UNZ_PARAMERROR; - s=(unz_s*)file; - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; - if (lufseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO; - if (uReadThis>0) - { *szComment='\0'; - if (lufread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO; - } - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - - - - - -int unzOpenCurrentFile (unzFile file, const char *password); -int unzReadCurrentFile (unzFile file, void *buf, unsigned len); -int unzCloseCurrentFile (unzFile file); - - -typedef unsigned __int32 lutime_t; // define it ourselves since we don't include time.h - -FILETIME timet2filetime(const lutime_t t) -{ LONGLONG i = Int32x32To64(t,10000000) + 116444736000000000; - FILETIME ft; - ft.dwLowDateTime = (DWORD) i; - ft.dwHighDateTime = (DWORD)(i >>32); - return ft; -} - -FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime) -{ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 - // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 - SYSTEMTIME st; - st.wYear = (WORD)(((dosdate>>9)&0x7f) + 1980); - st.wMonth = (WORD)((dosdate>>5)&0xf); - st.wDay = (WORD)(dosdate&0x1f); - st.wHour = (WORD)((dostime>>11)&0x1f); - st.wMinute = (WORD)((dostime>>5)&0x3f); - st.wSecond = (WORD)((dostime&0x1f)*2); - st.wMilliseconds = 0; - FILETIME ft; SystemTimeToFileTime(&st,&ft); - return ft; -} - - - -class TUnzip -{ public: - TUnzip(const char *pwd) : uf(0), unzbuf(0), currentfile(-1), czei(-1), password(0) {if (pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}} - ~TUnzip() {if (password!=0) delete[] password; password=0; if (unzbuf!=0) delete[] unzbuf; unzbuf=0;} - - unzFile uf; int currentfile; ZIPENTRY cze; int czei; - char *password; - char *unzbuf; // lazily created and destroyed, used by Unzip - TCHAR rootdir[MAX_PATH]; // includes a trailing slash - - ZRESULT Open(void *z,unsigned int len,DWORD flags); - ZRESULT Get(int index,ZIPENTRY *ze); - ZRESULT Find(const TCHAR *name,bool ic,int *index,ZIPENTRY *ze); - ZRESULT Unzip(int index,void *dst,unsigned int len,DWORD flags); - ZRESULT SetUnzipBaseDir(const TCHAR *dir); - ZRESULT Close(); -}; - - -ZRESULT TUnzip::Open(void *z,unsigned int len,DWORD flags) -{ if (uf!=0 || currentfile!=-1) return ZR_NOTINITED; - // -#ifdef GetCurrentDirectory - GetCurrentDirectory(MAX_PATH,rootdir); -#else - _tcscpy(rootdir,_T("\\")); -#endif - TCHAR lastchar = rootdir[_tcslen(rootdir)-1]; - if (lastchar!='\\' && lastchar!='/') _tcscat(rootdir,_T("\\")); - // - if (flags==ZIP_HANDLE) - { // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. - DWORD res = SetFilePointer(z,0,0,FILE_CURRENT); - bool canseek = (res!=0xFFFFFFFF); - if (!canseek) return ZR_SEEK; - } - ZRESULT e; LUFILE *f = lufopen(z,len,flags,&e); - if (f==NULL) return e; - uf = unzOpenInternal(f); - if (uf==0) return ZR_NOFILE; - return ZR_OK; -} - -ZRESULT TUnzip::SetUnzipBaseDir(const TCHAR *dir) -{ _tcscpy(rootdir,dir); - TCHAR lastchar = rootdir[_tcslen(rootdir)-1]; - if (lastchar!='\\' && lastchar!='/') _tcscat(rootdir,_T("\\")); - return ZR_OK; -} - -ZRESULT TUnzip::Get(int index,ZIPENTRY *ze) -{ if (index<-1 || index>=(int)uf->gi.number_entry) return ZR_ARGS; - if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; - if (index==czei && index!=-1) {memcpy(ze,&cze,sizeof(ZIPENTRY)); return ZR_OK;} - if (index==-1) - { ze->index = uf->gi.number_entry; - ze->name[0]=0; - ze->attr=0; - ze->atime.dwLowDateTime=0; ze->atime.dwHighDateTime=0; - ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0; - ze->mtime.dwLowDateTime=0; ze->mtime.dwHighDateTime=0; - ze->comp_size=0; - ze->unc_size=0; - return ZR_OK; - } - if (index<(int)uf->num_file) unzGoToFirstFile(uf); - while ((int)uf->num_filefile,offset,SEEK_SET)!=0) return ZR_READ; - unsigned char *extra = new unsigned char[extralen]; - if (lufread(extra,1,(uInt)extralen,uf->file)!=extralen) {delete[] extra; return ZR_READ;} - // - ze->index=uf->num_file; - TCHAR tfn[MAX_PATH]; -#ifdef UNICODE - MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH); -#else - strcpy(tfn,fn); -#endif - // As a safety feature: if the zip filename had sneaky stuff - // like "c:\windows\file.txt" or "\windows\file.txt" or "fred\..\..\..\windows\file.txt" - // then we get rid of them all. That way, when the programmer does UnzipItem(hz,i,ze.name), - // it won't be a problem. (If the programmer really did want to get the full evil information, - // then they can edit out this security feature from here). - // In particular, we chop off any prefixes that are "c:\" or "\" or "/" or "[stuff]\.." or "[stuff]/.." - const TCHAR *sfn=tfn; - for (;;) - { if (sfn[0]!=0 && sfn[1]==':') {sfn+=2; continue;} - if (sfn[0]=='\\') {sfn++; continue;} - if (sfn[0]=='/') {sfn++; continue;} - const TCHAR *c; - c=_tcsstr(sfn,_T("\\..\\")); if (c!=0) {sfn=c+4; continue;} - c=_tcsstr(sfn,_T("\\../")); if (c!=0) {sfn=c+4; continue;} - c=_tcsstr(sfn,_T("/../")); if (c!=0) {sfn=c+4; continue;} - c=_tcsstr(sfn,_T("/..\\")); if (c!=0) {sfn=c+4; continue;} - break; - } - _tcscpy(ze->name, sfn); - - - // zip has an 'attribute' 32bit value. Its lower half is windows stuff - // its upper half is standard unix stat.st_mode. We'll start trying - // to read it in unix mode - unsigned long a = ufi.external_fa; - bool isdir = (a&0x40000000)!=0; - bool readonly= (a&0x00800000)==0; - //bool readable= (a&0x01000000)!=0; // unused - //bool executable=(a&0x00400000)!=0; // unused - bool hidden=false, system=false, archive=true; - // but in normal hostmodes these are overridden by the lower half... - int host = ufi.version>>8; - if (host==0 || host==7 || host==11 || host==14) - { readonly= (a&0x00000001)!=0; - hidden= (a&0x00000002)!=0; - system= (a&0x00000004)!=0; - isdir= (a&0x00000010)!=0; - archive= (a&0x00000020)!=0; - } - ze->attr=0; - if (isdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY; - if (archive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE; - if (hidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN; - if (readonly) ze->attr|=FILE_ATTRIBUTE_READONLY; - if (system) ze->attr|=FILE_ATTRIBUTE_SYSTEM; - ze->comp_size = ufi.compressed_size; - ze->unc_size = ufi.uncompressed_size; - // - WORD dostime = (WORD)(ufi.dosDate&0xFFFF); - WORD dosdate = (WORD)((ufi.dosDate>>16)&0xFFFF); - FILETIME ftd = dosdatetime2filetime(dosdate,dostime); - FILETIME ft; LocalFileTimeToFileTime(&ftd,&ft); - ze->atime=ft; ze->ctime=ft; ze->mtime=ft; - // the zip will always have at least that dostime. But if it also has - // an extra header, then we'll instead get the info from that. - unsigned int epos=0; - while (epos+4mtime = timet2filetime(mtime); - } - if (hasatime) - { lutime_t atime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); - epos+=4; - ze->atime = timet2filetime(atime); - } - if (hasctime) - { lutime_t ctime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); - epos+=4; - ze->ctime = timet2filetime(ctime); - } - break; - } - // - if (extra!=0) delete[] extra; - memcpy(&cze,ze,sizeof(ZIPENTRY)); czei=index; - return ZR_OK; -} - -ZRESULT TUnzip::Find(const TCHAR *tname,bool ic,int *index,ZIPENTRY *ze) -{ char name[MAX_PATH]; -#ifdef UNICODE - WideCharToMultiByte(CP_UTF8,0,tname,-1,name,MAX_PATH,0,0); -#else - strcpy(name,tname); -#endif - int res = unzLocateFile(uf,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE); - if (res!=UNZ_OK) - { if (index!=0) *index=-1; - if (ze!=NULL) {ZeroMemory(ze,sizeof(ZIPENTRY)); ze->index=-1;} - return ZR_NOTFOUND; - } - if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; - int i = (int)uf->num_file; - if (index!=NULL) *index=i; - if (ze!=NULL) - { ZRESULT zres = Get(i,ze); - if (zres!=ZR_OK) return zres; - } - return ZR_OK; -} - -void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) -{ if (rootdir!=0 && GetFileAttributes(rootdir)==0xFFFFFFFF) CreateDirectory(rootdir,0); - if (*dir==0) return; - const TCHAR *lastslash=dir, *c=lastslash; - while (*c!=0) {if (*c=='/' || *c=='\\') lastslash=c; c++;} - const TCHAR *name=lastslash; - if (lastslash!=dir) - { TCHAR tmp[MAX_PATH]; memcpy(tmp,dir,sizeof(TCHAR)*(lastslash-dir)); - tmp[lastslash-dir]=0; - EnsureDirectory(rootdir,tmp); - name++; - } - TCHAR cd[MAX_PATH]; *cd=0; if (rootdir!=0) _tcscpy(cd,rootdir); _tcscat(cd,dir); - if (GetFileAttributes(cd)==0xFFFFFFFF) CreateDirectory(cd,NULL); -} - - - -ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) -{ if (flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE) return ZR_ARGS; - if (flags==ZIP_MEMORY) - { if (index!=currentfile) - { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; - if (index>=(int)uf->gi.number_entry) return ZR_ARGS; - if (index<(int)uf->num_file) unzGoToFirstFile(uf); - while ((int)uf->num_file0) return ZR_MORE; - if (res==UNZ_PASSWORD) return ZR_PASSWORD; - return ZR_FLATE; - } - // otherwise we're writing to a handle or a file - if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; - if (index>=(int)uf->gi.number_entry) return ZR_ARGS; - if (index<(int)uf->num_file) unzGoToFirstFile(uf); - while ((int)uf->num_file0) {DWORD writ; BOOL bres=WriteFile(h,unzbuf,res,&writ,NULL); if (!bres) {haderr=ZR_WRITE; break;}} - if (reached_eof) break; - if (res==0) {haderr=ZR_FLATE; break;} - } - if (!haderr) SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); // may fail if it was a pipe - if (flags!=ZIP_HANDLE) CloseHandle(h); - unzCloseCurrentFile(uf); - if (haderr!=0) return haderr; - return ZR_OK; -} - -ZRESULT TUnzip::Close() -{ if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; - if (uf!=0) unzClose(uf); uf=0; - return ZR_OK; -} - - - - - -ZRESULT lasterrorU=ZR_OK; - -unsigned int FormatZipMessageU(ZRESULT code, TCHAR *buf,unsigned int len) -{ if (code==ZR_RECENT) code=lasterrorU; - const TCHAR *msg=_T("unknown zip result code"); - switch (code) - { case ZR_OK: msg=_T("Success"); break; - case ZR_NODUPH: msg=_T("Culdn't duplicate handle"); break; - case ZR_NOFILE: msg=_T("Couldn't create/open file"); break; - case ZR_NOALLOC: msg=_T("Failed to allocate memory"); break; - case ZR_WRITE: msg=_T("Error writing to file"); break; - case ZR_NOTFOUND: msg=_T("File not found in the zipfile"); break; - case ZR_MORE: msg=_T("Still more data to unzip"); break; - case ZR_CORRUPT: msg=_T("Zipfile is corrupt or not a zipfile"); break; - case ZR_READ: msg=_T("Error reading file"); break; - case ZR_PASSWORD: msg=_T("Correct password required"); break; - case ZR_ARGS: msg=_T("Caller: faulty arguments"); break; - case ZR_PARTIALUNZ: msg=_T("Caller: the file had already been partially unzipped"); break; - case ZR_NOTMMAP: msg=_T("Caller: can only get memory of a memory zipfile"); break; - case ZR_MEMSIZE: msg=_T("Caller: not enough space allocated for memory zipfile"); break; - case ZR_FAILED: msg=_T("Caller: there was a previous error"); break; - case ZR_ENDED: msg=_T("Caller: additions to the zip have already been ended"); break; - case ZR_ZMODE: msg=_T("Caller: mixing creation and opening of zip"); break; - case ZR_NOTINITED: msg=_T("Zip-bug: internal initialisation not completed"); break; - case ZR_SEEK: msg=_T("Zip-bug: trying to seek the unseekable"); break; - case ZR_MISSIZE: msg=_T("Zip-bug: the anticipated size turned out wrong"); break; - case ZR_NOCHANGE: msg=_T("Zip-bug: tried to change mind, but not allowed"); break; - case ZR_FLATE: msg=_T("Zip-bug: an internal error during flation"); break; - } - unsigned int mlen=(unsigned int)_tcslen(msg); - if (buf==0 || len==0) return mlen; - unsigned int n=mlen; if (n+1>len) n=len-1; - _tcsncpy(buf,msg,n); buf[n]=0; - return mlen; -} - - -typedef struct -{ DWORD flag; - TUnzip *unz; -} TUnzipHandleData; - -HZIP OpenZipInternal(void *z,unsigned int len,DWORD flags, const char *password) -{ TUnzip *unz = new TUnzip(password); - lasterrorU = unz->Open(z,len,flags); - if (lasterrorU!=ZR_OK) {delete unz; return 0;} - TUnzipHandleData *han = new TUnzipHandleData; - han->flag=1; han->unz=unz; return (HZIP)han; -} -HZIP OpenZipHandle(HANDLE h, const char *password) {return OpenZipInternal((void*)h,0,ZIP_HANDLE,password);} -HZIP OpenZip(const TCHAR *fn, const char *password) {return OpenZipInternal((void*)fn,0,ZIP_FILENAME,password);} -HZIP OpenZip(void *z,unsigned int len, const char *password) {return OpenZipInternal(z,len,ZIP_MEMORY,password);} - - -ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze) -{ ze->index=0; *ze->name=0; ze->unc_size=0; - if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} - TUnzipHandleData *han = (TUnzipHandleData*)hz; - if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} - TUnzip *unz = han->unz; - lasterrorU = unz->Get(index,ze); - return lasterrorU; -} - -ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) -{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} - TUnzipHandleData *han = (TUnzipHandleData*)hz; - if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} - TUnzip *unz = han->unz; - lasterrorU = unz->Find(name,ic,index,ze); - return lasterrorU; -} - -ZRESULT UnzipItemInternal(HZIP hz, int index, void *dst, unsigned int len, DWORD flags) -{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} - TUnzipHandleData *han = (TUnzipHandleData*)hz; - if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} - TUnzip *unz = han->unz; - lasterrorU = unz->Unzip(index,dst,len,flags); - return lasterrorU; -} -ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h) {return UnzipItemInternal(hz,index,(void*)h,0,ZIP_HANDLE);} -ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn) {return UnzipItemInternal(hz,index,(void*)fn,0,ZIP_FILENAME);} -ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len) {return UnzipItemInternal(hz,index,z,len,ZIP_MEMORY);} - -ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir) -{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} - TUnzipHandleData *han = (TUnzipHandleData*)hz; - if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} - TUnzip *unz = han->unz; - lasterrorU = unz->SetUnzipBaseDir(dir); - return lasterrorU; -} - - -ZRESULT CloseZipU(HZIP hz) -{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} - TUnzipHandleData *han = (TUnzipHandleData*)hz; - if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} - TUnzip *unz = han->unz; - lasterrorU = unz->Close(); - delete unz; - delete han; - return lasterrorU; -} - -bool IsZipHandleU(HZIP hz) -{ if (hz==0) return false; - TUnzipHandleData *han = (TUnzipHandleData*)hz; - return (han->flag==1); -} - - diff --git a/CocXlsxTool/unzip.h b/CocXlsxTool/unzip.h deleted file mode 100644 index 70d3ad3c..00000000 --- a/CocXlsxTool/unzip.h +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef _unzip_H -#define _unzip_H - -// UNZIPPING functions -- for unzipping. -// This file is a repackaged form of extracts from the zlib code available -// at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original -// copyright notice may be found in unzip.cpp. The repackaging was done -// by Lucian Wischik to simplify and extend its use in Windows/C++. Also -// encryption and unicode filenames have been added. - - -#ifndef _zip_H -DECLARE_HANDLE(HZIP); -#endif -// An HZIP identifies a zip file that has been opened - -typedef DWORD ZRESULT; -// return codes from any of the zip functions. Listed later. - -typedef struct -{ int index; // index of this file within the zip - TCHAR name[MAX_PATH]; // filename within the zip - DWORD attr; // attributes, as in GetFileAttributes. - FILETIME atime,ctime,mtime;// access, create, modify filetimes - long comp_size; // sizes of item, compressed and uncompressed. These - long unc_size; // may be -1 if not yet known (e.g. being streamed in) -} ZIPENTRY; - - -HZIP OpenZip(const TCHAR *fn, const char *password); -HZIP OpenZip(void *z,unsigned int len, const char *password); -HZIP OpenZipHandle(HANDLE h, const char *password); -// OpenZip - opens a zip file and returns a handle with which you can -// subsequently examine its contents. You can open a zip file from: -// from a pipe: OpenZipHandle(hpipe_read,0); -// from a file (by handle): OpenZipHandle(hfile,0); -// from a file (by name): OpenZip("c:\\test.zip","password"); -// from a memory block: OpenZip(bufstart, buflen,0); -// If the file is opened through a pipe, then items may only be -// accessed in increasing order, and an item may only be unzipped once, -// although GetZipItem can be called immediately before and after unzipping -// it. If it's opened in any other way, then full random access is possible. -// Note: pipe input is not yet implemented. -// Note: zip passwords are ascii, not unicode. -// Note: for windows-ce, you cannot close the handle until after CloseZip. -// but for real windows, the zip makes its own copy of your handle, so you -// can close yours anytime. - -ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze); -// GetZipItem - call this to get information about an item in the zip. -// If index is -1 and the file wasn't opened through a pipe, -// then it returns information about the whole zipfile -// (and in particular ze.index returns the number of index items). -// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) -// See below for notes on what happens when you unzip such an item. -// Note: if you are opening the zip through a pipe, then random access -// is not possible and GetZipItem(-1) fails and you can't discover the number -// of items except by calling GetZipItem on each one of them in turn, -// starting at 0, until eventually the call fails. Also, in the event that -// you are opening through a pipe and the zip was itself created into a pipe, -// then then comp_size and sometimes unc_size as well may not be known until -// after the item has been unzipped. - -ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); -// FindZipItem - finds an item by name. ic means 'insensitive to case'. -// It returns the index of the item, and returns information about it. -// If nothing was found, then index is set to -1 and the function returns -// an error code. - -ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn); -ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len); -ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h); -// UnzipItem - given an index to an item, unzips it. You can unzip to: -// to a pipe: UnzipItemHandle(hz,i, hpipe_write); -// to a file (by handle): UnzipItemHandle(hz,i, hfile); -// to a file (by name): UnzipItem(hz,i, ze.name); -// to a memory block: UnzipItem(hz,i, buf,buflen); -// In the final case, if the buffer isn't large enough to hold it all, -// then the return code indicates that more is yet to come. If it was -// large enough, and you want to know precisely how big, GetZipItem. -// Note: zip files are normally stored with relative pathnames. If you -// unzip with ZIP_FILENAME a relative pathname then the item gets created -// relative to the current directory - it first ensures that all necessary -// subdirectories have been created. Also, the item may itself be a directory. -// If you unzip a directory with ZIP_FILENAME, then the directory gets created. -// If you unzip it to a handle or a memory block, then nothing gets created -// and it emits 0 bytes. -ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir); -// if unzipping to a filename, and it's a relative filename, then it will be relative to here. -// (defaults to current-directory). - - -ZRESULT CloseZip(HZIP hz); -// CloseZip - the zip handle must be closed with this function. - -unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); -// FormatZipMessage - given an error code, formats it as a string. -// It returns the length of the error message. If buf/len points -// to a real buffer, then it also writes as much as possible into there. - - -// These are the result codes: -#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, -#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. -// The following come from general system stuff (e.g. files not openable) -#define ZR_GENMASK 0x0000FF00 -#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle -#define ZR_NOFILE 0x00000200 // couldn't create/open the file -#define ZR_NOALLOC 0x00000300 // failed to allocate some resource -#define ZR_WRITE 0x00000400 // a general error writing to the file -#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip -#define ZR_MORE 0x00000600 // there's still more data to be unzipped -#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile -#define ZR_READ 0x00000800 // a general error reading the file -#define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file -// The following come from mistakes on the part of the caller -#define ZR_CALLERMASK 0x00FF0000 -#define ZR_ARGS 0x00010000 // general mistake with the arguments -#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't -#define ZR_MEMSIZE 0x00030000 // the memory size is too small -#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function -#define ZR_ENDED 0x00050000 // the zip creation has already been closed -#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken -#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped -#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip -// The following come from bugs within the zip library itself -#define ZR_BUGMASK 0xFF000000 -#define ZR_NOTINITED 0x01000000 // initialisation didn't work -#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file -#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed -#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code - - - - - -// e.g. -// -// SetCurrentDirectory("c:\\docs\\stuff"); -// HZIP hz = OpenZip("c:\\stuff.zip",0); -// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; -// for (int i=0; i -#include -#include -#include "zip.h" - - -// THIS FILE is almost entirely based upon code by info-zip. -// It has been modified by Lucian Wischik. The modifications -// were a complete rewrite of the bit of code that generates the -// layout of the zipfile, and support for zipping to/from memory -// or handles or pipes or pagefile or diskfiles, encryption, unicode. -// The original code may be found at http://www.info-zip.org -// The original copyright text follows. -// -// -// -// This is version 1999-Oct-05 of the Info-ZIP copyright and license. -// The definitive version of this document should be available at -// ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely. -// -// Copyright (c) 1990-1999 Info-ZIP. All rights reserved. -// -// For the purposes of this copyright and license, "Info-ZIP" is defined as -// the following set of individuals: -// -// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, -// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, -// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum, -// Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller, -// Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel, -// Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen, -// Paul von Behren, Rich Wales, Mike White -// -// This software is provided "as is," without warranty of any kind, express -// or implied. In no event shall Info-ZIP or its contributors be held liable -// for any direct, indirect, incidental, special or consequential damages -// arising out of the use of or inability to use this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. Redistributions of source code must retain the above copyright notice, -// definition, disclaimer, and this list of conditions. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, definition, disclaimer, and this list of conditions in -// documentation and/or other materials provided with the distribution. -// -// 3. Altered versions--including, but not limited to, ports to new operating -// systems, existing ports with new graphical interfaces, and dynamic, -// shared, or static library versions--must be plainly marked as such -// and must not be misrepresented as being the original source. Such -// altered versions also must not be misrepresented as being Info-ZIP -// releases--including, but not limited to, labeling of the altered -// versions with the names "Info-ZIP" (or any variation thereof, including, -// but not limited to, different capitalizations), "Pocket UnZip," "WiZ" -// or "MacZip" without the explicit permission of Info-ZIP. Such altered -// versions are further prohibited from misrepresentative use of the -// Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s). -// -// 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," -// "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and -// binary releases. -// - - -typedef unsigned char uch; // unsigned 8-bit value -typedef unsigned short ush; // unsigned 16-bit value -typedef unsigned long ulg; // unsigned 32-bit value -typedef size_t extent; // file size -typedef unsigned Pos; // must be at least 32 bits -typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing - -#ifndef EOF -#define EOF (-1) -#endif - - -// Error return values. The values 0..4 and 12..18 follow the conventions -// of PKZIP. The values 4..10 are all assigned to "insufficient memory" -// by PKZIP, so the codes 5..10 are used here for other purposes. -#define ZE_MISS -1 // used by procname(), zipbare() -#define ZE_OK 0 // success -#define ZE_EOF 2 // unexpected end of zip file -#define ZE_FORM 3 // zip file structure error -#define ZE_MEM 4 // out of memory -#define ZE_LOGIC 5 // internal logic error -#define ZE_BIG 6 // entry too large to split -#define ZE_NOTE 7 // invalid comment format -#define ZE_TEST 8 // zip test (-T) failed or out of memory -#define ZE_ABORT 9 // user interrupt or termination -#define ZE_TEMP 10 // error using a temp file -#define ZE_READ 11 // read or seek error -#define ZE_NONE 12 // nothing to do -#define ZE_NAME 13 // missing or empty zip file -#define ZE_WRITE 14 // error writing to a file -#define ZE_CREAT 15 // couldn't open to write -#define ZE_PARMS 16 // bad command line -#define ZE_OPEN 18 // could not open a specified file to read -#define ZE_MAXERR 18 // the highest error number - - -// internal file attribute -#define UNKNOWN (-1) -#define BINARY 0 -#define ASCII 1 - -#define BEST -1 // Use best method (deflation or store) -#define STORE 0 // Store method -#define DEFLATE 8 // Deflation method - -#define CRCVAL_INITIAL 0L - -// MSDOS file or directory attributes -#define MSDOS_HIDDEN_ATTR 0x02 -#define MSDOS_DIR_ATTR 0x10 - -// Lengths of headers after signatures in bytes -#define LOCHEAD 26 -#define CENHEAD 42 -#define ENDHEAD 18 - -// Definitions for extra field handling: -#define EB_HEADSIZE 4 /* length of a extra field block header */ -#define EB_LEN 2 /* offset of data length field in header */ -#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */ -#define EB_UT_FLAGS 0 /* byte offset of Flags field */ -#define EB_UT_TIME1 1 /* byte offset of 1st time value */ -#define EB_UT_FL_MTIME (1 << 0) /* mtime present */ -#define EB_UT_FL_ATIME (1 << 1) /* atime present */ -#define EB_UT_FL_CTIME (1 << 2) /* ctime present */ -#define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n)) -#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3)) -#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1)) - - -// Macros for writing machine integers to little-endian format -#define PUTSH(a,f) {char _putsh_c=(char)((a)&0xff); wfunc(param,&_putsh_c,1); _putsh_c=(char)((a)>>8); wfunc(param,&_putsh_c,1);} -#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))} - - -// -- Structure of a ZIP file -- -// Signatures for zip file information headers -#define LOCSIG 0x04034b50L -#define CENSIG 0x02014b50L -#define ENDSIG 0x06054b50L -#define EXTLOCSIG 0x08074b50L - - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -// The minimum and maximum match lengths - - -#define WSIZE (0x8000) -// Maximum window size = 32K. If you are really short of memory, compile -// with a smaller WSIZE but this reduces the compression ratio for files -// of size > WSIZE. WSIZE must be a power of two in the current implementation. -// - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -// Minimum amount of lookahead, except at the end of the input file. -// See deflate.c for comments about the MIN_MATCH+1. -// - -#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) -// In order to simplify the code, particularly on 16 bit machines, match -// distances are limited to MAX_DIST instead of WSIZE. -// - - -#define ZIP_HANDLE 1 -#define ZIP_FILENAME 2 -#define ZIP_MEMORY 3 -#define ZIP_FOLDER 4 - - - -// =========================================================================== -// Constants -// - -#define MAX_BITS 15 -// All codes must not exceed MAX_BITS bits - -#define MAX_BL_BITS 7 -// Bit length codes must not exceed MAX_BL_BITS bits - -#define LENGTH_CODES 29 -// number of length codes, not counting the special END_BLOCK code - -#define LITERALS 256 -// number of literal bytes 0..255 - -#define END_BLOCK 256 -// end of block literal code - -#define L_CODES (LITERALS+1+LENGTH_CODES) -// number of Literal or Length codes, including the END_BLOCK code - -#define D_CODES 30 -// number of distance codes - -#define BL_CODES 19 -// number of codes used to transfer the bit lengths - - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -// The three kinds of block type - -#define LIT_BUFSIZE 0x8000 -#define DIST_BUFSIZE LIT_BUFSIZE -// Sizes of match buffers for literals/lengths and distances. There are -// 4 reasons for limiting LIT_BUFSIZE to 64K: -// - frequencies can be kept in 16 bit counters -// - if compression is not successful for the first block, all input data is -// still in the window so we can still emit a stored block even when input -// comes from standard input. (This can also be done for all blocks if -// LIT_BUFSIZE is not greater than 32K.) -// - if compression is not successful for a file smaller than 64K, we can -// even emit a stored file instead of a stored block (saving 5 bytes). -// - creating new Huffman trees less frequently may not provide fast -// adaptation to changes in the input data statistics. (Take for -// example a binary file with poorly compressible code followed by -// a highly compressible string table.) Smaller buffer sizes give -// fast adaptation but have of course the overhead of transmitting trees -// more frequently. -// - I can't count above 4 -// The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save -// memory at the expense of compression). Some optimizations would be possible -// if we rely on DIST_BUFSIZE == LIT_BUFSIZE. -// - -#define REP_3_6 16 -// repeat previous bit length 3-6 times (2 bits of repeat count) - -#define REPZ_3_10 17 -// repeat a zero length 3-10 times (3 bits of repeat count) - -#define REPZ_11_138 18 -// repeat a zero length 11-138 times (7 bits of repeat count) - -#define HEAP_SIZE (2*L_CODES+1) -// maximum heap size - - -// =========================================================================== -// Local data used by the "bit string" routines. -// - -#define Buf_size (8 * 2*sizeof(char)) -// Number of bits used within bi_buf. (bi_buf may be implemented on -// more than 16 bits on some systems.) - -// Output a 16 bit value to the bit stream, lower (oldest) byte first -#define PUTSHORT(state,w) \ -{ if (state.bs.out_offset >= state.bs.out_size-1) \ - state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ - state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \ - state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \ -} - -#define PUTBYTE(state,b) \ -{ if (state.bs.out_offset >= state.bs.out_size) \ - state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ - state.bs.out_buf[state.bs.out_offset++] = (char) (b); \ -} - -// DEFLATE.CPP HEADER - -#define HASH_BITS 15 -// For portability to 16 bit machines, do not use values above 15. - -#define HASH_SIZE (unsigned)(1<= HASH_BITS - -#define max_insert_length max_lazy_match -// Insert new strings in the hash table only if the match length -// is not greater than this length. This saves time but degrades compression. -// max_insert_length is used only for compression levels <= 3. - - - -const int extra_lbits[LENGTH_CODES] // extra bits for each length code - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -const int extra_dbits[D_CODES] // extra bits for each distance code - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -const int extra_blbits[BL_CODES]// extra bits for each bit length code - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -// The lengths of the bit length codes are sent in order of decreasing -// probability, to avoid transmitting the lengths for unused bit length codes. - - -typedef struct config { - ush good_length; // reduce lazy search above this match length - ush max_lazy; // do not perform lazy search above this match length - ush nice_length; // quit search above this match length - ush max_chain; -} config; - -// Values for max_lazy_match, good_match, nice_match and max_chain_length, -// depending on the desired pack level (0..9). The values given below have -// been tuned to exclude worst case performance for pathological files. -// Better values may be found for specific files. -// - -const config configuration_table[10] = { -// good lazy nice chain - {0, 0, 0, 0}, // 0 store only - {4, 4, 8, 4}, // 1 maximum speed, no lazy matches - {4, 5, 16, 8}, // 2 - {4, 6, 32, 32}, // 3 - {4, 4, 16, 16}, // 4 lazy matches */ - {8, 16, 32, 32}, // 5 - {8, 16, 128, 128}, // 6 - {8, 32, 128, 256}, // 7 - {32, 128, 258, 1024}, // 8 - {32, 258, 258, 4096}};// 9 maximum compression */ - -// Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 -// For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning. - - - - - - - -// Data structure describing a single value and its code string. -typedef struct ct_data { - union { - ush freq; // frequency count - ush code; // bit string - } fc; - union { - ush dad; // father node in Huffman tree - ush len; // length of bit string - } dl; -} ct_data; - -typedef struct tree_desc { - ct_data *dyn_tree; // the dynamic tree - ct_data *static_tree; // corresponding static tree or NULL - const int *extra_bits; // extra bits for each code or NULL - int extra_base; // base index for extra_bits - int elems; // max number of elements in the tree - int max_length; // max bit length for the codes - int max_code; // largest code with non zero frequency -} tree_desc; - - - - -class TTreeState -{ public: - TTreeState(); - - ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree - ct_data dyn_dtree[2*D_CODES+1]; // distance tree - ct_data static_ltree[L_CODES+2]; // the static literal tree... - // ... Since the bit lengths are imposed, there is no need for the L_CODES - // extra codes used during heap construction. However the codes 286 and 287 - // are needed to build a canonical tree (see ct_init below). - ct_data static_dtree[D_CODES]; // the static distance tree... - // ... (Actually a trivial tree since all codes use 5 bits.) - ct_data bl_tree[2*BL_CODES+1]; // Huffman tree for the bit lengths - - tree_desc l_desc; - tree_desc d_desc; - tree_desc bl_desc; - - ush bl_count[MAX_BITS+1]; // number of codes at each bit length for an optimal tree - - int heap[2*L_CODES+1]; // heap used to build the Huffman trees - int heap_len; // number of elements in the heap - int heap_max; // element of largest frequency - // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - // The same heap array is used to build all trees. - - uch depth[2*L_CODES+1]; - // Depth of each subtree used as tie breaker for trees of equal frequency - - uch length_code[MAX_MATCH-MIN_MATCH+1]; - // length code for each normalized match length (0 == MIN_MATCH) - - uch dist_code[512]; - // distance codes. The first 256 values correspond to the distances - // 3 .. 258, the last 256 values correspond to the top 8 bits of - // the 15 bit distances. - - int base_length[LENGTH_CODES]; - // First normalized length for each code (0 = MIN_MATCH) - - int base_dist[D_CODES]; - // First normalized distance for each code (0 = distance of 1) - - uch far l_buf[LIT_BUFSIZE]; // buffer for literals/lengths - ush far d_buf[DIST_BUFSIZE]; // buffer for distances - - uch flag_buf[(LIT_BUFSIZE/8)]; - // flag_buf is a bit array distinguishing literals from lengths in - // l_buf, and thus indicating the presence or absence of a distance. - - unsigned last_lit; // running index in l_buf - unsigned last_dist; // running index in d_buf - unsigned last_flags; // running index in flag_buf - uch flags; // current flags not yet saved in flag_buf - uch flag_bit; // current bit used in flags - // bits are filled in flags starting at bit 0 (least significant). - // Note: these flags are overkill in the current code since we don't - // take advantage of DIST_BUFSIZE == LIT_BUFSIZE. - - ulg opt_len; // bit length of current block with optimal trees - ulg static_len; // bit length of current block with static trees - - ulg cmpr_bytelen; // total byte length of compressed file - ulg cmpr_len_bits; // number of bits past 'cmpr_bytelen' - - ulg input_len; // total byte length of input file - // input_len is for debugging only since we can get it by other means. - - ush *file_type; // pointer to UNKNOWN, BINARY or ASCII -// int *file_method; // pointer to DEFLATE or STORE -}; - -TTreeState::TTreeState() -{ tree_desc a = {dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0}; l_desc = a; - tree_desc b = {dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0}; d_desc = b; - tree_desc c = {bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0}; bl_desc = c; - last_lit=0; - last_dist=0; - last_flags=0; -} - - - -class TBitState -{ public: - - int flush_flg; - // - unsigned bi_buf; - // Output buffer. bits are inserted starting at the bottom (least significant - // bits). The width of bi_buf must be at least 16 bits. - int bi_valid; - // Number of valid bits in bi_buf. All bits above the last valid bit - // are always zero. - char *out_buf; - // Current output buffer. - unsigned out_offset; - // Current offset in output buffer. - // On 16 bit machines, the buffer is limited to 64K. - unsigned out_size; - // Size of current output buffer - ulg bits_sent; // bit length of the compressed data only needed for debugging??? -}; - - - - - - - -class TDeflateState -{ public: - TDeflateState() {window_size=0;} - - uch window[2L*WSIZE]; - // Sliding window. Input bytes are read into the second half of the window, - // and move to the first half later to keep a dictionary of at least WSIZE - // bytes. With this organization, matches are limited to a distance of - // WSIZE-MAX_MATCH bytes, but this ensures that IO is always - // performed with a length multiple of the block size. Also, it limits - // the window size to 64K, which is quite useful on MSDOS. - // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would - // be less efficient since the data would have to be copied WSIZE/CBSZ times) - Pos prev[WSIZE]; - // Link to older string with same hash index. To limit the size of this - // array to 64K, this link is maintained only for the last 32K strings. - // An index in this array is thus a window index modulo 32K. - Pos head[HASH_SIZE]; - // Heads of the hash chains or NIL. If your compiler thinks that - // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC. - - ulg window_size; - // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the - // input file length plus MIN_LOOKAHEAD. - - long block_start; - // window position at the beginning of the current output block. Gets - // negative when the window is moved backwards. - - int sliding; - // Set to false when the input file is already in memory - - unsigned ins_h; // hash index of string to be inserted - - unsigned int prev_length; - // Length of the best match at previous step. Matches not greater than this - // are discarded. This is used in the lazy match evaluation. - - unsigned strstart; // start of string to insert - unsigned match_start; // start of matching string - int eofile; // flag set at end of input file - unsigned lookahead; // number of valid bytes ahead in window - - unsigned max_chain_length; - // To speed up deflation, hash chains are never searched beyond this length. - // A higher limit improves compression ratio but degrades the speed. - - unsigned int max_lazy_match; - // Attempt to find a better match only when the current match is strictly - // smaller than this value. This mechanism is used only for compression - // levels >= 4. - - unsigned good_match; - // Use a faster search when the previous match is longer than this - - int nice_match; // Stop searching when current match exceeds this -}; - -typedef __int64 lutime_t; // define it ourselves since we don't include time.h - -typedef struct iztimes { - lutime_t atime,mtime,ctime; -} iztimes; // access, modify, create times - -typedef struct zlist { - ush vem, ver, flg, how; // See central header in zipfile.c for what vem..off are - ulg tim, crc, siz, len; - extent nam, ext, cext, com; // offset of ext must be >= LOCHEAD - ush dsk, att, lflg; // offset of lflg must be >= LOCHEAD - ulg atx, off; - char name[MAX_PATH]; // File name in zip file - char *extra; // Extra field (set only if ext != 0) - char *cextra; // Extra in central (set only if cext != 0) - char *comment; // Comment (set only if com != 0) - char iname[MAX_PATH]; // Internal file name after cleanup - char zname[MAX_PATH]; // External version of internal name - int mark; // Marker for files to operate on - int trash; // Marker for files to delete - int dosflag; // Set to force MSDOS file attributes - struct zlist far *nxt; // Pointer to next header in list -} TZipFileInfo; - - -struct TState; -typedef unsigned (*READFUNC)(TState &state, char *buf,unsigned size); -typedef unsigned (*FLUSHFUNC)(void *param, const char *buf, unsigned *size); -typedef unsigned (*WRITEFUNC)(void *param, const char *buf, unsigned size); -struct TState -{ void *param; - int level; bool seekable; - READFUNC readfunc; FLUSHFUNC flush_outbuf; - TTreeState ts; TBitState bs; TDeflateState ds; - const char *err; -}; - - - - - - - - - -void Assert(TState &state,bool cond, const char *msg) -{ if (cond) return; - state.err=msg; -} -void __cdecl Trace(const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} -void __cdecl Tracec(bool ,const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} - - - -// =========================================================================== -// Local (static) routines in this file. -// - -void init_block (TState &); -void pqdownheap (TState &,ct_data *tree, int k); -void gen_bitlen (TState &,tree_desc *desc); -void gen_codes (TState &state,ct_data *tree, int max_code); -void build_tree (TState &,tree_desc *desc); -void scan_tree (TState &,ct_data *tree, int max_code); -void send_tree (TState &state,ct_data *tree, int max_code); -int build_bl_tree (TState &); -void send_all_trees (TState &state,int lcodes, int dcodes, int blcodes); -void compress_block (TState &state,ct_data *ltree, ct_data *dtree); -void set_file_type (TState &); -void send_bits (TState &state, int value, int length); -unsigned bi_reverse (unsigned code, int len); -void bi_windup (TState &state); -void copy_block (TState &state,char *buf, unsigned len, int header); - - -#define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len) -// Send a code of the given tree. c and tree must not have side effects - -// alternatively... -//#define send_code(state, c, tree) -// { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c)); -// send_bits(state, tree[c].fc.code, tree[c].dl.len); } - -#define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)]) -// Mapping from a distance to a distance code. dist is the distance - 1 and -// must not have side effects. dist_code[256] and dist_code[257] are never used. - -#define Max(a,b) (a >= b ? a : b) -/* the arguments must not have side effects */ - -/* =========================================================================== - * Allocate the match buffer, initialize the various tables and save the - * location of the internal file attribute (ascii/binary) and method - * (DEFLATE/STORE). - */ -void ct_init(TState &state, ush *attr) -{ - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - - state.ts.file_type = attr; - //state.ts.file_method = method; - state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L; - state.ts.input_len = 0L; - - if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */ - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - state.ts.base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - state.ts.base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - state.ts.base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - state.ts.dist_code[256 + dist++] = (uch)code; - } - } - Assert(state,dist == 256, "ct_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; - n = 0; - while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; - while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++; - while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++; - while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; - /* fc.codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes(state,(ct_data *)state.ts.static_ltree, L_CODES+1); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - state.ts.static_dtree[n].dl.len = 5; - state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5); - } - - /* Initialize the first block of the first file: */ - init_block(state); -} - -/* =========================================================================== - * Initialize a new block. - */ -void init_block(TState &state) -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) state.ts.dyn_ltree[n].fc.freq = 0; - for (n = 0; n < D_CODES; n++) state.ts.dyn_dtree[n].fc.freq = 0; - for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0; - - state.ts.dyn_ltree[END_BLOCK].fc.freq = 1; - state.ts.opt_len = state.ts.static_len = 0L; - state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0; - state.ts.flags = 0; state.ts.flag_bit = 1; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(tree, top) \ -{\ - top = state.ts.heap[SMALLEST]; \ - state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \ - pqdownheap(state,tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m) \ - (tree[n].fc.freq < tree[m].fc.freq || \ - (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -void pqdownheap(TState &state,ct_data *tree, int k) -{ - int v = state.ts.heap[k]; - int j = k << 1; /* left son of k */ - int htemp; /* required because of bug in SASC compiler */ - - while (j <= state.ts.heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j+1], state.ts.heap[j])) j++; - - /* Exit if v is smaller than both sons */ - htemp = state.ts.heap[j]; - if (smaller(tree, v, htemp)) break; - - /* Exchange v with the smallest son */ - state.ts.heap[k] = htemp; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - state.ts.heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -void gen_bitlen(TState &state,tree_desc *desc) -{ - ct_data *tree = desc->dyn_tree; - const int *extra = desc->extra_bits; - int base = desc->extra_base; - int max_code = desc->max_code; - int max_length = desc->max_length; - ct_data *stree = desc->static_tree; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */ - - for (h = state.ts.heap_max+1; h < HEAP_SIZE; h++) { - n = state.ts.heap[h]; - bits = tree[tree[n].dl.dad].dl.len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].dl.len = (ush)bits; - /* We overwrite tree[n].dl.dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - state.ts.bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].fc.freq; - state.ts.opt_len += (ulg)f * (bits + xbits); - if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits); - } - if (overflow == 0) return; - - Trace("\nbit length overflow\n"); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (state.ts.bl_count[bits] == 0) bits--; - state.ts.bl_count[bits]--; /* move one leaf down the tree */ - state.ts.bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */ - state.ts.bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = state.ts.bl_count[bits]; - while (n != 0) { - m = state.ts.heap[--h]; - if (m > max_code) continue; - if (tree[m].dl.len != (ush)bits) { - Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits); - state.ts.opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq; - tree[m].dl.len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -void gen_codes (TState &state, ct_data *tree, int max_code) -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (ush)((code + state.ts.bl_count[bits-1]) << 1); - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert(state,code + state.ts.bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1, - "inconsistent bit counts"); - Trace("\ngen_codes: max_code %d ", max_code); - - for (n = 0; n <= max_code; n++) { - int len = tree[n].dl.len; - if (len == 0) continue; - /* Now reverse the bits */ - tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len); - - //Tracec(tree != state.ts.static_ltree, "\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].fc.code, next_code[len]-1); - } -} - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -void build_tree(TState &state,tree_desc *desc) -{ - ct_data *tree = desc->dyn_tree; - ct_data *stree = desc->static_tree; - int elems = desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node = elems; /* next internal node of the tree */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].fc.freq != 0) { - state.ts.heap[++state.ts.heap_len] = max_code = n; - state.ts.depth[n] = 0; - } else { - tree[n].dl.len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (state.ts.heap_len < 2) { - int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[newcp].fc.freq = 1; - state.ts.depth[newcp] = 0; - state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len; - /* new is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = state.ts.heap_len/2; n >= 1; n--) pqdownheap(state,tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - do { - pqremove(tree, n); /* n = node of least frequency */ - m = state.ts.heap[SMALLEST]; /* m = node of next least frequency */ - - state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */ - state.ts.heap[--state.ts.heap_max] = m; - - /* Create a new node father of n and m */ - tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq); - state.ts.depth[node] = (uch) (Max(state.ts.depth[n], state.ts.depth[m]) + 1); - tree[n].dl.dad = tree[m].dl.dad = (ush)node; - /* and insert the new node in the heap */ - state.ts.heap[SMALLEST] = node++; - pqdownheap(state,tree, SMALLEST); - - } while (state.ts.heap_len >= 2); - - state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(state,(tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes (state,(ct_data *)tree, max_code); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. Updates opt_len to take into account the repeat - * counts. (The contribution of the bit length codes will be added later - * during the construction of bl_tree.) - */ -void scan_tree (TState &state,ct_data *tree, int max_code) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].dl.len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].dl.len = (ush)-1; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].dl.len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count); - } else if (curlen != 0) { - if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++; - state.ts.bl_tree[REP_3_6].fc.freq++; - } else if (count <= 10) { - state.ts.bl_tree[REPZ_3_10].fc.freq++; - } else { - state.ts.bl_tree[REPZ_11_138].fc.freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -void send_tree (TState &state, ct_data *tree, int max_code) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].dl.len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].dl.len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].dl.len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(state, curlen, state.ts.bl_tree); count--; - } - Assert(state,count >= 3 && count <= 6, " 3_6?"); - send_code(state,REP_3_6, state.ts.bl_tree); send_bits(state,count-3, 2); - - } else if (count <= 10) { - send_code(state,REPZ_3_10, state.ts.bl_tree); send_bits(state,count-3, 3); - - } else { - send_code(state,REPZ_11_138, state.ts.bl_tree); send_bits(state,count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -int build_bl_tree(TState &state) -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(state,(ct_data *)state.ts.dyn_ltree, state.ts.l_desc.max_code); - scan_tree(state,(ct_data *)state.ts.dyn_dtree, state.ts.d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(state,(tree_desc *)(&state.ts.bl_desc)); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - state.ts.opt_len += 3*(max_blindex+1) + 5+5+4; - Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -void send_all_trees(TState &state,int lcodes, int dcodes, int blcodes) -{ - int rank; /* index in bl_order */ - - Assert(state,lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert(state,lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Trace("\nbl counts: "); - send_bits(state,lcodes-257, 5); - /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */ - send_bits(state,dcodes-1, 5); - send_bits(state,blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Trace("\nbl code %2d ", bl_order[rank]); - send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3); - } - Trace("\nbl tree: sent %ld", state.bs.bits_sent); - - send_tree(state,(ct_data *)state.ts.dyn_ltree, lcodes-1); /* send the literal tree */ - Trace("\nlit tree: sent %ld", state.bs.bits_sent); - - send_tree(state,(ct_data *)state.ts.dyn_dtree, dcodes-1); /* send the distance tree */ - Trace("\ndist tree: sent %ld", state.bs.bits_sent); -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length (in bytes) for the file so far. - */ -ulg flush_block(TState &state,char *buf, ulg stored_len, int eof) -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex; /* index of last bit length code of non zero freq */ - - state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */ - - /* Check if the file is ascii or binary */ - if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state); - - /* Construct the literal and distance trees */ - build_tree(state,(tree_desc *)(&state.ts.l_desc)); - Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); - - build_tree(state,(tree_desc *)(&state.ts.d_desc)); - Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(state); - - /* Determine the best encoding. Compute first the block length in bytes */ - opt_lenb = (state.ts.opt_len+3+7)>>3; - static_lenb = (state.ts.static_len+3+7)>>3; - state.ts.input_len += stored_len; /* for debugging only */ - - Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", - opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len, - state.ts.last_lit, state.ts.last_dist); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - // Originally, zip allowed the file to be transformed from a compressed - // into a stored file in the case where compression failed, there - // was only one block, and it was allowed to change. I've removed this - // possibility since the code's cleaner if no changes are allowed. - //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L - // && state.ts.cmpr_len_bits == 0L && state.seekable) - //{ // && state.ts.file_method != NULL - // // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: - // Assert(state,buf!=NULL,"block vanished"); - // copy_block(state,buf, (unsigned)stored_len, 0); // without header - // state.ts.cmpr_bytelen = stored_len; - // Assert(state,false,"unimplemented *state.ts.file_method = STORE;"); - // //*state.ts.file_method = STORE; - //} - //else - if (stored_len+4 <= opt_lenb && buf != (char*)NULL) { - /* 4: two words for the lengths */ - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - send_bits(state,(STORED_BLOCK<<1)+eof, 3); /* send block type */ - state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4; - state.ts.cmpr_len_bits = 0L; - - copy_block(state,buf, (unsigned)stored_len, 1); /* with header */ - } - else if (static_lenb == opt_lenb) { - send_bits(state,(STATIC_TREES<<1)+eof, 3); - compress_block(state,(ct_data *)state.ts.static_ltree, (ct_data *)state.ts.static_dtree); - state.ts.cmpr_len_bits += 3 + state.ts.static_len; - state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; - state.ts.cmpr_len_bits &= 7L; - } - else { - send_bits(state,(DYN_TREES<<1)+eof, 3); - send_all_trees(state,state.ts.l_desc.max_code+1, state.ts.d_desc.max_code+1, max_blindex+1); - compress_block(state,(ct_data *)state.ts.dyn_ltree, (ct_data *)state.ts.dyn_dtree); - state.ts.cmpr_len_bits += 3 + state.ts.opt_len; - state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; - state.ts.cmpr_len_bits &= 7L; - } - Assert(state,((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size"); - init_block(state); - - if (eof) { - // Assert(state,input_len == isize, "bad input size"); - bi_windup(state); - state.ts.cmpr_len_bits += 7; /* align on byte boundary */ - } - Trace("\n"); - - return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int ct_tally (TState &state,int dist, int lc) -{ - state.ts.l_buf[state.ts.last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - state.ts.dyn_ltree[lc].fc.freq++; - } else { - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert(state,(ush)dist < (ush)MAX_DIST && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match"); - - state.ts.dyn_ltree[state.ts.length_code[lc]+LITERALS+1].fc.freq++; - state.ts.dyn_dtree[d_code(dist)].fc.freq++; - - state.ts.d_buf[state.ts.last_dist++] = (ush)dist; - state.ts.flags |= state.ts.flag_bit; - } - state.ts.flag_bit <<= 1; - - /* Output the flags if they fill a byte: */ - if ((state.ts.last_lit & 7) == 0) { - state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags; - state.ts.flags = 0, state.ts.flag_bit = 1; - } - /* Try to guess if it is profitable to stop the current block here */ - if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)state.ts.last_lit*8L; - ulg in_length = (ulg)state.ds.strstart-state.ds.block_start; - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq*(5L+extra_dbits[dcode]); - } - out_length >>= 3; - Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", - state.ts.last_lit, state.ts.last_dist, in_length, out_length, - 100L - out_length*100L/in_length); - if (state.ts.last_dist < state.ts.last_lit/2 && out_length < in_length/2) return 1; - } - return (state.ts.last_lit == LIT_BUFSIZE-1 || state.ts.last_dist == DIST_BUFSIZE); - /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -void compress_block(TState &state,ct_data *ltree, ct_data *dtree) -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned dx = 0; /* running index in d_buf */ - unsigned fx = 0; /* running index in flag_buf */ - uch flag = 0; /* current flags */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (state.ts.last_lit != 0) do { - if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++]; - lc = state.ts.l_buf[lx++]; - if ((flag & 1) == 0) { - send_code(state,lc, ltree); /* send a literal byte */ - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = state.ts.length_code[lc]; - send_code(state,code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= state.ts.base_length[code]; - send_bits(state,lc, extra); /* send the extra length bits */ - } - dist = state.ts.d_buf[dx++]; - /* Here, dist is the match distance - 1 */ - code = d_code(dist); - Assert(state,code < D_CODES, "bad d_code"); - - send_code(state,code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= state.ts.base_dist[code]; - send_bits(state,dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - flag >>= 1; - } while (lx < state.ts.last_lit); - - send_code(state,END_BLOCK, ltree); -} - -/* =========================================================================== - * Set the file type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -void set_file_type(TState &state) -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += state.ts.dyn_ltree[n++].fc.freq; - while (n < 128) ascii_freq += state.ts.dyn_ltree[n++].fc.freq; - while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq; - *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); -} - - -/* =========================================================================== - * Initialize the bit string routines. - */ -void bi_init (TState &state,char *tgt_buf, unsigned tgt_size, int flsh_allowed) -{ - state.bs.out_buf = tgt_buf; - state.bs.out_size = tgt_size; - state.bs.out_offset = 0; - state.bs.flush_flg = flsh_allowed; - - state.bs.bi_buf = 0; - state.bs.bi_valid = 0; - state.bs.bits_sent = 0L; -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -void send_bits(TState &state,int value, int length) -{ - Assert(state,length > 0 && length <= 15, "invalid length"); - state.bs.bits_sent += (ulg)length; - /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and - * (Buf_size - bi_valid) bits from value to flush the filled bi_buf, - * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid)) - * unused bits in bi_buf. - */ - state.bs.bi_buf |= (value << state.bs.bi_valid); - state.bs.bi_valid += length; - if (state.bs.bi_valid > (int)Buf_size) { - PUTSHORT(state,state.bs.bi_buf); - state.bs.bi_valid -= Buf_size; - state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid); - } -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -unsigned bi_reverse(unsigned code, int len) -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Write out any remaining bits in an incomplete byte. - */ -void bi_windup(TState &state) -{ - if (state.bs.bi_valid > 8) { - PUTSHORT(state,state.bs.bi_buf); - } else if (state.bs.bi_valid > 0) { - PUTBYTE(state,state.bs.bi_buf); - } - if (state.bs.flush_flg) { - state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); - } - state.bs.bi_buf = 0; - state.bs.bi_valid = 0; - state.bs.bits_sent = (state.bs.bits_sent+7) & ~7; -} - -/* =========================================================================== - * Copy a stored block to the zip file, storing first the length and its - * one's complement if requested. - */ -void copy_block(TState &state, char *block, unsigned len, int header) -{ - bi_windup(state); /* align on byte boundary */ - - if (header) { - PUTSHORT(state,(ush)len); - PUTSHORT(state,(ush)~len); - state.bs.bits_sent += 2*16; - } - if (state.bs.flush_flg) { - state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); - state.bs.out_offset = len; - state.flush_outbuf(state.param,block, &state.bs.out_offset); - } else if (state.bs.out_offset + len > state.bs.out_size) { - Assert(state,false,"output buffer too small for in-memory compression"); - } else { - memcpy(state.bs.out_buf + state.bs.out_offset, block, len); - state.bs.out_offset += len; - } - state.bs.bits_sent += (ulg)len<<3; -} - - - - - - - - -/* =========================================================================== - * Prototypes for functions. - */ - -void fill_window (TState &state); -ulg deflate_fast (TState &state); - -int longest_match (TState &state,IPos cur_match); - - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(h,c) (h = (((h)< 0 if the input file is already read or - * mmap'ed in the window[] array, 0 otherwise. In the first case, - * window_size is sufficient to contain the whole input file plus - * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end - * of window[] when looking for matches towards the end). - */ -void lm_init (TState &state, int pack_level, ush *flags) -{ - register unsigned j; - - Assert(state,pack_level>=1 && pack_level<=8,"bad pack level"); - - /* Do not slide the window if the whole input is already in memory - * (window_size > 0) - */ - state.ds.sliding = 0; - if (state.ds.window_size == 0L) { - state.ds.sliding = 1; - state.ds.window_size = (ulg)2L*WSIZE; - } - - /* Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ - state.ds.head[HASH_SIZE-1] = NIL; - memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*state.ds.head)); - - /* Set the default configuration parameters: - */ - state.ds.max_lazy_match = configuration_table[pack_level].max_lazy; - state.ds.good_match = configuration_table[pack_level].good_length; - state.ds.nice_match = configuration_table[pack_level].nice_length; - state.ds.max_chain_length = configuration_table[pack_level].max_chain; - if (pack_level <= 2) { - *flags |= FAST; - } else if (pack_level >= 8) { - *flags |= SLOW; - } - /* ??? reduce max_chain_length for binary files */ - - state.ds.strstart = 0; - state.ds.block_start = 0L; - - j = WSIZE; - j <<= 1; // Can read 64K in one step - state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j); - - if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) { - state.ds.eofile = 1, state.ds.lookahead = 0; - return; - } - state.ds.eofile = 0; - /* Make sure that we always have enough lookahead. This is important - * if input comes from a device such as a tty. - */ - if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); - - state.ds.ins_h = 0; - for (j=0; j= 1 - */ -// For 80x86 and 680x0 and ARM, an optimized version is in match.asm or -// match.S. The code is functionally equivalent, so you can use the C version -// if desired. Which I do so desire! -int longest_match(TState &state,IPos cur_match) -{ - unsigned chain_length = state.ds.max_chain_length; /* max hash chain length */ - register uch far *scan = state.ds.window + state.ds.strstart; /* current string */ - register uch far *match; /* matched string */ - register int len; /* length of current match */ - int best_len = state.ds.prev_length; /* best match length so far */ - IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - - // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - // It is easy to get rid of this optimization if necessary. - Assert(state,HASH_BITS>=8 && MAX_MATCH==258,"Code too clever"); - - - - register uch far *strend = state.ds.window + state.ds.strstart + MAX_MATCH; - register uch scan_end1 = scan[best_len-1]; - register uch scan_end = scan[best_len]; - - /* Do not waste too much time if we already have a good match: */ - if (state.ds.prev_length >= state.ds.good_match) { - chain_length >>= 2; - } - - Assert(state,state.ds.strstart <= state.ds.window_size-MIN_LOOKAHEAD, "insufficient lookahead"); - - do { - Assert(state,cur_match < state.ds.strstart, "no future"); - match = state.ds.window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(state,scan <= state.ds.window+(unsigned)(state.ds.window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - - - if (len > best_len) { - state.ds.match_start = cur_match; - best_len = len; - if (len >= state.ds.nice_match) break; - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; - } - } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit - && --chain_length != 0); - - return best_len; -} - - - -#define check_match(state,start, match, length) -// or alternatively... -//void check_match(TState &state,IPos start, IPos match, int length) -//{ // check that the match is indeed a match -// if (memcmp((char*)state.ds.window + match, -// (char*)state.ds.window + start, length) != EQUAL) { -// fprintf(stderr, -// " start %d, match %d, length %d\n", -// start, match, length); -// error("invalid match"); -// } -// if (state.verbose > 1) { -// fprintf(stderr,"\\[%d,%d]", start-match, length); -// do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0); -// } -//} - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead, and sets eofile if end of input file. - * - * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or eofile is set; file reads are - * performed for at least two bytes (required for the translate_eol option). - */ -void fill_window(TState &state) -{ - register unsigned n, m; - unsigned more; /* Amount of free space at the end of the window. */ - - do { - more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart); - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (more == (unsigned)EOF) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - - /* For MMAP or BIG_MEM, the whole input file is already in memory so - * we must not perform sliding. We must however call (*read_buf)() in - * order to compute the crc, update lookahead and possibly set eofile. - */ - } else if (state.ds.strstart >= WSIZE+MAX_DIST && state.ds.sliding) { - - /* By the IN assertion, the window is not empty so we can't confuse - * more == 0 with more == 64K on a 16 bit machine. - */ - memcpy((char*)state.ds.window, (char*)state.ds.window+WSIZE, (unsigned)WSIZE); - state.ds.match_start -= WSIZE; - state.ds.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ - - state.ds.block_start -= (long) WSIZE; - - for (n = 0; n < HASH_SIZE; n++) { - m = state.ds.head[n]; - state.ds.head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); - } - for (n = 0; n < WSIZE; n++) { - m = state.ds.prev[n]; - state.ds.prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } - more += WSIZE; - } - if (state.ds.eofile) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the MMAP or BIG_MEM case (not yet supported in gzip), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(state,more >= 2, "more < 2"); - - n = state.readfunc(state, (char*)state.ds.window+state.ds.strstart+state.ds.lookahead, more); - - if (n == 0 || n == (unsigned)EOF) { - state.ds.eofile = 1; - } else { - state.ds.lookahead += n; - } - } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK(state,eof) \ - flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \ - (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof)) - -/* =========================================================================== - * Processes a new input file and return its compressed length. This - * function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -ulg deflate_fast(TState &state) -{ - IPos hash_head = NIL; /* head of the hash chain */ - int flush; /* set if current block must be flushed */ - unsigned match_length = 0; /* length of best match */ - - state.ds.prev_length = MIN_MATCH-1; - while (state.ds.lookahead != 0) { - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (state.ds.lookahead >= MIN_MATCH) - INSERT_STRING(state.ds.strstart, hash_head); - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - /* Do not look for matches beyond the end of the input. - * This is necessary to make deflate deterministic. - */ - if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; - match_length = longest_match (state,hash_head); - /* longest_match() sets match_start */ - if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; - } - if (match_length >= MIN_MATCH) { - check_match(state,state.ds.strstart, state.ds.match_start, match_length); - - flush = ct_tally(state,state.ds.strstart-state.ds.match_start, match_length - MIN_MATCH); - - state.ds.lookahead -= match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (match_length <= state.ds.max_insert_length - && state.ds.lookahead >= MIN_MATCH) { - match_length--; /* string at strstart already in hash table */ - do { - state.ds.strstart++; - INSERT_STRING(state.ds.strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--match_length != 0); - state.ds.strstart++; - } else { - state.ds.strstart += match_length; - match_length = 0; - state.ds.ins_h = state.ds.window[state.ds.strstart]; - UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart+1]); - Assert(state,MIN_MATCH==3,"Call UPDATE_HASH() MIN_MATCH-3 more times"); - } - } else { - /* No match, output a literal byte */ - flush = ct_tally (state,0, state.ds.window[state.ds.strstart]); - state.ds.lookahead--; - state.ds.strstart++; - } - if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; - - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); - } - return FLUSH_BLOCK(state,1); /* eof */ -} - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -ulg deflate(TState &state) -{ - IPos hash_head = NIL; /* head of hash chain */ - IPos prev_match; /* previous match */ - int flush; /* set if current block must be flushed */ - int match_available = 0; /* set if previous match exists */ - register unsigned match_length = MIN_MATCH-1; /* length of best match */ - - if (state.level <= 3) return deflate_fast(state); /* optimized for speed */ - - /* Process the input block. */ - while (state.ds.lookahead != 0) { - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (state.ds.lookahead >= MIN_MATCH) - INSERT_STRING(state.ds.strstart, hash_head); - - /* Find the longest match, discarding those <= prev_length. - */ - state.ds.prev_length = match_length, prev_match = state.ds.match_start; - match_length = MIN_MATCH-1; - - if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match && - state.ds.strstart - hash_head <= MAX_DIST) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - /* Do not look for matches beyond the end of the input. - * This is necessary to make deflate deterministic. - */ - if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; - match_length = longest_match (state,hash_head); - /* longest_match() sets match_start */ - if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; - - /* Ignore a length 3 match if it is too distant: */ - if (match_length == MIN_MATCH && state.ds.strstart-state.ds.match_start > TOO_FAR){ - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) { - unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH; - check_match(state,state.ds.strstart-1, prev_match, state.ds.prev_length); - flush = ct_tally(state,state.ds.strstart-1-prev_match, state.ds.prev_length - MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. - */ - state.ds.lookahead -= state.ds.prev_length-1; - state.ds.prev_length -= 2; - do { - if (++state.ds.strstart <= max_insert) { - INSERT_STRING(state.ds.strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } - } while (--state.ds.prev_length != 0); - state.ds.strstart++; - match_available = 0; - match_length = MIN_MATCH-1; - - if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; - - } else if (match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - if (ct_tally (state,0, state.ds.window[state.ds.strstart-1])) { - FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; - } - state.ds.strstart++; - state.ds.lookahead--; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - match_available = 1; - state.ds.strstart++; - state.ds.lookahead--; - } -// Assert(state,strstart <= isize && lookahead <= isize, "a bit too far"); - - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); - } - if (match_available) ct_tally (state,0, state.ds.window[state.ds.strstart-1]); - - return FLUSH_BLOCK(state,1); /* eof */ -} - - - - - - - - - - - - -int putlocal(struct zlist far *z, WRITEFUNC wfunc,void *param) -{ // Write a local header described by *z to file *f. Return a ZE_ error code. - PUTLG(LOCSIG, f); - PUTSH(z->ver, f); - PUTSH(z->lflg, f); - PUTSH(z->how, f); - PUTLG(z->tim, f); - PUTLG(z->crc, f); - PUTLG(z->siz, f); - PUTLG(z->len, f); - PUTSH(z->nam, f); - PUTSH(z->ext, f); - size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam); - if (res!=z->nam) return ZE_TEMP; - if (z->ext) - { res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext); - if (res!=z->ext) return ZE_TEMP; - } - return ZE_OK; -} - -int putextended(struct zlist far *z, WRITEFUNC wfunc, void *param) -{ // Write an extended local header described by *z to file *f. Returns a ZE_ code - PUTLG(EXTLOCSIG, f); - PUTLG(z->crc, f); - PUTLG(z->siz, f); - PUTLG(z->len, f); - return ZE_OK; -} - -int putcentral(struct zlist far *z, WRITEFUNC wfunc, void *param) -{ // Write a central header entry of *z to file *f. Returns a ZE_ code. - PUTLG(CENSIG, f); - PUTSH(z->vem, f); - PUTSH(z->ver, f); - PUTSH(z->flg, f); - PUTSH(z->how, f); - PUTLG(z->tim, f); - PUTLG(z->crc, f); - PUTLG(z->siz, f); - PUTLG(z->len, f); - PUTSH(z->nam, f); - PUTSH(z->cext, f); - PUTSH(z->com, f); - PUTSH(z->dsk, f); - PUTSH(z->att, f); - PUTLG(z->atx, f); - PUTLG(z->off, f); - if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam || - (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) || - (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com)) - return ZE_TEMP; - return ZE_OK; -} - - -int putend(int n, ulg s, ulg c, extent m, char *z, WRITEFUNC wfunc, void *param) -{ // write the end of the central-directory-data to file *f. - PUTLG(ENDSIG, f); - PUTSH(0, f); - PUTSH(0, f); - PUTSH(n, f); - PUTSH(n, f); - PUTLG(s, f); - PUTLG(c, f); - PUTSH(m, f); - // Write the comment, if any - if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP; - return ZE_OK; -} - - - - - - -const ulg crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - -#define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) -#define DO1(buf) crc = CRC32(crc, *buf++) -#define DO2(buf) DO1(buf); DO1(buf) -#define DO4(buf) DO2(buf); DO2(buf) -#define DO8(buf) DO4(buf); DO4(buf) - -ulg crc32(ulg crc, const uch *buf, extent len) -{ if (buf==NULL) return 0L; - crc = crc ^ 0xffffffffL; - while (len >= 8) {DO8(buf); len -= 8;} - if (len) do {DO1(buf);} while (--len); - return crc ^ 0xffffffffL; // (instead of ~c for 64-bit machines) -} - - -void update_keys(unsigned long *keys, char c) -{ keys[0] = CRC32(keys[0],c); - keys[1] += keys[0] & 0xFF; - keys[1] = keys[1]*134775813L +1; - keys[2] = CRC32(keys[2], keys[1] >> 24); -} -char decrypt_byte(unsigned long *keys) -{ unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; - return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); -} -char zencode(unsigned long *keys, char c) -{ int t=decrypt_byte(keys); - update_keys(keys,c); - return (char)(t^c); -} - - - - - - - -bool HasZipSuffix(const TCHAR *fn) -{ const TCHAR *ext = fn+_tcslen(fn); - while (ext>fn && *ext!='.') ext--; - if (ext==fn && *ext!='.') return false; - if (_tcsicmp(ext,_T(".Z"))==0) return true; - if (_tcsicmp(ext,_T(".zip"))==0) return true; - if (_tcsicmp(ext,_T(".zoo"))==0) return true; - if (_tcsicmp(ext,_T(".arc"))==0) return true; - if (_tcsicmp(ext,_T(".lzh"))==0) return true; - if (_tcsicmp(ext,_T(".arj"))==0) return true; - if (_tcsicmp(ext,_T(".gz"))==0) return true; - if (_tcsicmp(ext,_T(".tgz"))==0) return true; - return false; -} - - -lutime_t filetime2timet(const FILETIME ft) -{ __int64 i = *(__int64*)&ft; - return (lutime_t)((i-116444736000000000)/10000000); -} - -void filetime2dosdatetime(const FILETIME ft, WORD *dosdate,WORD *dostime) -{ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 - // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 - SYSTEMTIME st; FileTimeToSystemTime(&ft,&st); - *dosdate = (WORD)(((st.wYear-1980)&0x7f) << 9); - *dosdate |= (WORD)((st.wMonth&0xf) << 5); - *dosdate |= (WORD)((st.wDay&0x1f)); - *dostime = (WORD)((st.wHour&0x1f) << 11); - *dostime |= (WORD)((st.wMinute&0x3f) << 5); - *dostime |= (WORD)((st.wSecond*2)&0x1f); -} - - -ZRESULT GetFileInfo(HANDLE hf, ulg *attr, long *size, iztimes *times, ulg *timestamp) -{ // The handle must be a handle to a file - // The date and time is returned in a long with the date most significant to allow - // unsigned integer comparison of absolute times. The attributes have two - // high bytes unix attr, and two low bytes a mapping of that to DOS attr. - //struct stat s; int res=stat(fn,&s); if (res!=0) return false; - // translate windows file attributes into zip ones. - BY_HANDLE_FILE_INFORMATION bhi; BOOL res=GetFileInformationByHandle(hf,&bhi); - if (!res) return ZR_NOFILE; - DWORD fa=bhi.dwFileAttributes; ulg a=0; - // Zip uses the lower word for its interpretation of windows stuff - if (fa&FILE_ATTRIBUTE_READONLY) a|=0x01; - if (fa&FILE_ATTRIBUTE_HIDDEN) a|=0x02; - if (fa&FILE_ATTRIBUTE_SYSTEM) a|=0x04; - if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x10; - if (fa&FILE_ATTRIBUTE_ARCHIVE) a|=0x20; - // It uses the upper word for standard unix attr, which we manually construct - if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x40000000; // directory - else a|=0x80000000; // normal file - a|=0x01000000; // readable - if (fa&FILE_ATTRIBUTE_READONLY) {} else a|=0x00800000; // writeable - // now just a small heuristic to check if it's an executable: - DWORD red, hsize=GetFileSize(hf,NULL); if (hsize>40) - { SetFilePointer(hf,0,NULL,FILE_BEGIN); unsigned short magic; ReadFile(hf,&magic,sizeof(magic),&red,NULL); - SetFilePointer(hf,36,NULL,FILE_BEGIN); unsigned long hpos; ReadFile(hf,&hpos,sizeof(hpos),&red,NULL); - if (magic==0x54AD && hsize>hpos+4+20+28) - { SetFilePointer(hf,hpos,NULL,FILE_BEGIN); unsigned long signature; ReadFile(hf,&signature,sizeof(signature),&red,NULL); - if (signature==IMAGE_DOS_SIGNATURE || signature==IMAGE_OS2_SIGNATURE - || signature==IMAGE_OS2_SIGNATURE_LE || signature==IMAGE_NT_SIGNATURE) - { a |= 0x00400000; // executable - } - } - } - // - if (attr!=NULL) *attr = a; - if (size!=NULL) *size = hsize; - if (times!=NULL) - { // lutime_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970. - // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601 - times->atime = filetime2timet(bhi.ftLastAccessTime); - times->mtime = filetime2timet(bhi.ftLastWriteTime); - times->ctime = filetime2timet(bhi.ftCreationTime); - } - if (timestamp!=NULL) - { WORD dosdate,dostime; - filetime2dosdatetime(bhi.ftLastWriteTime,&dosdate,&dostime); - *timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); - } - return ZR_OK; -} - - - - - - - - -class TZip -{ public: - TZip(const char *pwd) : hfout(0),mustclosehfout(false),hmapout(0),zfis(0),obuf(0),hfin(0),writ(0),oerr(false),hasputcen(false),ooffset(0),encwriting(false),encbuf(0),password(0), state(0) {if (pwd!=0 && *pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}} - ~TZip() {if (state!=0) delete state; state=0; if (encbuf!=0) delete[] encbuf; encbuf=0; if (password!=0) delete[] password; password=0;} - - // These variables say about the file we're writing into - // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile - char *password; // keep a copy of the password - HANDLE hfout; // if valid, we'll write here (for files or pipes) - bool mustclosehfout; // if true, we are responsible for closing hfout - HANDLE hmapout; // otherwise, we'll write here (for memmap) - unsigned ooffset; // for hfout, this is where the pointer was initially - ZRESULT oerr; // did a write operation give rise to an error? - unsigned writ; // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks - bool ocanseek; // can we seek? - char *obuf; // this is where we've locked mmap to view. - unsigned int opos; // current pos in the mmap - unsigned int mapsize; // the size of the map we created - bool hasputcen; // have we yet placed the central directory? - bool encwriting; // if true, then we'll encrypt stuff using 'keys' before we write it to disk - unsigned long keys[3]; // keys are initialised inside Add() - char *encbuf; // if encrypting, then this is a temporary workspace for encrypting the data - unsigned int encbufsize; // (to be used and resized inside write(), and deleted in the destructor) - // - TZipFileInfo *zfis; // each file gets added onto this list, for writing the table at the end - TState *state; // we use just one state object per zip, because it's big (500k) - - ZRESULT Create(void *z,unsigned int len,DWORD flags); - static unsigned sflush(void *param,const char *buf, unsigned *size); - static unsigned swrite(void *param,const char *buf, unsigned size); - unsigned int write(const char *buf,unsigned int size); - bool oseek(unsigned int pos); - ZRESULT GetMemory(void **pbuf, unsigned long *plen); - ZRESULT Close(); - - // some variables to do with the file currently being read: - // I haven't done it object-orientedly here, just put them all - // together, since OO didn't seem to make the design any clearer. - ulg attr; iztimes times; ulg timestamp; // all open_* methods set these - bool iseekable; long isize,ired; // size is not set until close() on pips - ulg crc; // crc is not set until close(). iwrit is cumulative - HANDLE hfin; bool selfclosehf; // for input files and pipes - const char *bufin; unsigned int lenin,posin; // for memory - // and a variable for what we've done with the input: (i.e. compressed it!) - ulg csize; // compressed size, set by the compression routines - // and this is used by some of the compression routines - char buf[16384]; - - - ZRESULT open_file(const TCHAR *fn); - ZRESULT open_handle(HANDLE hf,unsigned int len); - ZRESULT open_mem(void *src,unsigned int len); - ZRESULT open_dir(); - static unsigned sread(TState &s,char *buf,unsigned size); - unsigned read(char *buf, unsigned size); - ZRESULT iclose(); - - ZRESULT ideflate(TZipFileInfo *zfi); - ZRESULT istore(); - - ZRESULT Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags); - ZRESULT AddCentral(); - -}; - - - -ZRESULT TZip::Create(void *z,unsigned int len,DWORD flags) -{ if (hfout!=0 || hmapout!=0 || obuf!=0 || writ!=0 || oerr!=ZR_OK || hasputcen) return ZR_NOTINITED; - // - if (flags==ZIP_HANDLE) - { HANDLE hf = (HANDLE)z; - hfout=hf; mustclosehfout=false; -#ifdef DuplicateHandle - BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&hfout,0,FALSE,DUPLICATE_SAME_ACCESS); - if (res) mustclosehandle=true; -#endif - // now we have hfout. Either we duplicated the handle and we close it ourselves - // (while the caller closes h themselves), or we couldn't duplicate it. - DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT); - ocanseek = (res!=0xFFFFFFFF); - if (ocanseek) ooffset=res; else ooffset=0; - return ZR_OK; - } - else if (flags==ZIP_FILENAME) - { const TCHAR *fn = (const TCHAR*)z; - hfout = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if (hfout==INVALID_HANDLE_VALUE) {hfout=0; return ZR_NOFILE;} - ocanseek=true; - ooffset=0; - mustclosehfout=true; - return ZR_OK; - } - else if (flags==ZIP_MEMORY) - { unsigned int size = len; - if (size==0) return ZR_MEMSIZE; - if (z!=0) obuf=(char*)z; - else - { hmapout = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,NULL); - if (hmapout==NULL) return ZR_NOALLOC; - obuf = (char*)MapViewOfFile(hmapout,FILE_MAP_ALL_ACCESS,0,0,size); - if (obuf==0) {CloseHandle(hmapout); hmapout=0; return ZR_NOALLOC;} - } - ocanseek=true; - opos=0; mapsize=size; - return ZR_OK; - } - else return ZR_ARGS; -} - -unsigned TZip::sflush(void *param,const char *buf, unsigned *size) -{ // static - if (*size==0) return 0; - TZip *zip = (TZip*)param; - unsigned int writ = zip->write(buf,*size); - if (writ!=0) *size=0; - return writ; -} -unsigned TZip::swrite(void *param,const char *buf, unsigned size) -{ // static - if (size==0) return 0; - TZip *zip=(TZip*)param; return zip->write(buf,size); -} -unsigned int TZip::write(const char *buf,unsigned int size) -{ const char *srcbuf=buf; - if (encwriting) - { if (encbuf!=0 && encbufsize=mapsize) {oerr=ZR_MEMSIZE; return 0;} - memcpy(obuf+opos, srcbuf, size); - opos+=size; - return size; - } - else if (hfout!=0) - { DWORD writ; WriteFile(hfout,srcbuf,size,&writ,NULL); - return writ; - } - oerr=ZR_NOTINITED; return 0; -} - -bool TZip::oseek(unsigned int pos) -{ if (!ocanseek) {oerr=ZR_SEEK; return false;} - if (obuf!=0) - { if (pos>=mapsize) {oerr=ZR_MEMSIZE; return false;} - opos=pos; - return true; - } - else if (hfout!=0) - { SetFilePointer(hfout,pos+ooffset,NULL,FILE_BEGIN); - return true; - } - oerr=ZR_NOTINITED; return 0; -} - -ZRESULT TZip::GetMemory(void **pbuf, unsigned long *plen) -{ // When the user calls GetMemory, they're presumably at the end - // of all their adding. In any case, we have to add the central - // directory now, otherwise the memory we tell them won't be complete. - if (!hasputcen) AddCentral(); hasputcen=true; - if (pbuf!=NULL) *pbuf=(void*)obuf; - if (plen!=NULL) *plen=writ; - if (obuf==NULL) return ZR_NOTMMAP; - return ZR_OK; -} - -ZRESULT TZip::Close() -{ // if the directory hadn't already been added through a call to GetMemory, - // then we do it now - ZRESULT res=ZR_OK; if (!hasputcen) res=AddCentral(); hasputcen=true; - if (obuf!=0 && hmapout!=0) UnmapViewOfFile(obuf); obuf=0; - if (hmapout!=0) CloseHandle(hmapout); hmapout=0; - if (hfout!=0 && mustclosehfout) CloseHandle(hfout); hfout=0; mustclosehfout=false; - return res; -} - - - - -ZRESULT TZip::open_file(const TCHAR *fn) -{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; - if (fn==0) return ZR_ARGS; - HANDLE hf = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); - if (hf==INVALID_HANDLE_VALUE) return ZR_NOFILE; - ZRESULT res = open_handle(hf,0); - if (res!=ZR_OK) {CloseHandle(hf); return res;} - selfclosehf=true; - return ZR_OK; -} -ZRESULT TZip::open_handle(HANDLE hf,unsigned int len) -{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; - if (hf==0 || hf==INVALID_HANDLE_VALUE) return ZR_ARGS; - DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT); - if (res!=0xFFFFFFFF) - { ZRESULT res = GetFileInfo(hf,&attr,&isize,×,×tamp); - if (res!=ZR_OK) return res; - SetFilePointer(hf,0,NULL,FILE_BEGIN); // because GetFileInfo will have screwed it up - iseekable=true; hfin=hf; - return ZR_OK; - } - else - { attr= 0x80000000; // just a normal file - isize = -1; // can't know size until at the end - if (len!=0) isize=len; // unless we were told explicitly! - iseekable=false; - SYSTEMTIME st; GetLocalTime(&st); - FILETIME ft; SystemTimeToFileTime(&st,&ft); - WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime); - times.atime = filetime2timet(ft); - times.mtime = times.atime; - times.ctime = times.atime; - timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); - hfin=hf; - return ZR_OK; - } -} -ZRESULT TZip::open_mem(void *src,unsigned int len) -{ hfin=0; bufin=(const char*)src; selfclosehf=false; crc=CRCVAL_INITIAL; ired=0; csize=0; ired=0; - lenin=len; posin=0; - if (src==0 || len==0) return ZR_ARGS; - attr= 0x80000000; // just a normal file - isize = len; - iseekable=true; - SYSTEMTIME st; GetLocalTime(&st); - FILETIME ft; SystemTimeToFileTime(&st,&ft); - WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime); - times.atime = filetime2timet(ft); - times.mtime = times.atime; - times.ctime = times.atime; - timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); - return ZR_OK; -} -ZRESULT TZip::open_dir() -{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; - attr= 0x41C00010; // a readable writable directory, and again directory - isize = 0; - iseekable=false; - SYSTEMTIME st; GetLocalTime(&st); - FILETIME ft; SystemTimeToFileTime(&st,&ft); - WORD dosdate,dostime; filetime2dosdatetime(ft,&dosdate,&dostime); - times.atime = filetime2timet(ft); - times.mtime = times.atime; - times.ctime = times.atime; - timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); - return ZR_OK; -} - -unsigned TZip::sread(TState &s,char *buf,unsigned size) -{ // static - TZip *zip = (TZip*)s.param; - return zip->read(buf,size); -} - -unsigned TZip::read(char *buf, unsigned size) -{ if (bufin!=0) - { if (posin>=lenin) return 0; // end of input - ulg red = lenin-posin; - if (red>size) red=size; - memcpy(buf, bufin+posin, red); - posin += red; - ired += red; - crc = crc32(crc, (uch*)buf, red); - return red; - } - else if (hfin!=0) - { DWORD red; - BOOL ok = ReadFile(hfin,buf,size,&red,NULL); - if (!ok) return 0; - ired += red; - crc = crc32(crc, (uch*)buf, red); - return red; - } - else {oerr=ZR_NOTINITED; return 0;} -} - -ZRESULT TZip::iclose() -{ if (selfclosehf && hfin!=0) CloseHandle(hfin); hfin=0; - bool mismatch = (isize!=-1 && isize!=ired); - isize=ired; // and crc has been being updated anyway - if (mismatch) return ZR_MISSIZE; - else return ZR_OK; -} - - - -ZRESULT TZip::ideflate(TZipFileInfo *zfi) -{ if (state==0) state=new TState(); - // It's a very big object! 500k! We allocate it on the heap, because PocketPC's - // stack breaks if we try to put it all on the stack. It will be deleted lazily - state->err=0; - state->readfunc=sread; state->flush_outbuf=sflush; - state->param=this; state->level=8; state->seekable=iseekable; state->err=NULL; - // the following line will make ct_init realise it has to perform the init - state->ts.static_dtree[0].dl.len = 0; - // Thanks to Alvin77 for this crucial fix: - state->ds.window_size=0; - // I think that covers everything that needs to be initted. - // - bi_init(*state,buf, sizeof(buf), TRUE); // it used to be just 1024-size, not 16384 as here - ct_init(*state,&zfi->att); - lm_init(*state,state->level, &zfi->flg); - ulg sz = deflate(*state); - csize=sz; - ZRESULT r=ZR_OK; if (state->err!=NULL) r=ZR_FLATE; - return r; -} - -ZRESULT TZip::istore() -{ ulg size=0; - for (;;) - { unsigned int cin=read(buf,16384); if (cin<=0 || cin==(unsigned int)EOF) break; - unsigned int cout = write(buf,cin); if (cout!=cin) return ZR_MISSIZE; - size += cin; - } - csize=size; - return ZR_OK; -} - - - - - -bool has_seeded=false; -ZRESULT TZip::Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags) -{ if (oerr) return ZR_FAILED; - if (hasputcen) return ZR_ENDED; - - // if we use password encryption, then every isize and csize is 12 bytes bigger - int passex=0; if (password!=0 && flags!=ZIP_FOLDER) passex=12; - - // zip has its own notion of what its names should look like: i.e. dir/file.stuff - TCHAR dstzn[MAX_PATH]; _tcscpy(dstzn,odstzn); - if (*dstzn==0) return ZR_ARGS; - TCHAR *d=dstzn; while (*d!=0) {if (*d=='\\') *d='/'; d++;} - bool isdir = (flags==ZIP_FOLDER); - bool needs_trailing_slash = (isdir && dstzn[_tcslen(dstzn)-1]!='/'); - int method=DEFLATE; if (isdir || HasZipSuffix(dstzn)) method=STORE; - - // now open whatever was our input source: - ZRESULT openres; - if (flags==ZIP_FILENAME) openres=open_file((const TCHAR*)src); - else if (flags==ZIP_HANDLE) openres=open_handle((HANDLE)src,len); - else if (flags==ZIP_MEMORY) openres=open_mem(src,len); - else if (flags==ZIP_FOLDER) openres=open_dir(); - else return ZR_ARGS; - if (openres!=ZR_OK) return openres; - - // A zip "entry" consists of a local header (which includes the file name), - // then the compressed data, and possibly an extended local header. - - // Initialize the local header - TZipFileInfo zfi; zfi.nxt=NULL; - strcpy(zfi.name,""); -#ifdef UNICODE - WideCharToMultiByte(CP_UTF8,0,dstzn,-1,zfi.iname,MAX_PATH,0,0); -#else - strcpy(zfi.iname,dstzn); -#endif - zfi.nam=strlen(zfi.iname); - if (needs_trailing_slash) {strcat(zfi.iname,"/"); zfi.nam++;} - strcpy(zfi.zname,""); - zfi.extra=NULL; zfi.ext=0; // extra header to go after this compressed data, and its length - zfi.cextra=NULL; zfi.cext=0; // extra header to go in the central end-of-zip directory, and its length - zfi.comment=NULL; zfi.com=0; // comment, and its length - zfi.mark = 1; - zfi.dosflag = 0; - zfi.att = (ush)BINARY; - zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3 - zfi.ver = (ush)20; // Needs PKUNZIP 2.0 to unzip it - zfi.tim = timestamp; - // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. - zfi.crc = 0; // to be updated later - zfi.flg = 8; // 8 means 'there is an extra header'. Assume for the moment that we need it. - if (password!=0 && !isdir) zfi.flg=9; // and 1 means 'password-encrypted' - zfi.lflg = zfi.flg; // to be updated later - zfi.how = (ush)method; // to be updated later - zfi.siz = (ulg)(method==STORE && isize>=0 ? isize+passex : 0); // to be updated later - zfi.len = (ulg)(isize); // to be updated later - zfi.dsk = 0; - zfi.atx = attr; - zfi.off = writ+ooffset; // offset within file of the start of this local record - // stuff the 'times' structure into zfi.extra - - // nb. apparently there's a problem with PocketPC CE(zip)->CE(unzip) fails. And removing the following block fixes it up. - char xloc[EB_L_UT_SIZE]; zfi.extra=xloc; zfi.ext=EB_L_UT_SIZE; - char xcen[EB_C_UT_SIZE]; zfi.cextra=xcen; zfi.cext=EB_C_UT_SIZE; - xloc[0] = 'U'; - xloc[1] = 'T'; - xloc[2] = EB_UT_LEN(3); // length of data part of e.f. - xloc[3] = 0; - xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME; - xloc[5] = (char)(times.mtime); - xloc[6] = (char)(times.mtime >> 8); - xloc[7] = (char)(times.mtime >> 16); - xloc[8] = (char)(times.mtime >> 24); - xloc[9] = (char)(times.atime); - xloc[10] = (char)(times.atime >> 8); - xloc[11] = (char)(times.atime >> 16); - xloc[12] = (char)(times.atime >> 24); - xloc[13] = (char)(times.ctime); - xloc[14] = (char)(times.ctime >> 8); - xloc[15] = (char)(times.ctime >> 16); - xloc[16] = (char)(times.ctime >> 24); - memcpy(zfi.cextra,zfi.extra,EB_C_UT_SIZE); - zfi.cextra[EB_LEN] = EB_UT_LEN(1); - - - // (1) Start by writing the local header: - int r = putlocal(&zfi,swrite,this); - if (r!=ZE_OK) {iclose(); return ZR_WRITE;} - writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext; - if (oerr!=ZR_OK) {iclose(); return oerr;} - - // (1.5) if necessary, write the encryption header - keys[0]=305419896L; - keys[1]=591751049L; - keys[2]=878082192L; - for (const char *cp=password; cp!=0 && *cp!=0; cp++) update_keys(keys,*cp); - // generate some random bytes - if (!has_seeded) srand(GetTickCount()^(unsigned long)GetDesktopWindow()); - char encbuf[12]; for (int i=0; i<12; i++) encbuf[i]=(char)((rand()>>7)&0xff); - encbuf[11] = (char)((zfi.tim>>8)&0xff); - for (int ei=0; ei<12; ei++) encbuf[ei]=zencode(keys,encbuf[ei]); - if (password!=0 && !isdir) {swrite(this,encbuf,12); writ+=12;} - - //(2) Write deflated/stored file to zip file - ZRESULT writeres=ZR_OK; - encwriting = (password!=0 && !isdir); // an object member variable to say whether we write to disk encrypted - if (!isdir && method==DEFLATE) writeres=ideflate(&zfi); - else if (!isdir && method==STORE) writeres=istore(); - else if (isdir) csize=0; - encwriting = false; - iclose(); - writ += csize; - if (oerr!=ZR_OK) return oerr; - if (writeres!=ZR_OK) return ZR_WRITE; - - // (3) Either rewrite the local header with correct information... - bool first_header_has_size_right = (zfi.siz==csize+passex); - zfi.crc = crc; - zfi.siz = csize+passex; - zfi.len = isize; - if (ocanseek && (password==0 || isdir)) - { zfi.how = (ush)method; - if ((zfi.flg & 1) == 0) zfi.flg &= ~8; // clear the extended local header flag - zfi.lflg = zfi.flg; - // rewrite the local header: - if (!oseek(zfi.off-ooffset)) return ZR_SEEK; - if ((r = putlocal(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE; - if (!oseek(writ)) return ZR_SEEK; - } - else - { // (4) ... or put an updated header at the end - if (zfi.how != (ush) method) return ZR_NOCHANGE; - if (method==STORE && !first_header_has_size_right) return ZR_NOCHANGE; - if ((r = putextended(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE; - writ += 16L; - zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index - } - if (oerr!=ZR_OK) return oerr; - - // Keep a copy of the zipfileinfo, for our end-of-zip directory - char *cextra = new char[zfi.cext]; memcpy(cextra,zfi.cextra,zfi.cext); zfi.cextra=cextra; - TZipFileInfo *pzfi = new TZipFileInfo; memcpy(pzfi,&zfi,sizeof(zfi)); - if (zfis==NULL) zfis=pzfi; - else {TZipFileInfo *z=zfis; while (z->nxt!=NULL) z=z->nxt; z->nxt=pzfi;} - return ZR_OK; -} - -ZRESULT TZip::AddCentral() -{ // write central directory - int numentries = 0; - ulg pos_at_start_of_central = writ; - //ulg tot_unc_size=0, tot_compressed_size=0; - bool okay=true; - for (TZipFileInfo *zfi=zfis; zfi!=NULL; ) - { if (okay) - { int res = putcentral(zfi, swrite,this); - if (res!=ZE_OK) okay=false; - } - writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com; - //tot_unc_size += zfi->len; - //tot_compressed_size += zfi->siz; - numentries++; - // - TZipFileInfo *zfinext = zfi->nxt; - if (zfi->cextra!=0) delete[] zfi->cextra; - delete zfi; - zfi = zfinext; - } - ulg center_size = writ - pos_at_start_of_central; - if (okay) - { int res = putend(numentries, center_size, pos_at_start_of_central+ooffset, 0, NULL, swrite,this); - if (res!=ZE_OK) okay=false; - writ += 4 + ENDHEAD + 0; - } - if (!okay) return ZR_WRITE; - return ZR_OK; -} - - - - - -ZRESULT lasterrorZ=ZR_OK; - -unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len) -{ if (code==ZR_RECENT) code=lasterrorZ; - const char *msg="unknown zip result code"; - switch (code) - { case ZR_OK: msg="Success"; break; - case ZR_NODUPH: msg="Culdn't duplicate handle"; break; - case ZR_NOFILE: msg="Couldn't create/open file"; break; - case ZR_NOALLOC: msg="Failed to allocate memory"; break; - case ZR_WRITE: msg="Error writing to file"; break; - case ZR_NOTFOUND: msg="File not found in the zipfile"; break; - case ZR_MORE: msg="Still more data to unzip"; break; - case ZR_CORRUPT: msg="Zipfile is corrupt or not a zipfile"; break; - case ZR_READ: msg="Error reading file"; break; - case ZR_ARGS: msg="Caller: faulty arguments"; break; - case ZR_PARTIALUNZ: msg="Caller: the file had already been partially unzipped"; break; - case ZR_NOTMMAP: msg="Caller: can only get memory of a memory zipfile"; break; - case ZR_MEMSIZE: msg="Caller: not enough space allocated for memory zipfile"; break; - case ZR_FAILED: msg="Caller: there was a previous error"; break; - case ZR_ENDED: msg="Caller: additions to the zip have already been ended"; break; - case ZR_ZMODE: msg="Caller: mixing creation and opening of zip"; break; - case ZR_NOTINITED: msg="Zip-bug: internal initialisation not completed"; break; - case ZR_SEEK: msg="Zip-bug: trying to seek the unseekable"; break; - case ZR_MISSIZE: msg="Zip-bug: the anticipated size turned out wrong"; break; - case ZR_NOCHANGE: msg="Zip-bug: tried to change mind, but not allowed"; break; - case ZR_FLATE: msg="Zip-bug: an internal error during flation"; break; - } - unsigned int mlen=(unsigned int)strlen(msg); - if (buf==0 || len==0) return mlen; - unsigned int n=mlen; if (n+1>len) n=len-1; - strncpy(buf,msg,n); buf[n]=0; - return mlen; -} - - - -typedef struct -{ DWORD flag; - TZip *zip; -} TZipHandleData; - - -HZIP CreateZipInternal(void *z,unsigned int len,DWORD flags, const char *password) -{ TZip *zip = new TZip(password); - lasterrorZ = zip->Create(z,len,flags); - if (lasterrorZ!=ZR_OK) {delete zip; return 0;} - TZipHandleData *han = new TZipHandleData; - han->flag=2; han->zip=zip; return (HZIP)han; -} -HZIP CreateZipHandle(HANDLE h, const char *password) {return CreateZipInternal(h,0,ZIP_HANDLE,password);} -HZIP CreateZip(const TCHAR *fn, const char *password) {return CreateZipInternal((void*)fn,0,ZIP_FILENAME,password);} -HZIP CreateZip(void *z,unsigned int len, const char *password) {return CreateZipInternal(z,len,ZIP_MEMORY,password);} - - -ZRESULT ZipAddInternal(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len, DWORD flags) -{ if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} - TZipHandleData *han = (TZipHandleData*)hz; - if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} - TZip *zip = han->zip; - lasterrorZ = zip->Add(dstzn,src,len,flags); - return lasterrorZ; -} -ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn) {return ZipAddInternal(hz,dstzn,(void*)fn,0,ZIP_FILENAME);} -ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len) {return ZipAddInternal(hz,dstzn,src,len,ZIP_MEMORY);} -ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h) {return ZipAddInternal(hz,dstzn,h,0,ZIP_HANDLE);} -ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len) {return ZipAddInternal(hz,dstzn,h,len,ZIP_HANDLE);} -ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn) {return ZipAddInternal(hz,dstzn,0,0,ZIP_FOLDER);} - - - -ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len) -{ if (hz==0) {if (buf!=0) *buf=0; if (len!=0) *len=0; lasterrorZ=ZR_ARGS;return ZR_ARGS;} - TZipHandleData *han = (TZipHandleData*)hz; - if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} - TZip *zip = han->zip; - lasterrorZ = zip->GetMemory(buf,len); - return lasterrorZ; -} - -ZRESULT CloseZipZ(HZIP hz) -{ if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} - TZipHandleData *han = (TZipHandleData*)hz; - if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} - TZip *zip = han->zip; - lasterrorZ = zip->Close(); - delete zip; - delete han; - return lasterrorZ; -} - -bool IsZipHandleZ(HZIP hz) -{ if (hz==0) return false; - TZipHandleData *han = (TZipHandleData*)hz; - return (han->flag==2); -} - diff --git a/CocXlsxTool/zip.h b/CocXlsxTool/zip.h deleted file mode 100644 index 083895ec..00000000 --- a/CocXlsxTool/zip.h +++ /dev/null @@ -1,203 +0,0 @@ -#ifndef _zip_H -#define _zip_H - - -// ZIP functions -- for creating zip files -// This file is a repackaged form of the Info-Zip source code available -// at www.info-zip.org. The original copyright notice may be found in -// zip.cpp. The repackaging was done by Lucian Wischik to simplify and -// extend its use in Windows/C++. Also to add encryption and unicode. - - -#ifndef _unzip_H -DECLARE_HANDLE(HZIP); -#endif -// An HZIP identifies a zip file that is being created - -typedef DWORD ZRESULT; -// return codes from any of the zip functions. Listed later. - - - -HZIP CreateZip(const TCHAR *fn, const char *password); -HZIP CreateZip(void *buf,unsigned int len, const char *password); -HZIP CreateZipHandle(HANDLE h, const char *password); -// CreateZip - call this to start the creation of a zip file. -// As the zip is being created, it will be stored somewhere: -// to a pipe: CreateZipHandle(hpipe_write); -// in a file (by handle): CreateZipHandle(hfile); -// in a file (by name): CreateZip("c:\\test.zip"); -// in memory: CreateZip(buf, len); -// or in pagefile memory: CreateZip(0, len); -// The final case stores it in memory backed by the system paging file, -// where the zip may not exceed len bytes. This is a bit friendlier than -// allocating memory with new[]: it won't lead to fragmentation, and the -// memory won't be touched unless needed. That means you can give very -// large estimates of the maximum-size without too much worry. -// As for the password, it lets you encrypt every file in the archive. -// (This api doesn't support per-file encryption.) -// Note: because pipes don't allow random access, the structure of a zipfile -// created into a pipe is slightly different from that created into a file -// or memory. In particular, the compressed-size of the item cannot be -// stored in the zipfile until after the item itself. (Also, for an item added -// itself via a pipe, the uncompressed-size might not either be known until -// after.) This is not normally a problem. But if you try to unzip via a pipe -// as well, then the unzipper will not know these things about the item until -// after it has been unzipped. Therefore: for unzippers which don't just write -// each item to disk or to a pipe, but instead pre-allocate memory space into -// which to unzip them, then either you have to create the zip not to a pipe, -// or you have to add items not from a pipe, or at least when adding items -// from a pipe you have to specify the length. -// Note: for windows-ce, you cannot close the handle until after CloseZip. -// but for real windows, the zip makes its own copy of your handle, so you -// can close yours anytime. - - -ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn); -ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len); -ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h); -ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len); -ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn); -// ZipAdd - call this for each file to be added to the zip. -// dstzn is the name that the file will be stored as in the zip file. -// The file to be added to the zip can come -// from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read); -// from a file: ZipAddHandle(hz,"file.dat", hfile); -// from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat"); -// from memory: ZipAdd(hz,"subdir\\file.dat", buf,len); -// (folder): ZipAddFolder(hz,"subdir"); -// Note: if adding an item from a pipe, and if also creating the zip file itself -// to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle -// function. This will let the zipfile store the item's size ahead of the -// compressed item itself, which in turn makes it easier when unzipping the -// zipfile from a pipe. - -ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len); -// ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len), -// then this function will return information about that memory block. -// buf will receive a pointer to its start, and len its length. -// Note: you can't add any more after calling this. - -ZRESULT CloseZip(HZIP hz); -// CloseZip - the zip handle must be closed with this function. - -unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); -// FormatZipMessage - given an error code, formats it as a string. -// It returns the length of the error message. If buf/len points -// to a real buffer, then it also writes as much as possible into there. - - - -// These are the result codes: -#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, -#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. -// The following come from general system stuff (e.g. files not openable) -#define ZR_GENMASK 0x0000FF00 -#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle -#define ZR_NOFILE 0x00000200 // couldn't create/open the file -#define ZR_NOALLOC 0x00000300 // failed to allocate some resource -#define ZR_WRITE 0x00000400 // a general error writing to the file -#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip -#define ZR_MORE 0x00000600 // there's still more data to be unzipped -#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile -#define ZR_READ 0x00000800 // a general error reading the file -// The following come from mistakes on the part of the caller -#define ZR_CALLERMASK 0x00FF0000 -#define ZR_ARGS 0x00010000 // general mistake with the arguments -#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't -#define ZR_MEMSIZE 0x00030000 // the memory size is too small -#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function -#define ZR_ENDED 0x00050000 // the zip creation has already been closed -#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken -#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped -#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip -// The following come from bugs within the zip library itself -#define ZR_BUGMASK 0xFF000000 -#define ZR_NOTINITED 0x01000000 // initialisation didn't work -#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file -#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed -#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code - - - - - - -// e.g. -// -// (1) Traditional use, creating a zipfile from existing files -// HZIP hz = CreateZip("c:\\simple1.zip",0); -// ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp"); -// ZipAdd(hz,"znsimple.txt", "c:\\simple.txt"); -// CloseZip(hz); -// -// (2) Memory use, creating an auto-allocated mem-based zip file from various sources -// HZIP hz = CreateZip(0,100000, 0); -// // adding a conventional file... -// ZipAdd(hz,"src1.txt", "c:\\src1.txt"); -// // adding something from memory... -// char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F); -// ZipAdd(hz,"file.dat", buf,1000); -// // adding something from a pipe... -// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0); -// HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0); -// ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional. -// WaitForSingleObject(hthread,INFINITE); -// CloseHandle(hthread); CloseHandle(hread); -// ... meanwhile DWORD WINAPI ThreadFunc(void *dat) -// { HANDLE hwrite = (HANDLE)dat; -// char buf[1000]={17}; -// DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL); -// CloseHandle(hwrite); -// return 0; -// } -// // and now that the zip is created, let's do something with it: -// void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen); -// HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); -// DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL); -// CloseHandle(hfz); -// CloseZip(hz); -// -// (3) Handle use, for file handles and pipes -// HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0); -// HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0); -// HZIP hz = CreateZipHandle(hzwrite,0); -// // ... add to it -// CloseZip(hz); -// CloseHandle(hzwrite); -// WaitForSingleObject(hthread,INFINITE); -// CloseHandle(hthread); -// ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat) -// { HANDLE hread = (HANDLE)dat; -// char buf[1000]; -// while (true) -// { DWORD red; ReadFile(hread,buf,1000,&red,NULL); -// // ... and do something with this zip data we're receiving -// if (red==0) break; -// } -// CloseHandle(hread); -// return 0; -// } - - - -// Now we indulge in a little skullduggery so that the code works whether -// the user has included just zip or both zip and unzip. -// Idea: if header files for both zip and unzip are present, then presumably -// the cpp files for zip and unzip are both present, so we will call -// one or the other of them based on a dynamic choice. If the header file -// for only one is present, then we will bind to that particular one. -ZRESULT CloseZipZ(HZIP hz); -unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len); -bool IsZipHandleZ(HZIP hz); -#ifdef _unzip_H -#undef CloseZip -#define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz)) -#else -#define CloseZip CloseZipZ -#define FormatZipMessage FormatZipMessageZ -#endif - - - -#endif From 75584ab4a5396d483b4b119b61b553ff78f8b5ed Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 22:59:52 +0800 Subject: [PATCH 16/33] =?UTF-8?q?=E5=A2=9E=E8=AE=BE=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=8F=B0=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/Dice.cpp | 23 ++++++++------ Dice/DiceConsole.cpp | 43 +++++++++++++------------- Dice/DiceConsole.h | 12 ++------ Dice/DiceEvent.h | 72 +++++++++++++++++++++++++------------------- 4 files changed, 78 insertions(+), 72 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index 3ebe31d9..a7767e8d 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -93,7 +93,7 @@ void dataBackUp() { //备份MasterQQ if (!boolStandByMe) { ofstream ofstreamMaster(strFileLoc + "Master.RDconf", ios::out | ios::trunc); - ofstreamMaster << masterQQ << std::endl << boolMasterMode << std::endl << boolDisabledGlobal << std::endl << boolDisabledMeGlobal << std::endl << boolPreserve << std::endl << boolDisabledJrrpGlobal << std::endl << boolNoDiscuss << std::endl; + ofstreamMaster << masterQQ << std::endl << boolMasterMode << std::endl << boolConsole["DisabledGlobal"] << std::endl << boolConsole["DisabledMe"] << std::endl << boolConsole["Private"] << std::endl << boolConsole["DisabledJrrp"] << std::endl << boolConsole["LeaveDiscuss"] << std::endl; ofstreamMaster << ClockToWork.first << " " << ClockToWork.second << endl << ClockOffWork.first << " " << ClockOffWork.second << endl; ofstreamMaster.close(); @@ -110,6 +110,7 @@ void dataBackUp() { if (it.first)ofstreamMonitorList << it.first << " " << it.second << std::endl; } ofstreamMonitorList.close(); + saveJMap(strFileLoc + "boolConsole.json", boolConsole); //备份个性化语句 ofstream ofstreamPersonalMsg(strFileLoc + "PersonalMsg.RDconf", ios::out | ios::trunc); for (auto it = PersonalMsg.begin(); it != PersonalMsg.end(); ++it) @@ -220,7 +221,7 @@ EVE_Enable(eventEnable) ifstream ifstreamMaster(strFileLoc + "Master.RDconf"); if (ifstreamMaster) { - ifstreamMaster >> masterQQ >> boolMasterMode >> boolDisabledGlobal >> boolDisabledMeGlobal >> boolPreserve >> boolDisabledJrrpGlobal >> boolNoDiscuss + ifstreamMaster >> masterQQ >> boolMasterMode >> boolConsole["DisabledGlobal"] >> boolConsole["DisabledMe"] >> boolConsole["Private"] >> boolConsole["DisabledJrrp"] >> boolConsole["LeaveDiscuss"] >> ClockToWork.first >> ClockToWork.second >> ClockOffWork.first >> ClockOffWork.second; } ifstreamMaster.close(); @@ -252,6 +253,8 @@ EVE_Enable(eventEnable) MonitorList.insert({ 754494359 ,Group }); } ifstreamMonitorList.close(); + //获取boolConsole + loadJMap(strFileLoc + "boolConsole.json", boolConsole); getDiceList(); ifstream ifstreamCharacterProp(strFileLoc + "CharacterProp.RDconf"); if (ifstreamCharacterProp) @@ -643,6 +646,7 @@ EVE_GroupMsg_EX(eventGroupMsg) if (WhiteGroup.count(eve.fromGroup))WhiteGroup.erase(eve.fromGroup); //setGroupLeave(eve.fromGroup); string strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + ",\n\"type\":\"ban\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":" + to_string(getLoginQQ()) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; + while (strWarning.find('\"') != string::npos)strWarning.replace(strWarning.find('\"'), 1, "\'"); NotifyMonitor(strWarning); if (getGroupMemberInfo(eve.fromGroup, getLoginQQ()).permissions == 2)strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + "\",\n\"type\":\"ban\",\n\"fromQQ\":\"" + to_string(fromQQ) + "\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":\"" + to_string(getLoginQQ()) + "\",\n\"masterQQ\":\"" + to_string(masterQQ) + "\",\n\"note\":\"" + eve.message + "\"\n}"; NotifyMonitor(strWarning); } @@ -657,7 +661,7 @@ EVE_GroupMsg_EX(eventGroupMsg) EVE_DiscussMsg_EX(eventDiscussMsg) { time_t tNow = time(NULL); - if (boolNoDiscuss) { + if (boolConsole["LeaveDiscuss"]) { AddMsgToQueue(GlobalMsg["strNoDiscuss"], eve.fromDiscuss, Discuss); Sleep(1000); setDiscussLeave(eve.fromDiscuss); @@ -710,21 +714,21 @@ EVE_System_GroupMemberIncrease(eventGroupMemberIncrease) if (beingOperateQQ != getLoginQQ() && BlackQQ.count(beingOperateQQ)) { string strNote = printGroup(fromGroup) + "发现黑名单用户" + printQQ(beingOperateQQ) + "入群"; if (WhiteGroup.count(fromGroup))strNote += "(群在白名单中)"; - else if(getGroupMemberInfo(fromGroup,getLoginQQ()).permissions>1)strNote += "(群内有权限)"; - else { + else if (getGroupMemberInfo(fromGroup, getLoginQQ()).permissions > 1)strNote += "(群内有权限)"; + else if (boolConsole["LeaveBlackQQ"]) { AddMsgToQueue("发现黑名单用户" + printQQ(beingOperateQQ) + "入群,将预防性退群", Group); strNote += "(已退群)"; Sleep(100); setGroupLeave(fromGroup); - sendAdmin(strNote); } + sendAdmin(strNote); } else if(beingOperateQQ == getLoginQQ()){ if (BlackGroup.count(fromGroup)) { AddMsgToQueue(GlobalMsg["strBlackGroup"], fromGroup, Group); setGroupLeave(fromGroup); } - else if (boolPreserve&&WhiteGroup.count(fromGroup)==0) + else if (boolConsole["Private"]&&WhiteGroup.count(fromGroup)==0) { //避免小群绕过邀请没加上白名单 if (fromQQ == masterQQ || WhiteQQ.count(fromQQ) || getGroupMemberInfo(fromGroup, masterQQ).QQID == masterQQ) { WhiteGroup.insert(fromGroup); @@ -761,6 +765,7 @@ EVE_System_GroupMemberDecrease(eventGroupMemberDecrease) { } BlackGroup.insert(fromGroup); string strWarning = "!warning{\n\"fromGroup\":" + to_string(fromGroup) + ",\n\"type\":\"kick\",\n\"fromQQ\":" + to_string(fromQQ) + ",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(beingOperateQQ) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; + while (strWarning.find('\"') != string::npos)strWarning.replace(strWarning.find('\"'), 1, "\'"); NotifyMonitor(strWarning); addBlackQQ(fromQQ, strNote, strWarning); } @@ -768,7 +773,7 @@ EVE_System_GroupMemberDecrease(eventGroupMemberDecrease) { string strNow = printSTime(stNow); string strNote = strNow + " " + printQQ(fromQQ) + "将" + printQQ(beingOperateQQ) + "移出了群" + to_string(fromGroup); string strWarning = "!warning{\n\"fromGroup\":" + to_string(fromGroup) + ",\n\"type\":\"kick\",\n\"fromQQ\":" + to_string(fromQQ) + ",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(beingOperateQQ) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; - NotifyMonitor(strWarning); + while (strWarning.find('\"') != string::npos)strWarning.replace(strWarning.find('\"'), 1, "\'"); NotifyMonitor(strWarning); if (WhiteGroup.count(fromGroup)) { WhiteGroup.erase(fromGroup); } @@ -801,7 +806,7 @@ EVE_Request_AddGroup(eventGroupInvited) { setGroupAddRequest(responseFlag, 2, 1, ""); mGroupInviter[fromGroup] = fromQQ; } - else if (boolPreserve) { + else if (boolConsole["Private"]) { strMsg += "\n已拒绝(当前在私用模式)"; setGroupAddRequest(responseFlag, 2, 2, ""); } diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 5e0fca51..ccec81aa 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -35,16 +35,9 @@ using namespace CQ; long long masterQQ = 0; set AdminQQ = {}; set MonitorList = {}; - //全局静默 - bool boolDisabledGlobal = false; - //全局禁用.me - bool boolDisabledMeGlobal = false; - //全局禁用.jrrp - bool boolDisabledJrrpGlobal = false; - //私用模式 - bool boolPreserve = false; - //禁用讨论组 - bool boolNoDiscuss = false; +std::mapboolConsole = { {"DisabledGlobal",false},{"DisabledMe",false},{"DisabledJrrp",false}, +{"Private",false},{"LeaveDiscuss",false}, +{"LeaveBlackQQ",true},{"AllowStranger",true} }; //骰娘列表 std::map mDiceList; //讨论组消息记录 @@ -161,13 +154,14 @@ void checkBlackQQ(long long llQQ, std::string strWarning) { else if (WhiteGroup.count(eachGroup.first)) { strNotice += "群在白名单中"; } - else { - AddMsgToQueue(strWarning, eachGroup.first, Group); + else if (boolConsole["LeaveBlackQQ"]) { AddMsgToQueue("发现新增黑名单成员" + printQQ(llQQ) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first, Group); strNotice += "已退群"; Sleep(1000); setGroupLeave(eachGroup.first); } + else + AddMsgToQueue(strWarning, eachGroup.first, Group); intCnt++; } } @@ -194,12 +188,12 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { //分钟时点变动 if (stTmp.wMinute != stNow.wMinute) { stTmp = stNow; - if (stNow.wHour == ClockOffWork.first&&stNow.wMinute == ClockOffWork.second && !boolDisabledGlobal) { - boolDisabledGlobal = true; + if (stNow.wHour == ClockOffWork.first&&stNow.wMinute == ClockOffWork.second && !boolConsole["DisabledGlobal"]) { + boolConsole["DisabledGlobal"] = true; NotifyMonitor(GlobalMsg["strSelfName"] + GlobalMsg["strClockOffWork"]); } - if (stNow.wHour == ClockToWork.first&&stNow.wMinute == ClockToWork.second&&boolDisabledGlobal) { - boolDisabledGlobal = false; + if (stNow.wHour == ClockToWork.first&&stNow.wMinute == ClockToWork.second&&boolConsole["DisabledGlobal"]) { + boolConsole["DisabledGlobal"] = false; NotifyMonitor(GlobalMsg["strSelfName"] + GlobalMsg["strClockToWork"]); } if (stNow.wHour == 5 && stNow.wMinute == 0) { @@ -274,19 +268,20 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { strReply += "\n" + printGroup(eachGroup.first) + ":" + printQQ(eachQQ.QQID) + "对方群权限较高"; Sleep(10); setGroupLeave(eachGroup.first); + intCnt++; break; } else if (WhiteGroup.count(eachGroup.first)) { continue; } - else { + else if (boolConsole["LeaveBlackQQ"]) { AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first); strReply += "\n" + printGroup(eachGroup.first) + ":" + printQQ(eachQQ.QQID); - Sleep(100); + Sleep(10); setGroupLeave(eachGroup.first); + intCnt++; break; } - intCnt++; } } } @@ -329,12 +324,12 @@ EVE_Menu(eventClearGroup30) { return 0; } EVE_Menu(eventGlobalSwitch) { - if (boolDisabledGlobal) { - boolDisabledGlobal = false; + if (boolConsole["DisabledGlobal"]) { + boolConsole["DisabledGlobal"] = false; MessageBoxA(nullptr, "骰娘已结束静默√", "全局开关", MB_OK | MB_ICONINFORMATION); } else { - boolDisabledGlobal = true; + boolConsole["DisabledGlobal"] = true; MessageBoxA(nullptr, "骰娘已全局静默√", "全局开关", MB_OK | MB_ICONINFORMATION); } @@ -352,6 +347,10 @@ EVE_Request_AddFriend(eventAddFriend) { GlobalMsg["strAddFriendWhiteQQ"].empty() ? AddMsgToQueue(GlobalMsg["strAddFriend"], fromQQ) : AddMsgToQueue(GlobalMsg["strAddFriendWhiteQQ"], fromQQ); } + else if (boolConsole["Private"]&& !boolConsole["AllowStranger"]) { + strMsg += ",已拒绝(当前在私用模式)"; + setFriendAddRequest(responseFlag, 2, ""); + } else { strMsg += ",已同意"; setFriendAddRequest(responseFlag, 1, ""); diff --git a/Dice/DiceConsole.h b/Dice/DiceConsole.h index e61f85fc..24a91162 100644 --- a/Dice/DiceConsole.h +++ b/Dice/DiceConsole.h @@ -21,16 +21,8 @@ extern std::set AdminQQ; //监控窗口列表 extern std::set> MonitorList; - //全部群静默 - extern bool boolDisabledGlobal; - //全局禁用.ME - extern bool boolDisabledMeGlobal; - //全局禁用.jrrp - extern bool boolDisabledJrrpGlobal; - //独占模式:被拉进讨论组或Master不在的群则秒退 - extern bool boolPreserve; - //自动退出一切讨论组 - extern bool boolNoDiscuss; + //各类全局开关 + extern std::mapboolConsole; //骰娘列表 extern std::map mDiceList; //讨论组消息记录 diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 19ee9e43..aa00bd03 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -111,16 +111,26 @@ class FromMsg { } } int AdminEvent(string strOption) { + if (boolConsole.count(strOption)){ + string strBool=readDigit(); + if (strBool.empty())reply("该项当前正" + boolConsole[strOption] ? "开启" : "关闭"); + else { + bool isOn = stoi(strBool); + boolConsole[strOption] = isOn; + AdminNotify("已" + isOn ? "开启" : "关闭" + strOption); + } + return 1; + } if (strOption == "state") { strReply = GlobalMsg["strSelfName"] + "的当前情况" + "\n" + "Master:" + printQQ(masterQQ) + "\n" + (ClockToWork.first < 24 ? "定时开启" + printClock(ClockToWork) + "\n" : "") + (ClockOffWork.first < 24 ? "定时关闭" + printClock(ClockOffWork) + "\n" : "") - + (boolPreserve ? "私用模式" : "公用模式") + "\n" - + (boolNoDiscuss ? "禁用讨论组" : "启用讨论组") + "\n" - + "全局开关:" + (boolDisabledGlobal ? "禁用" : "启用") + "\n" - + "全局.me开关:" + (boolDisabledMeGlobal ? "禁用" : "启用") + "\n" - + "全局.jrrp开关:" + (boolDisabledJrrpGlobal ? "禁用" : "启用") + "\n"; + + (boolConsole["Private"] ? "私用模式" : "公用模式") + "\n" + + (boolConsole["LeaveDiscuss"] ? "禁用讨论组" : "启用讨论组") + "\n" + + "全局开关:" + (boolConsole["DisabledGlobal"] ? "禁用" : "启用") + "\n" + + "全局.me开关:" + (boolConsole["DisabledMe"] ? "禁用" : "启用") + "\n" + + "全局.jrrp开关:" + (boolConsole["DisabledJrrp"] ? "禁用" : "启用") + "\n"; if (isAdmin) strReply += "所在群聊数:" + to_string(getGroupList().size()) + "\n" + (DiscussList.size() ? "有记录的讨论组数:" + to_string(DiscussList.size()) + "\n" : "") + "黑名单用户数:" + to_string(BlackQQ.size()) + "\n" @@ -141,8 +151,8 @@ class FromMsg { return 1; } else if (strOption == "on") { - if (boolDisabledGlobal) { - boolDisabledGlobal = false; + if (boolConsole["DisabledGlobal"]) { + boolConsole["DisabledGlobal"] = false; AdminNotify("已全局开启" + GlobalMsg["strSelfName"]); } else { @@ -151,18 +161,18 @@ class FromMsg { return 1; } else if (strOption == "off") { - if (boolDisabledGlobal) { + if (boolConsole["DisabledGlobal"]) { reply(GlobalMsg["strSelfName"] + "已经静默!"); } else { - boolDisabledGlobal = true; + boolConsole["DisabledGlobal"] = true; AdminNotify("已全局关闭" + GlobalMsg["strSelfName"]); } return 1; } else if (strOption == "meon") { - if (boolDisabledMeGlobal) { - boolDisabledMeGlobal = false; + if (boolConsole["DisabledMe"]) { + boolConsole["DisabledMe"] = false; AdminNotify("已令" + GlobalMsg["strSelfName"] + "全局启用.me√"); } else { @@ -171,18 +181,18 @@ class FromMsg { return 1; } else if (strOption == "meoff") { - if (boolDisabledMeGlobal) { + if (boolConsole["DisabledMe"]) { reply(GlobalMsg["strSelfName"] + "已禁用.me!"); } else { - boolDisabledMeGlobal = true; + boolConsole["DisabledMe"] = true; AdminNotify("已令" + GlobalMsg["strSelfName"] + "全局禁用.me√"); } return 1; } else if (strOption == "jrrpon") { - if (boolDisabledMeGlobal) { - boolDisabledMeGlobal = false; + if (boolConsole["DisabledMe"]) { + boolConsole["DisabledMe"] = false; AdminNotify("已令" + GlobalMsg["strSelfName"] + "全局启用.jrrp√"); } else { @@ -191,18 +201,18 @@ class FromMsg { return 1; } else if (strOption == "jrrpoff") { - if (boolDisabledMeGlobal) { + if (boolConsole["DisabledMe"]) { reply(GlobalMsg["strSelfName"] + "已禁用.jrrp!"); } else { - boolDisabledMeGlobal = true; + boolConsole["DisabledMe"] = true; AdminNotify("已令" + GlobalMsg["strSelfName"] + "全局禁用.jrrp√"); } return 1; } else if (strOption == "discusson") { - if (boolNoDiscuss) { - boolNoDiscuss = false; + if (boolConsole["LeaveDiscuss"]) { + boolConsole["LeaveDiscuss"] = false; AdminNotify("已关闭讨论组自动退出√"); } else { @@ -211,28 +221,28 @@ class FromMsg { return 1; } else if (strOption == "discussoff") { - if (boolNoDiscuss) { + if (boolConsole["LeaveDiscuss"]) { reply(GlobalMsg["strSelfName"] + "已开启讨论组自动退出!"); } else { - boolNoDiscuss = true; + boolConsole["LeaveDiscuss"] = true; AdminNotify("已开启讨论组自动退出√"); } return 1; } else if (strOption == "only") { - if (boolPreserve) { + if (boolConsole["Private"]) { reply(GlobalMsg["strSelfName"] + "已成为私用骰娘!"); } else { - boolPreserve = true; + boolConsole["Private"] = true; AdminNotify("已将" + GlobalMsg["strSelfName"] + "变为私用√"); } return 1; } else if (strOption == "public") { - if (boolPreserve) { - boolPreserve = false; + if (boolConsole["Private"]) { + boolConsole["Private"] = false; AdminNotify("已将" + GlobalMsg["strSelfName"] + "变为公用√"); } else { @@ -746,7 +756,7 @@ class FromMsg { } return 1; } - if (boolDisabledGlobal && (!isAdmin || !isCalled)) { + if (boolConsole["DisabledGlobal"] && (!isAdmin || !isCalled)) { if (intT == PrivateT)reply(GlobalMsg["strGlobalOff"]); return 1; } @@ -1007,9 +1017,9 @@ class FromMsg { } strReply += getGroupList()[fromGroup] + "——本群现状:\n" + "群号:" + to_string(fromGroup) + "\n" - + GlobalMsg["strSelfName"] + "在本群状态:" + (DisabledGroup.count(fromGroup) ? "禁用" : "启用") + (boolDisabledGlobal ? "(全局静默中)" : "") + "\n" - + ".me:" + (DisabledMEGroup.count(fromGroup) ? "禁用" : "启用") + (boolDisabledMeGlobal ? "(全局禁用中)" : "") + "\n" - + ".jrrp:" + (DisabledJRRPGroup.count(fromGroup) ? "禁用" : "启用") + (boolDisabledJrrpGlobal ? "(全局禁用中)" : "") + "\n" + + GlobalMsg["strSelfName"] + "在本群状态:" + (DisabledGroup.count(fromGroup) ? "禁用" : "启用") + (boolConsole["DisabledGlobal"] ? "(全局静默中)" : "") + "\n" + + ".me:" + (DisabledMEGroup.count(fromGroup) ? "禁用" : "启用") + (boolConsole["DisabledMe"] ? "(全局禁用中)" : "") + "\n" + + ".jrrp:" + (DisabledJRRPGroup.count(fromGroup) ? "禁用" : "启用") + (boolConsole["DisabledJrrp"] ? "(全局禁用中)" : "") + "\n" + (DisabledHELPGroup.count(fromGroup) ? "已禁用.help\n" : "") + (DisabledOBGroup.count(fromGroup) ? "已禁用旁观模式\n" : "") + (mGroupInviter.count(fromGroup) ? "邀请者" + printQQ(mGroupInviter[fromGroup]) + "\n" : "") @@ -1339,7 +1349,7 @@ class FromMsg { } else if (strLowerMessage.substr(intMsgCnt, 4) == "jrrp") { - if (boolDisabledJrrpGlobal) { + if (boolConsole["DisabledJrrp"]) { reply(GlobalMsg["strDisabledJrrpGlobal"]); return 1; } @@ -1924,7 +1934,7 @@ class FromMsg { } else if (strLowerMessage.substr(intMsgCnt, 2) == "me") { - if (boolDisabledMeGlobal) + if (boolConsole["DisabledMe"]) { reply(GlobalMsg["strDisabledMeGlobal"]); return 1; From f18a7102a3b2f446d7d26f552397f665422462f7 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 23:08:01 +0800 Subject: [PATCH 17/33] =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=8F=B0=E8=A1=A5?= =?UTF-8?q?=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 淇浜嗗ぇ灏忓啓闂瀵艰嚧鐨刡ug --- Dice/DiceEvent.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index aa00bd03..12224781 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -504,7 +504,7 @@ class FromMsg { } } int MasterSet() { - std::string strOption = readPara(); + std::string strOption = readUntilSpace(); if (strOption.empty()) { reply("有什么事么" + getName(fromQQ)); return -1; @@ -974,7 +974,7 @@ class FromMsg { else if (strLowerMessage.substr(intMsgCnt, 5) == "admin") { intMsgCnt += 5; - return AdminEvent(readPara()); + return AdminEvent(readUntilSpace()); } else if (strLowerMessage.substr(intMsgCnt, 5) == "coc7d" || strLowerMessage.substr(intMsgCnt, 4) == "cocd") { @@ -3344,6 +3344,15 @@ class FromMsg { void readSkipSpace() { while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; } + string readUntilSpace() { + string strPara; + readSkipSpace(); + while (!isspace(static_cast(strLowerMessage[intMsgCnt])) && intMsgCnt != strLowerMessage.length()) { + strPara += strMsg[intMsgCnt]; + intMsgCnt++; + } + return strPara; + } string readRest() { readSkipSpace(); return strMsg.substr(intMsgCnt); From 7afef1b202f939cc833a1e4928290b9c686584ed Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 23:09:46 +0800 Subject: [PATCH 18/33] =?UTF-8?q?Revert=20"=E6=8E=A7=E5=88=B6=E5=8F=B0?= =?UTF-8?q?=E8=A1=A5=E4=B8=81"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f18a7102a3b2f446d7d26f552397f665422462f7. --- Dice/DiceEvent.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 12224781..aa00bd03 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -504,7 +504,7 @@ class FromMsg { } } int MasterSet() { - std::string strOption = readUntilSpace(); + std::string strOption = readPara(); if (strOption.empty()) { reply("有什么事么" + getName(fromQQ)); return -1; @@ -974,7 +974,7 @@ class FromMsg { else if (strLowerMessage.substr(intMsgCnt, 5) == "admin") { intMsgCnt += 5; - return AdminEvent(readUntilSpace()); + return AdminEvent(readPara()); } else if (strLowerMessage.substr(intMsgCnt, 5) == "coc7d" || strLowerMessage.substr(intMsgCnt, 4) == "cocd") { @@ -3344,15 +3344,6 @@ class FromMsg { void readSkipSpace() { while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; } - string readUntilSpace() { - string strPara; - readSkipSpace(); - while (!isspace(static_cast(strLowerMessage[intMsgCnt])) && intMsgCnt != strLowerMessage.length()) { - strPara += strMsg[intMsgCnt]; - intMsgCnt++; - } - return strPara; - } string readRest() { readSkipSpace(); return strMsg.substr(intMsgCnt); From daae020c65bca9213df4527578fc64d6d76aaf42 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 3 Jul 2019 23:18:59 +0800 Subject: [PATCH 19/33] =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=8F=B0=E8=A1=A5?= =?UTF-8?q?=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 淇浜嗗ぇ灏忓啓闂瀵艰嚧鐨刡ug --- Dice/DiceEvent.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index aa00bd03..8b7658b2 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -113,11 +113,11 @@ class FromMsg { int AdminEvent(string strOption) { if (boolConsole.count(strOption)){ string strBool=readDigit(); - if (strBool.empty())reply("该项当前正" + boolConsole[strOption] ? "开启" : "关闭"); + if (strBool.empty())boolConsole[strOption] ? reply("该项当前正开启") : reply("该项当前正关闭"); else { bool isOn = stoi(strBool); boolConsole[strOption] = isOn; - AdminNotify("已" + isOn ? "开启" : "关闭" + strOption); + isOn ? AdminNotify("已开启" + strOption) : AdminNotify("已关闭" + strOption); } return 1; } @@ -504,7 +504,7 @@ class FromMsg { } } int MasterSet() { - std::string strOption = readPara(); + std::string strOption = readUntilSpace(); if (strOption.empty()) { reply("有什么事么" + getName(fromQQ)); return -1; @@ -974,7 +974,7 @@ class FromMsg { else if (strLowerMessage.substr(intMsgCnt, 5) == "admin") { intMsgCnt += 5; - return AdminEvent(readPara()); + return AdminEvent(readUntilSpace()); } else if (strLowerMessage.substr(intMsgCnt, 5) == "coc7d" || strLowerMessage.substr(intMsgCnt, 4) == "cocd") { @@ -3344,6 +3344,15 @@ class FromMsg { void readSkipSpace() { while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; } + string readUntilSpace() { + string strPara; + readSkipSpace(); + while (!isspace(static_cast(strLowerMessage[intMsgCnt])) && intMsgCnt != strLowerMessage.length()) { + strPara += strMsg[intMsgCnt]; + intMsgCnt++; + } + return strPara; + } string readRest() { readSkipSpace(); return strMsg.substr(intMsgCnt); From 6bf37fefa45b361b8f8830eb017ae1a0fd841be1 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 10 Jul 2019 20:25:18 +0800 Subject: [PATCH 20/33] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=8F=B0=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鍏佽鎸囦护鏄剧ず鍏ㄥ眬璁剧疆銆侀濞樺垪琛 --- Dice/Dice.cpp | 17 ++++++++------- Dice/DiceConsole.cpp | 20 +++++++++++------- Dice/DiceEvent.h | 50 +++++++++++++++++++++++++++----------------- Dice/GlobalVar.cpp | 7 ++++--- Dice/Jsonio.h | 8 ++++--- Dice/app.json | 4 ++-- 6 files changed, 64 insertions(+), 42 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index a7767e8d..a5dfd093 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -633,20 +633,20 @@ EVE_GroupMsg_EX(eventGroupMsg) intAuthCnt++; } } - addBlackQQ(fromQQ, "群内禁言"); + if(boolConsole["BannedBanOwner"])addBlackQQ(fromQQ, "群内禁言"); string strNote = "在" + printGroup(eve.fromGroup) + "中," + eve.message; - string strMsg = strNote + "\n已拉黑群主" + getStrangerInfo(fromQQ).nick + "(" + to_string(fromQQ) + "),另有管理员" + to_string(intAuthCnt) + "名" + strAuthList; + string strMsg = strNote + "\n群主" + getStrangerInfo(fromQQ).nick + "(" + to_string(fromQQ) + "),另有管理员" + to_string(intAuthCnt) + "名" + strAuthList; if (mGroupInviter.count(eve.fromGroup)) { long long llInviter = mGroupInviter[eve.fromGroup]; strMsg += "\n入群邀请者:" + printQQ(llInviter); - addBlackQQ(llInviter, "不负责任地邀请"); + if (boolConsole["BannedBanInviter"])addBlackQQ(llInviter, "不负责任地邀请"); } NotifyMonitor(strMsg); BlackGroup.insert(eve.fromGroup); if (WhiteGroup.count(eve.fromGroup))WhiteGroup.erase(eve.fromGroup); - //setGroupLeave(eve.fromGroup); + if (boolConsole["BannedLeave"])setGroupLeave(eve.fromGroup); + while (strNote.find('\"') != string::npos)strNote.replace(strNote.find('\"'), 1, "\'"); string strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + ",\n\"type\":\"ban\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":" + to_string(getLoginQQ()) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; - while (strWarning.find('\"') != string::npos)strWarning.replace(strWarning.find('\"'), 1, "\'"); NotifyMonitor(strWarning); if (getGroupMemberInfo(eve.fromGroup, getLoginQQ()).permissions == 2)strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + "\",\n\"type\":\"ban\",\n\"fromQQ\":\"" + to_string(fromQQ) + "\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":\"" + to_string(getLoginQQ()) + "\",\n\"masterQQ\":\"" + to_string(masterQQ) + "\",\n\"note\":\"" + eve.message + "\"\n}"; NotifyMonitor(strWarning); } @@ -758,22 +758,23 @@ EVE_System_GroupMemberDecrease(eventGroupMemberDecrease) { if (mGroupInviter.count(fromGroup)) { long long llInviter = mGroupInviter[fromGroup]; strNote += ",入群邀请者:" + printQQ(llInviter); - addBlackQQ(llInviter, strNote); + if (boolConsole["BannedBanInviter"])addBlackQQ(llInviter, strNote); } if (WhiteGroup.count(fromGroup)) { WhiteGroup.erase(fromGroup); } BlackGroup.insert(fromGroup); + while (strNote.find('\"') != string::npos)strNote.replace(strNote.find('\"'), 1, "\'"); string strWarning = "!warning{\n\"fromGroup\":" + to_string(fromGroup) + ",\n\"type\":\"kick\",\n\"fromQQ\":" + to_string(fromQQ) + ",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(beingOperateQQ) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; - while (strWarning.find('\"') != string::npos)strWarning.replace(strWarning.find('\"'), 1, "\'"); NotifyMonitor(strWarning); addBlackQQ(fromQQ, strNote, strWarning); } else if (mDiceList.count(beingOperateQQ) && subType == 2) { string strNow = printSTime(stNow); string strNote = strNow + " " + printQQ(fromQQ) + "将" + printQQ(beingOperateQQ) + "移出了群" + to_string(fromGroup); + while (strNote.find('\"') != string::npos)strNote.replace(strNote.find('\"'), 1, "\'"); string strWarning = "!warning{\n\"fromGroup\":" + to_string(fromGroup) + ",\n\"type\":\"kick\",\n\"fromQQ\":" + to_string(fromQQ) + ",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(beingOperateQQ) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; - while (strWarning.find('\"') != string::npos)strWarning.replace(strWarning.find('\"'), 1, "\'"); NotifyMonitor(strWarning); + NotifyMonitor(strWarning); if (WhiteGroup.count(fromGroup)) { WhiteGroup.erase(fromGroup); } diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index ccec81aa..b616c406 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -37,7 +37,9 @@ set AdminQQ = {}; set MonitorList = {}; std::mapboolConsole = { {"DisabledGlobal",false},{"DisabledMe",false},{"DisabledJrrp",false}, {"Private",false},{"LeaveDiscuss",false}, -{"LeaveBlackQQ",true},{"AllowStranger",true} }; +{"LeaveBlackQQ",true},{"AllowStranger",true}, +{"BannedBanOwner",true},{"BannedInviter",true},{"BannedLeave",false}, +{"KickedBanInviter",false} }; //骰娘列表 std::map mDiceList; //讨论组消息记录 @@ -155,6 +157,7 @@ void checkBlackQQ(long long llQQ, std::string strWarning) { strNotice += "群在白名单中"; } else if (boolConsole["LeaveBlackQQ"]) { + AddMsgToQueue(strWarning, eachGroup.first, Group); AddMsgToQueue("发现新增黑名单成员" + printQQ(llQQ) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first, Group); strNotice += "已退群"; Sleep(1000); @@ -229,7 +232,7 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { for (auto eachGroup : GroupList) { int intDay = (int)(tNow - getGroupMemberInfo(eachGroup.first, getLoginQQ()).LastMsgTime)/86400; if (intDay > intDayLim) { - strReply += "群(" + to_string(eachGroup.first) + "):" + to_string(intDay) + "天\n"; + strReply += printGroup(eachGroup.first) + ":" + to_string(intDay) + "天\n"; AddMsgToQueue(format(GlobalMsg["strOverdue"], { GlobalMsg["strSelfName"], to_string(intDay) }), eachGroup.first, Group); Sleep(10); setGroupLeave(eachGroup.first); @@ -240,7 +243,7 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { for (auto eachDiscuss : DiscussList) { int intDay = (int)(tNow - eachDiscuss.second) / 86400; if (intDay > intDayLim){ - strReply += "讨论组(" + to_string(eachDiscuss.first) + "):" + to_string(intDay) + "天\n"; + strReply += printChat({ eachDiscuss.first,Discuss }) + ":" + to_string(intDay) + "天\n"; AddMsgToQueue(format(GlobalMsg["strOverdue"], { GlobalMsg["strSelfName"], to_string(intDay) }), eachDiscuss.first, Group); Sleep(10); setDiscussLeave(eachDiscuss.first); @@ -255,7 +258,10 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { else if (strPara == "black") { for (auto eachGroup : GroupList) { if (BlackGroup.count(eachGroup.first)) { + AddMsgToQueue(GlobalMsg["strBlackGroup"], eachGroup.first, Group); strReply += "\n" + printGroup(eachGroup.first) + ":" + "黑名单群"; + Sleep(100); + setGroupLeave(eachGroup.first); } vector MemberList = getGroupMemberList(eachGroup.first); for (auto eachQQ : MemberList) { @@ -264,9 +270,9 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { continue; } else if (getGroupMemberInfo(eachGroup.first, eachQQ.QQID).permissions > getGroupMemberInfo(eachGroup.first, getLoginQQ()).permissions) { - AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first); + AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first, Group); strReply += "\n" + printGroup(eachGroup.first) + ":" + printQQ(eachQQ.QQID) + "对方群权限较高"; - Sleep(10); + Sleep(100); setGroupLeave(eachGroup.first); intCnt++; break; @@ -275,9 +281,9 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { continue; } else if (boolConsole["LeaveBlackQQ"]) { - AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first); + AddMsgToQueue("发现黑名单成员" + printQQ(eachQQ.QQID) + "\n" + GlobalMsg["strSelfName"] + "将预防性退群", eachGroup.first, Group); strReply += "\n" + printGroup(eachGroup.first) + ":" + printQQ(eachQQ.QQID); - Sleep(10); + Sleep(100); setGroupLeave(eachGroup.first); intCnt++; break; diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 8b7658b2..4155776d 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -111,16 +111,6 @@ class FromMsg { } } int AdminEvent(string strOption) { - if (boolConsole.count(strOption)){ - string strBool=readDigit(); - if (strBool.empty())boolConsole[strOption] ? reply("该项当前正开启") : reply("该项当前正关闭"); - else { - bool isOn = stoi(strBool); - boolConsole[strOption] = isOn; - isOn ? AdminNotify("已开启" + strOption) : AdminNotify("已关闭" + strOption); - } - return 1; - } if (strOption == "state") { strReply = GlobalMsg["strSelfName"] + "的当前情况" + "\n" + "Master:" + printQQ(masterQQ) + "\n" @@ -130,8 +120,8 @@ class FromMsg { + (boolConsole["LeaveDiscuss"] ? "禁用讨论组" : "启用讨论组") + "\n" + "全局开关:" + (boolConsole["DisabledGlobal"] ? "禁用" : "启用") + "\n" + "全局.me开关:" + (boolConsole["DisabledMe"] ? "禁用" : "启用") + "\n" - + "全局.jrrp开关:" + (boolConsole["DisabledJrrp"] ? "禁用" : "启用") + "\n"; - if (isAdmin) strReply += "所在群聊数:" + to_string(getGroupList().size()) + "\n" + + "全局.jrrp开关:" + (boolConsole["DisabledJrrp"] ? "禁用" : "启用"); + if (isAdmin) strReply += "\n所在群聊数:" + to_string(getGroupList().size()) + "\n" + (DiscussList.size() ? "有记录的讨论组数:" + to_string(DiscussList.size()) + "\n" : "") + "黑名单用户数:" + to_string(BlackQQ.size()) + "\n" + "黑名单群数:" + to_string(BlackGroup.size()) + "\n" @@ -144,7 +134,17 @@ class FromMsg { reply(GlobalMsg["strNotAdmin"]); return -1; } - if (strOption == "delete") { + if (boolConsole.count(strOption)) { + string strBool = readDigit(); + if (strBool.empty())boolConsole[strOption] ? reply("该项当前正开启") : reply("该项当前正关闭"); + else { + bool isOn = stoi(strBool); + boolConsole[strOption] = isOn; + isOn ? AdminNotify("已开启" + strOption) : AdminNotify("已关闭" + strOption); + } + return 1; + } + else if (strOption == "delete") { AdminNotify("已经放弃管理员权限√"); MonitorList.erase({ fromQQ,Private }); AdminQQ.erase(fromQQ); @@ -170,6 +170,16 @@ class FromMsg { } return 1; } + else if (strOption == "dicelist") + { + getDiceList(); + strReply = "当前骰娘列表:"; + for (auto it : mDiceList) { + strReply += "\n" + printQQ(it.first); + } + reply(); + return 1; + } else if (strOption == "meon") { if (boolConsole["DisabledMe"]) { boolConsole["DisabledMe"] = false; @@ -613,9 +623,12 @@ class FromMsg { if (isAdmin || mDiceList.count(fromQQ)) { intMsgCnt += 7; string strWarning = readRest(); - nlohmann::json jInfo = { {"fromGroup",0},{"time","Unknown"},{"fromQQ",0},{"note","" } }; + long long blackQQ,blackGroup; + nlohmann::json jInfo = { {"type","Unknown"},{"fromGroup",0},{"time","Unknown"},{"fromQQ",0},{"note","" } }; try { jInfo = nlohmann::json::parse(GBKtoUTF8(strWarning)); + blackQQ = jInfo["fromQQ"]; + blackGroup = jInfo["fromGroup"]; } catch (...) { return -1; @@ -623,8 +636,6 @@ class FromMsg { string type = readJKey(jInfo["type"]); string time = readJKey(jInfo["time"]); string note = readJKey(jInfo["note"]); - long long blackQQ = jInfo["fromQQ"]; - long long blackGroup = jInfo["fromGroup"]; if (type != "ban" && type != "kick" || (blackGroup&&BlackGroup.count(blackGroup)) && (blackQQ&&BlackQQ.count(blackQQ))) { return 1; } @@ -688,7 +699,7 @@ class FromMsg { if (Command == "on") { if (fromType == Group) { - if (getGroupMemberInfo(fromGroup, fromQQ).permissions >= 2) + if (isAuth) { if (DisabledGroup.count(fromGroup)) { @@ -720,7 +731,7 @@ class FromMsg { else if (Command == "off") { if (fromType == Group) { - if (getGroupMemberInfo(fromGroup, fromQQ).permissions >= 2) + if (isAuth) { if (!DisabledGroup.count(fromGroup)) { @@ -903,7 +914,7 @@ class FromMsg { intMsgCnt += 7; while (isspace(static_cast(strLowerMessage[intMsgCnt]))) intMsgCnt++; - if (getGroupMemberInfo(fromGroup, fromQQ).permissions >= 2) + if (isAuth) { string strWelcomeMsg = strMsg.substr(intMsgCnt); if (strWelcomeMsg.empty()) @@ -1022,6 +1033,7 @@ class FromMsg { + ".jrrp:" + (DisabledJRRPGroup.count(fromGroup) ? "禁用" : "启用") + (boolConsole["DisabledJrrp"] ? "(全局禁用中)" : "") + "\n" + (DisabledHELPGroup.count(fromGroup) ? "已禁用.help\n" : "") + (DisabledOBGroup.count(fromGroup) ? "已禁用旁观模式\n" : "") + + "COC房规:" + (mDefaultCOC.count({ fromGroup,Group }) ? to_string(mDefaultCOC[{ fromGroup, Group }])+"\n" : "未设置\n") + (mGroupInviter.count(fromGroup) ? "邀请者" + printQQ(mGroupInviter[fromGroup]) + "\n" : "") + "入群欢迎:" + (WelcomeMsg.count(fromGroup) ? "已设置" : "未设置") + (sInact.size() ? "\n30天不活跃群员数:" + to_string(sInact.size()) : ""); diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index 29e9ad9c..33e6e9ff 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -35,7 +35,7 @@ CQ::logger DiceLogger("Dice!"); * 请勿修改Dice_Build, Dice_Ver_Without_Build,DiceRequestHeader以及Dice_Ver常量 * 请修改Dice_Short_Ver或Dice_Full_Ver常量以达到版本自定义 */ -const unsigned short Dice_Build = 545; +const unsigned short Dice_Build = 546; const std::string Dice_Ver_Without_Build = "2.3.8Express8"; const std::string DiceRequestHeader = "Dice/2.3.8"; const std::string Dice_Ver = Dice_Ver_Without_Build + "(" + std::to_string(Dice_Build) + ")"; @@ -249,7 +249,7 @@ std::map GlobalMsg std::map EditedMsg; std::map HelpDoc = { -{"更新","545:开放自定义deck\n544:后台管理更新\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, +{"更新","546:完善骰娘列表体验\n545:开放自定义deck\n544:后台管理更新\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, {"协议","0.本协议是Shiki(Death、Judgement、The World)的服务协议。如果你看到了这句话,意味着Master应用默认协议,请注意。\n1.邀请骰娘、使用掷骰服务和在群内阅读此协议视为同意并承诺遵守此协议,否则请使用.dismiss移出骰娘。\n2.不允许禁言、移出骰娘或刷屏掷骰等对骰娘的不友善行为,这些行为将会提高骰娘被制裁的风险。开关骰娘响应请使用.bot on/off。\n3.骰娘默认邀请行为已事先得到群内同意,因而会自动同意群邀请。因擅自邀请而使骰娘遭遇不友善行为时,邀请者因未履行预见义务而将承担连带责任。\n4.禁止将骰娘用于赌博及其他违法犯罪行为。\n5.对于设置敏感昵称等无法预见但有可能招致言论审查的行为,骰娘可能会出于自我保护而拒绝提供服务\n6.由于技术以及资金原因,我们无法保证机器人100%的时间稳定运行,可能不定时停机维护或遭遇冻结,但是相应情况会及时通过各种渠道进行通知,敬请谅解。临时停机的骰娘不会有任何响应,故而不会影响群内活动,此状态下仍然禁止不友善行为。\n7.对于违反协议的行为,骰娘将视情况终止对用户和所在群提供服务,并将不良记录共享给其他服务提供方。黑名单相关事宜可以与服务提供方协商,但最终裁定权在服务提供方。\n8.本协议内容随时有可能改动。请注意帮助信息、签名、空间、官方群等处的骰娘动态。\n9.骰娘提供掷骰服务是完全免费的,欢迎投食。\n10.本服务最终解释权归服务提供方所有。"}, {"链接","查看源码:https://github.com/w4123/Dice/tree/Shiki\n插件下载:https://github.com/w4123/Dice/releases\n官方文档:https://www.stringempty.xyz\n跑团记录着色器:https://logpainter.kokona.tech"}, {"设定","Master:()\n.me使用:禁止\n.jrrp使用:允许\n邀请处理:黑名单制,非禁即入\n讨论组使用:允许\n移出反制:拉黑群和操作者\n禁言反制:默认拉黑群和群主\n刷屏反制:警告\n邀请人责任:有限连带\n窥屏可能:有\n其他插件:无\n官方群:941980833\n私骰群:192499947"}, @@ -305,8 +305,9 @@ std::map HelpDoc = { {"增强检定","&en"}, {"en","成长检定:.en [技能名称]([技能值])(([失败成长值]/)[成功成长值])\n已经.st时,可省略最后的参数\n.en 教育 60 +1D10 教育增强\t//后接成功时成长值\n.en 幸运 +1D3/1D10幸运成长\t//调用人物卡属性时,成长后的值会自动更新\n可变成长值必须以加减号开头,不限制加减"}, {"抽牌","&draw"}, -{"draw","抽牌:.draw [牌堆名称] ([抽牌数量])\t//抽到的牌不放回,抽牌数量不能超过牌堆数量\n当前可用牌堆名:硬币/东方角色/麻将/扑克花色/扑克\n调查员职业/调查员背景/英雄天赋/煤气灯/个人描述/思想信念/重要之人/重要之人理由/意义非凡之地/宝贵之物/调查员特点/即时症状/总结症状/恐惧症状/狂躁症状/\n阵营/哈罗花色/冒险点子/\n人偶暗示/人偶宝物/人偶记忆碎片/\nAMGC/AMGC身材/AMGC专精/AMGC武器/AMGC套装/AMGC才能/AMGC特技1/AMGC特技2/AMGC特技3\n/塔罗牌/正逆/塔罗牌占卜/单张塔罗牌/圣三角牌阵/四要素牌阵/小十字牌阵/六芒星牌阵/凯尔特十字牌阵\n.help审判正位(牌+方向)可获取塔罗牌解读"}, +{"draw","抽牌:.draw [牌堆名称] ([抽牌数量])\t//抽到的牌不放回,抽牌数量不能超过牌堆数量\n当前内置牌堆:硬币/性别/\n调查员职业/调查员背景/英雄天赋/煤气灯/个人描述/思想信念/重要之人/重要之人理由/意义非凡之地/宝贵之物/调查员特点/即时症状/总结症状/恐惧症状/狂躁症状/\n阵营/哈罗花色/冒险点子/\n人偶暗示/人偶宝物/人偶记忆碎片/人偶依恋/\nAMGC/AMGC身材/AMGC专精/AMGC武器/AMGC套装/AMGC才能/AMGC特技1/AMGC特技2/AMGC特技3\n/塔罗牌/正逆/塔罗牌占卜/单张塔罗牌/圣三角牌阵/四要素牌阵/小十字牌阵/六芒星牌阵/凯尔特十字牌阵\n.help审判正位(牌+方向)可获取塔罗牌解读\nmaster额外配置请.help扩展牌堆"}, {"先攻","&ri"}, +{"扩展牌堆","此处展示master额外添加的牌堆名:"}, {"ri","先攻(群聊限定):.ri([加值])([昵称])\n.ri -1 某pc\t//自动记入先攻列表\n.ri +5 boss"}, {"先攻列表","&init"}, {"init","先攻列表:\n.init\t//查看先攻列表\n.init clr\t//清除先攻列表"}, diff --git a/Dice/Jsonio.h b/Dice/Jsonio.h index e3726741..0688abe0 100644 --- a/Dice/Jsonio.h +++ b/Dice/Jsonio.h @@ -23,7 +23,8 @@ int readJson(std::string strJson, std::map &mapTmp) { for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) { T1 tKey = readJKey(it.key()); - T2 tVal = UTF8toGBK(it.value()); + T2 tVal = it.value(); + tVal = UTF8toGBK(tVal); mapTmp[tKey] = tVal; intCnt++; } @@ -44,7 +45,8 @@ int loadJMap(std::string strLoc, std::map &mapTmp) { for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) { T1 tKey = readJKey(it.key()); - T2 tVal = UTF8toGBK(it.value()); + T2 tVal = it.value(); + tVal = UTF8toGBK(tVal); mapTmp[tKey] = tVal; } } @@ -73,7 +75,7 @@ int saveJMap(std::string strLoc, std::map mapTmp) { if (fout) { nlohmann::json j; for (auto it : mapTmp) { - j[writeJKey(it.first)] = GBKtoUTF8(it.second); + j[writeJKey(it.first)] = GBKtoUTF8(it.second); } fout << j; fout.close(); diff --git a/Dice/app.json b/Dice/app.json index b72412ab..2fedafff 100644 --- a/Dice/app.json +++ b/Dice/app.json @@ -2,8 +2,8 @@ "ret": 1, "apiver": 9, "name": "Dice!", - "version": "2.3.8Express7", - "version_id": 543, + "version": "2.3.8Express8", + "version_id": 546, "author": "w4123婧磩 Shiki", "description": "璺戝洟鐢ㄩ瀛 鏈▼搴忎娇鐢ˋGPLv3寮婧愬崗璁巿鏉 Copyright (c) 2018-2019 w4123婧磩 Shiki", "event": [ From 3c5fc667b33210927938cc395c094ee3d0a5115e Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Thu, 11 Jul 2019 15:20:37 +0800 Subject: [PATCH 21/33] =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 淇浜嗕竴浜涜鍙ョ殑鍒ゆ柇闂 --- Dice/Dice.cpp | 13 ++++++++----- Dice/DiceEvent.h | 17 ++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index a5dfd093..3ed2c8f0 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -619,6 +619,7 @@ EVE_GroupMsg_EX(eventGroupMsg) if (eve.isAnonymous())return; if (eve.isSystem()) { if (eve.message.find("被管理员禁言") != string::npos&&eve.message.find(to_string(getLoginQQ())) != string::npos) { + string strNow = printSTime(stNow); long long fromQQ; int intAuthCnt = 0; string strAuthList; @@ -633,9 +634,11 @@ EVE_GroupMsg_EX(eventGroupMsg) intAuthCnt++; } } - if(boolConsole["BannedBanOwner"])addBlackQQ(fromQQ, "群内禁言"); - string strNote = "在" + printGroup(eve.fromGroup) + "中," + eve.message; - string strMsg = strNote + "\n群主" + getStrangerInfo(fromQQ).nick + "(" + to_string(fromQQ) + "),另有管理员" + to_string(intAuthCnt) + "名" + strAuthList; + //能否锁定群主 + bool isOwner = intAuthCnt == 0 || getGroupMemberInfo(eve.fromGroup, getLoginQQ()).permissions == 2; + string strNote = strNow + "在" + printGroup(eve.fromGroup) + "中," + eve.message; + if (boolConsole["BannedBanOwner"]||isOwner)addBlackQQ(fromQQ, strNote); + string strMsg = strNote + "\n群主" + printQQ(fromQQ)+",另有管理员" + to_string(intAuthCnt) + "名" + strAuthList; if (mGroupInviter.count(eve.fromGroup)) { long long llInviter = mGroupInviter[eve.fromGroup]; strMsg += "\n入群邀请者:" + printQQ(llInviter); @@ -646,8 +649,8 @@ EVE_GroupMsg_EX(eventGroupMsg) if (WhiteGroup.count(eve.fromGroup))WhiteGroup.erase(eve.fromGroup); if (boolConsole["BannedLeave"])setGroupLeave(eve.fromGroup); while (strNote.find('\"') != string::npos)strNote.replace(strNote.find('\"'), 1, "\'"); - string strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + ",\n\"type\":\"ban\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":" + to_string(getLoginQQ()) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; - if (getGroupMemberInfo(eve.fromGroup, getLoginQQ()).permissions == 2)strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + "\",\n\"type\":\"ban\",\n\"fromQQ\":\"" + to_string(fromQQ) + "\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":\"" + to_string(getLoginQQ()) + "\",\n\"masterQQ\":\"" + to_string(masterQQ) + "\",\n\"note\":\"" + eve.message + "\"\n}"; + string strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + ",\n\"type\":\"ban\",\n\"time\":\"" + strNow + "\",\n\"DiceMaid\":" + to_string(getLoginQQ()) + ",\n\"masterQQ\":" + to_string(masterQQ) + ",\n\"note\":\"" + strNote + "\"\n}"; + if (isOwner)strWarning = "!warning{\n\"fromGroup\":" + to_string(eve.fromGroup) + "\",\n\"type\":\"ban\",\n\"fromQQ\":\"" + to_string(fromQQ) + "\",\n\"time\":\"" + printSTime(stNow) + "\",\n\"DiceMaid\":\"" + to_string(getLoginQQ()) + "\",\n\"masterQQ\":\"" + to_string(masterQQ) + "\",\n\"note\":\"" + eve.message + "\"\n}"; NotifyMonitor(strWarning); } else return; diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 4155776d..9bc568a2 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -343,7 +343,7 @@ class FromMsg { long long llTargetID = readID(); if (strOption == "dismiss") { WhiteGroup.erase(llTargetID); - if (getGroupList().count(llTargetID) && setGroupLeave(llTargetID)) { + if (getGroupList().count(llTargetID) && setGroupLeave(llTargetID) == 0) { mLastMsgList.erase({ llTargetID ,Group }); AdminNotify("已令" + GlobalMsg["strSelfName"] + "退出群" + to_string(llTargetID) + "√"); } @@ -606,7 +606,7 @@ class FromMsg { setDiscussLeave(fromGroup); mLastMsgList.erase(fromChat); } - else if (getGroupMemberInfo(fromGroup, fromQQ).permissions >= 2) + else if (isAuth) { if (!GlobalMsg["strDismiss"].empty())reply(GlobalMsg["strDismiss"]); setGroupLeave(fromGroup); @@ -631,28 +631,27 @@ class FromMsg { blackGroup = jInfo["fromGroup"]; } catch (...) { - return -1; + return 0; } string type = readJKey(jInfo["type"]); string time = readJKey(jInfo["time"]); string note = readJKey(jInfo["note"]); - if (type != "ban" && type != "kick" || (blackGroup&&BlackGroup.count(blackGroup)) && (blackQQ&&BlackQQ.count(blackQQ))) { + if (type != "ban" && type != "kick" || (!blackGroup||BlackGroup.count(blackGroup)) && (!blackQQ||BlackQQ.count(blackQQ))) { return 1; } if (!isAdmin)sendAdmin("来自" + printQQ(fromQQ) + ":" + strWarning); strWarning = "!warning" + strWarning; if (blackGroup) { BlackGroup.insert(blackGroup); - if (!intT && blackGroup == fromGroup) { - setGroupLeave(fromGroup); - } - else if(getGroupList().count(blackGroup)){ - AddMsgToQueue(strWarning, blackGroup, Group); + if(getGroupList().count(blackGroup)){ + if (blackGroup != fromGroup)AddMsgToQueue(strWarning, blackGroup, Group); + AdminNotify("已通知" + GlobalMsg["strSelfName"] + "将" + printGroup(blackGroup) + "加入群黑名单√"); Sleep(100); setGroupLeave(blackGroup); } } if (blackQQ) { + AdminNotify("已通知" + GlobalMsg["strSelfName"] + "将" + printQQ(blackQQ) + "加入用户黑名单"); addBlackQQ(blackQQ, note, strWarning); } return 1; From 07789f3282b8e0aea1280bc9b26173ecf40e6c09 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Thu, 11 Jul 2019 15:23:11 +0800 Subject: [PATCH 22/33] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E7=9A=84=E9=98=88=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rd鍙細鍦ㄨ秴杩20楠版椂瑙﹀彂 --- Dice/RD.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dice/RD.h b/Dice/RD.h index d1498f4e..26678811 100644 --- a/Dice/RD.h +++ b/Dice/RD.h @@ -88,7 +88,7 @@ class RD if (intTmpResOnce >= AddDiceVal) AddNum++; } - if (intCnt > 9)sort(vintTmpRes.end() - intCnt, vintTmpRes.end()); + if (intCnt > 10)sort(vintTmpRes.end() - intCnt, vintTmpRes.end()); intDiceCnt = AddNum; } if (boolNegative) @@ -276,7 +276,7 @@ class RD intTotal -= intTmpRes * intMultiplier; else intTotal += intTmpRes * intMultiplier; - if (vintTmpRes.size() > 9)sort(vintTmpRes.begin(), vintTmpRes.end()); + if (vintTmpRes.size() > 20)sort(vintTmpRes.begin(), vintTmpRes.end()); vvintRes.push_back(vintTmpRes); vintRes.push_back(intTmpRes * intMultiplier); return 0; @@ -317,7 +317,7 @@ class RD else intTotal += intTmpRes * intMultiplier; vintRes.push_back(intTmpRes); - if (vintTmpRes.size() > 9)sort(vintTmpRes.begin(), vintTmpRes.end()); + if (vintTmpRes.size() > 20)sort(vintTmpRes.begin(), vintTmpRes.end()); vvintRes.push_back(vintTmpRes); return 0; } From 60f5c5bd67e123d93bce8b3eae539648d15bb159 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Fri, 12 Jul 2019 12:33:09 +0800 Subject: [PATCH 23/33] =?UTF-8?q?=E9=A2=84=E8=AE=BE=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/DiceConsole.cpp | 4 ++-- Dice/DiceEvent.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index b616c406..0d95dd85 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -38,8 +38,8 @@ set MonitorList = {}; std::mapboolConsole = { {"DisabledGlobal",false},{"DisabledMe",false},{"DisabledJrrp",false}, {"Private",false},{"LeaveDiscuss",false}, {"LeaveBlackQQ",true},{"AllowStranger",true}, -{"BannedBanOwner",true},{"BannedInviter",true},{"BannedLeave",false}, -{"KickedBanInviter",false} }; +{"BannedBanOwner",true},{"BannedLeave",false},{"BannedBanInviter",true}, +{"KickedBanInviter",true} }; //骰娘列表 std::map mDiceList; //讨论组消息记录 diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 9bc568a2..758ee18e 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -90,6 +90,7 @@ class FromMsg { } } else { + if(!isMaster)AddMsgToQueue(strName + strMsg, masterQQ); for (auto it : AdminQQ) { AddMsgToQueue(strName + strMsg, it); } From 35f8992e9807acc206b919c76cb757bef3c4aff4 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sat, 13 Jul 2019 20:59:23 +0800 Subject: [PATCH 24/33] =?UTF-8?q?=E4=B8=BAwarning=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=8B=AC=E7=AB=8B=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 瑙e喅閲嶅閫氭姤鐨勯棶棰 --- Dice/Dice.cpp | 2 ++ Dice/DiceConsole.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++- Dice/DiceConsole.h | 2 ++ Dice/DiceEvent.h | 33 +------------------- 4 files changed, 75 insertions(+), 33 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index 3ed2c8f0..9cf2d565 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -212,6 +212,8 @@ EVE_Enable(eventEnable) msgSendThread.detach(); thread threadConsoleTimer(ConsoleTimer); threadConsoleTimer.detach(); + thread threadWarning(warningHandler); + threadWarning.detach(); strFileLoc = getAppDirectory(); /* * 名称存储-创建与读取 diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 0d95dd85..a5831907 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -22,6 +22,8 @@ */ #pragma once #include +#include +#include #include "DiceConsole.h" #include "GlobalVar.h" #include "MsgFormat.h" @@ -122,7 +124,7 @@ void getDiceList() { } } else { - AddMsgToQueue(strMsg, masterQQ); + masterQQ == fromQQ ? AddMsgToQueue(strMsg, masterQQ) : AddMsgToQueue(strName + strMsg, masterQQ); for (auto it : AdminQQ) { AddMsgToQueue(strName + strMsg, it); } @@ -133,6 +135,7 @@ void NotifyMonitor(std::string strMsg) { if (!boolMasterMode)return; for (auto it : MonitorList) { AddMsgToQueue(strMsg, it.first, it.second); + Sleep(1000); } } //拉黑用户后搜查群 @@ -184,6 +187,72 @@ void addBlackQQ(long long llQQ, std::string strReason, std::string strNotice) { } checkBlackQQ(llQQ, strNotice); } +struct fromMsg { + string strMsg; + long long fromQQ = 0; + long long fromGroup = 0; + fromMsg() = default; + fromMsg(string strMsg, long long QQ, long long Group) :strMsg(strMsg), fromQQ(QQ), fromGroup(Group) {}; +}; +// 消息发送队列 +std::queue warningQueue; +// 消息发送队列锁 +mutex warningMutex; +void AddWarning(const string& msg, long long DiceQQ, long long fromGroup) +{ + lock_guard lock_queue(warningMutex); + warningQueue.emplace(msg, DiceQQ, fromGroup); +} +void warningHandler() { + while (Enabled) + { + fromMsg warning; + { + lock_guard lock_queue(warningMutex); + if (!warningQueue.empty()) + { + warning = warningQueue.front(); + warningQueue.pop(); + } + } + if (!warning.strMsg.empty()) { + long long blackQQ, blackGroup; + nlohmann::json jInfo = { {"type","Unknown"},{"fromGroup",0},{"time","Unknown"},{"fromQQ",0},{"note","" } }; + try { + jInfo = nlohmann::json::parse(GBKtoUTF8(warning.strMsg)); + blackQQ = jInfo["fromQQ"]; + blackGroup = jInfo["fromGroup"]; + } + catch (...) { + continue; + } + string type = readJKey(jInfo["type"]); + string time = readJKey(jInfo["time"]); + string note = readJKey(jInfo["note"]); + if (type != "ban" && type != "kick" || (!blackGroup || BlackGroup.count(blackGroup)) && (!blackQQ || BlackQQ.count(blackQQ))) { + continue; + } + string strWarning = "!warning" + warning.strMsg; + if (warning.fromQQ != masterQQ || !AdminQQ.count(warning.fromQQ))sendAdmin("来自" + printQQ(warning.fromQQ) + strWarning); + if (blackGroup) { + BlackGroup.insert(blackGroup); + if (getGroupList().count(blackGroup)) { + if (blackGroup != warning.fromGroup)AddMsgToQueue(strWarning, blackGroup, Group); + setGroupLeave(blackGroup); + } + sendAdmin("已通知" + GlobalMsg["strSelfName"] + "将" + printGroup(blackGroup) + "加入群黑名单√", warning.fromQQ); + } + if (blackQQ) { + addBlackQQ(blackQQ, note, strWarning); + sendAdmin("已通知" + GlobalMsg["strSelfName"] + "将" + printQQ(blackQQ) + "加入用户黑名单", warning.fromQQ); + } + } + else + { + this_thread::sleep_for(chrono::milliseconds(20)); + } + } +} //简易计时器 void ConsoleTimer() { while (Enabled) { diff --git a/Dice/DiceConsole.h b/Dice/DiceConsole.h index 24a91162..cbe7fd78 100644 --- a/Dice/DiceConsole.h +++ b/Dice/DiceConsole.h @@ -72,6 +72,8 @@ void checkBlackQQ(long long, std::string strWarning = ""); //拉黑用户 void addBlackQQ(long long, std::string strReason = "", std::string strNotice = ""); +void AddWarning(const std::string& msg, long long DiceQQ, long long fromGroup); +void warningHandler(); extern void ConsoleTimer(); #endif /*Dice_Console*/ diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 758ee18e..0669d687 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -623,38 +623,7 @@ class FromMsg { else if (strLowerMessage.substr(intMsgCnt, 7) == "warning") { if (isAdmin || mDiceList.count(fromQQ)) { intMsgCnt += 7; - string strWarning = readRest(); - long long blackQQ,blackGroup; - nlohmann::json jInfo = { {"type","Unknown"},{"fromGroup",0},{"time","Unknown"},{"fromQQ",0},{"note","" } }; - try { - jInfo = nlohmann::json::parse(GBKtoUTF8(strWarning)); - blackQQ = jInfo["fromQQ"]; - blackGroup = jInfo["fromGroup"]; - } - catch (...) { - return 0; - } - string type = readJKey(jInfo["type"]); - string time = readJKey(jInfo["time"]); - string note = readJKey(jInfo["note"]); - if (type != "ban" && type != "kick" || (!blackGroup||BlackGroup.count(blackGroup)) && (!blackQQ||BlackQQ.count(blackQQ))) { - return 1; - } - if (!isAdmin)sendAdmin("来自" + printQQ(fromQQ) + ":" + strWarning); - strWarning = "!warning" + strWarning; - if (blackGroup) { - BlackGroup.insert(blackGroup); - if(getGroupList().count(blackGroup)){ - if (blackGroup != fromGroup)AddMsgToQueue(strWarning, blackGroup, Group); - AdminNotify("已通知" + GlobalMsg["strSelfName"] + "将" + printGroup(blackGroup) + "加入群黑名单√"); - Sleep(100); - setGroupLeave(blackGroup); - } - } - if (blackQQ) { - AdminNotify("已通知" + GlobalMsg["strSelfName"] + "将" + printQQ(blackQQ) + "加入用户黑名单"); - addBlackQQ(blackQQ, note, strWarning); - } + AddWarning(readRest(), fromQQ, fromGroup); return 1; } else return 0; From 79d641585002f7ee610f8e9b8330ebf7760fb3a9 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sat, 13 Jul 2019 22:39:18 +0800 Subject: [PATCH 25/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E9=9D=99=E9=BB=98=E6=97=B6=E5=AF=B9bot=20on=E7=9A=84=E5=8F=8D?= =?UTF-8?q?=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鐜板湪涓嶄細鏈夊搷搴攂ot on鍗存病鍙嶅簲鐨勮糠鎯戣涓轰簡 --- Dice/DiceEvent.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 0669d687..8c66b188 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -667,7 +667,8 @@ class FromMsg { { if (Command == "on") { - if (fromType == Group) { + if (boolConsole["DisabledGlobal"])reply(GlobalMsg["strGlobalOff"]); + else if (fromType == Group) { if (isAuth) { if (DisabledGroup.count(fromGroup)) From c1da38d0c3c19720ae6cad891bb21fb2d94cc723 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sun, 14 Jul 2019 00:50:22 +0800 Subject: [PATCH 26/33] =?UTF-8?q?=E9=83=A8=E5=88=86=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A6=81=E7=94=A8=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鍙夌鐢ㄦ湭蹇呬細鐢ㄥ埌鐨.deck .draw .send --- Dice/DiceConsole.cpp | 3 ++- Dice/DiceEvent.h | 21 ++++++++++++++++----- Dice/GlobalVar.cpp | 3 +++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index a5831907..7014fc71 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -37,7 +37,8 @@ using namespace CQ; long long masterQQ = 0; set AdminQQ = {}; set MonitorList = {}; -std::mapboolConsole = { {"DisabledGlobal",false},{"DisabledMe",false},{"DisabledJrrp",false}, +std::mapboolConsole = { {"DisabledGlobal",false}, +{"DisabledMe",false},{"DisabledJrrp",false},{"DisabledDeck",true},{"DisabledDraw",false},{"DisabledSend",true}, {"Private",false},{"LeaveDiscuss",false}, {"LeaveBlackQQ",true},{"AllowStranger",true}, {"BannedBanOwner",true},{"BannedLeave",false},{"BannedBanInviter",true}, diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 8c66b188..f3bc015f 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -1131,6 +1131,11 @@ class FromMsg { return 1; } else if (strLowerMessage.substr(intMsgCnt, 4) == "deck") { + if (!isAdmin&&boolConsole["DisabledDeck"]) + { + reply(GlobalMsg["strDisabledDeckGlobal"]); + return 1; + } intMsgCnt += 4; readSkipSpace(); string strPara = readPara(); @@ -1258,6 +1263,11 @@ class FromMsg { } else if (strLowerMessage.substr(intMsgCnt, 4) == "draw") { + if (!isAdmin&&boolConsole["DisabledDraw"]) + { + reply(GlobalMsg["strDisabledDrawGlobal"]); + return 1; + } intMsgCnt += 4; while (isspace(static_cast(strLowerMessage[intMsgCnt]))) intMsgCnt++; @@ -1629,14 +1639,15 @@ class FromMsg { if (!masterQQ || !boolMasterMode) { reply(GlobalMsg["strSendMsgInvalid"]); } + else if (boolConsole["DisabledSend"]) { + reply(GlobalMsg["strDisabledSendGlobal"]); + } else if (intMsgCnt == strMsg.length()) { reply(GlobalMsg["strSendMsgEmpty"]); } else { - string strFwd = "来自"; - if (fromType == Group)strFwd += "群(" + to_string(fromGroup) + ")"; - if (fromType == Discuss)strFwd += "讨论组(" + to_string(fromGroup) + ")"; - strFwd += getStrangerInfo(fromQQ).nick + "(" + to_string(fromQQ) + "):"; + string strFwd = "来自" + printChat(fromChat); + if (fromType == Private)strFwd += printQQ(fromQQ); if (masterQQ == fromQQ)strFwd.clear(); strFwd += readRest(); sendAdmin(strFwd); @@ -1916,7 +1927,7 @@ class FromMsg { } else if (strLowerMessage.substr(intMsgCnt, 2) == "me") { - if (boolConsole["DisabledMe"]) + if (!isAdmin&&boolConsole["DisabledMe"]) { reply(GlobalMsg["strDisabledMeGlobal"]); return 1; diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index 33e6e9ff..fd56da31 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -171,6 +171,9 @@ std::map GlobalMsg {"strMEDisabledErr", "管理员已在此群中禁用.me命令!"}, {"strDisabledMeGlobal", "恕不提供.me服务×"}, {"strDisabledJrrpGlobal", "恕不提供.jrrp服务×"}, + {"strDisabledDeckGlobal", "恕不提供.deck服务×"}, + {"strDisabledDrawGlobal", "恕不提供.draw服务×"}, + {"strDisabledSendGlobal", "恕不提供.send服务×"}, {"strHELPDisabledErr", "管理员已在此群中禁用.help命令!"}, {"strNameDelErr", "没有设置名称,无法删除!"}, {"strValueErr", "掷骰表达式输入错误!"}, From 370963b42589918a6afda6292a0c0e6cbc0209df Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sun, 14 Jul 2019 01:10:00 +0800 Subject: [PATCH 27/33] =?UTF-8?q?=E5=9B=9E=E9=80=80=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=9A=84=E9=87=8D=E5=AE=9A=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/DiceUpdate.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dice/DiceUpdate.cpp b/Dice/DiceUpdate.cpp index 81e0e34e..e7664b78 100644 --- a/Dice/DiceUpdate.cpp +++ b/Dice/DiceUpdate.cpp @@ -32,7 +32,8 @@ EVE_Menu(eventDiceUpdate) { std::string ver; - if (!Network::GET("api.kokona.tech", "/getExpVer", 5555, ver) && !Network::GET("shiki.stringempty.xyz", "/DiceVer", 80, ver)) { + //if (!Network::GET("api.kokona.tech", "/getExpVer", 5555, ver) && !Network::GET("shiki.stringempty.xyz", "/DiceVer", 80, ver)) { + if (!Network::GET("shiki.stringempty.xyz", "/DiceVer", 80, ver)) { MessageBoxA(nullptr, ("检查更新时遇到错误: \n" + ver).c_str(), "Dice!更新错误", MB_OK | MB_ICONWARNING); return -1; } @@ -66,7 +67,8 @@ EVE_Menu(eventDiceUpdate) filePath = filePath.substr(0, filePath.find_last_of("\\")) + "\\app\\com.w4123.dice.cpk"; std::string fileContent; - if (!Network::GET("api.kokona.tech", "/getExpDice", 5555, fileContent) && !Network::GET("shiki.stringempty.xyz", "/download/com.w4123.dice.cpk", 80, fileContent)) + //if (!Network::GET("api.kokona.tech", "/getExpDice", 5555, fileContent) && !Network::GET("shiki.stringempty.xyz", "/download/com.w4123.dice.cpk", 80, fileContent)) + if (!Network::GET("shiki.stringempty.xyz", "/download/com.w4123.dice.cpk", 80, fileContent)) { MessageBoxA(nullptr, ("新版本文件下载失败! 请检查您的网络状态! 错误信息: " + fileContent).c_str(), "Dice!更新错误", MB_OK | MB_ICONERROR); return -1; From 2b3f8dd01f7770579ae49741de040f1c7678c340 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Sun, 14 Jul 2019 01:13:46 +0800 Subject: [PATCH 28/33] Update547 --- Dice/GlobalVar.cpp | 4 ++-- Dice/app.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index fd56da31..9cd99ad9 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -35,7 +35,7 @@ CQ::logger DiceLogger("Dice!"); * 请勿修改Dice_Build, Dice_Ver_Without_Build,DiceRequestHeader以及Dice_Ver常量 * 请修改Dice_Short_Ver或Dice_Full_Ver常量以达到版本自定义 */ -const unsigned short Dice_Build = 546; +const unsigned short Dice_Build = 547; const std::string Dice_Ver_Without_Build = "2.3.8Express8"; const std::string DiceRequestHeader = "Dice/2.3.8"; const std::string Dice_Ver = Dice_Ver_Without_Build + "(" + std::to_string(Dice_Build) + ")"; @@ -252,7 +252,7 @@ std::map GlobalMsg std::map EditedMsg; std::map HelpDoc = { -{"更新","546:完善骰娘列表体验\n545:开放自定义deck\n544:后台管理更新\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, +{"更新","547:更新指令开关\n546:完善骰娘列表体验\n545:开放自定义deck\n544:后台管理更新\n543:允许.st输入变化值\n542:新增.deck功能\n541:后台管理大修,允许同意好友\n540:预定义回执文本\n539:优化表达,加入骰池计数\n537:更新.send功能\n535:新增了可变成长检定功能"}, {"协议","0.本协议是Shiki(Death、Judgement、The World)的服务协议。如果你看到了这句话,意味着Master应用默认协议,请注意。\n1.邀请骰娘、使用掷骰服务和在群内阅读此协议视为同意并承诺遵守此协议,否则请使用.dismiss移出骰娘。\n2.不允许禁言、移出骰娘或刷屏掷骰等对骰娘的不友善行为,这些行为将会提高骰娘被制裁的风险。开关骰娘响应请使用.bot on/off。\n3.骰娘默认邀请行为已事先得到群内同意,因而会自动同意群邀请。因擅自邀请而使骰娘遭遇不友善行为时,邀请者因未履行预见义务而将承担连带责任。\n4.禁止将骰娘用于赌博及其他违法犯罪行为。\n5.对于设置敏感昵称等无法预见但有可能招致言论审查的行为,骰娘可能会出于自我保护而拒绝提供服务\n6.由于技术以及资金原因,我们无法保证机器人100%的时间稳定运行,可能不定时停机维护或遭遇冻结,但是相应情况会及时通过各种渠道进行通知,敬请谅解。临时停机的骰娘不会有任何响应,故而不会影响群内活动,此状态下仍然禁止不友善行为。\n7.对于违反协议的行为,骰娘将视情况终止对用户和所在群提供服务,并将不良记录共享给其他服务提供方。黑名单相关事宜可以与服务提供方协商,但最终裁定权在服务提供方。\n8.本协议内容随时有可能改动。请注意帮助信息、签名、空间、官方群等处的骰娘动态。\n9.骰娘提供掷骰服务是完全免费的,欢迎投食。\n10.本服务最终解释权归服务提供方所有。"}, {"链接","查看源码:https://github.com/w4123/Dice/tree/Shiki\n插件下载:https://github.com/w4123/Dice/releases\n官方文档:https://www.stringempty.xyz\n跑团记录着色器:https://logpainter.kokona.tech"}, {"设定","Master:()\n.me使用:禁止\n.jrrp使用:允许\n邀请处理:黑名单制,非禁即入\n讨论组使用:允许\n移出反制:拉黑群和操作者\n禁言反制:默认拉黑群和群主\n刷屏反制:警告\n邀请人责任:有限连带\n窥屏可能:有\n其他插件:无\n官方群:941980833\n私骰群:192499947"}, diff --git a/Dice/app.json b/Dice/app.json index 2fedafff..62341ff8 100644 --- a/Dice/app.json +++ b/Dice/app.json @@ -3,7 +3,7 @@ "apiver": 9, "name": "Dice!", "version": "2.3.8Express8", - "version_id": 546, + "version_id": 547, "author": "w4123婧磩 Shiki", "description": "璺戝洟鐢ㄩ瀛 鏈▼搴忎娇鐢ˋGPLv3寮婧愬崗璁巿鏉 Copyright (c) 2018-2019 w4123婧磩 Shiki", "event": [ From 677451dd0e150e79d9d2b0bf00d22718ae99241e Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 16 Jul 2019 12:37:34 +0800 Subject: [PATCH 29/33] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8B=89=E9=BB=91?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E9=80=9A=E7=9F=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/DiceConsole.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 7014fc71..59b88f5e 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -236,16 +236,18 @@ void warningHandler() { string strWarning = "!warning" + warning.strMsg; if (warning.fromQQ != masterQQ || !AdminQQ.count(warning.fromQQ))sendAdmin("来自" + printQQ(warning.fromQQ) + strWarning); if (blackGroup) { - BlackGroup.insert(blackGroup); + if (!BlackGroup.count(blackGroup)) { + BlackGroup.insert(blackGroup); + sendAdmin("已通知" + GlobalMsg["strSelfName"] + "将" + printGroup(blackGroup) + "加入群黑名单√", warning.fromQQ); + } if (getGroupList().count(blackGroup)) { if (blackGroup != warning.fromGroup)AddMsgToQueue(strWarning, blackGroup, Group); setGroupLeave(blackGroup); } - sendAdmin("已通知" + GlobalMsg["strSelfName"] + "将" + printGroup(blackGroup) + "加入群黑名单√", warning.fromQQ); } if (blackQQ) { + if (!BlackQQ.count(blackQQ))sendAdmin("已通知" + GlobalMsg["strSelfName"] + "将" + printQQ(blackQQ) + "加入用户黑名单", warning.fromQQ); addBlackQQ(blackQQ, note, strWarning); - sendAdmin("已通知" + GlobalMsg["strSelfName"] + "将" + printQQ(blackQQ) + "加入用户黑名单", warning.fromQQ); } } else From ef570efa936ce15712d390ebbf4b3578e4132571 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 17 Jul 2019 21:30:10 +0800 Subject: [PATCH 30/33] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E5=9B=9E?= =?UTF-8?q?=E5=A4=8D=E8=8D=89=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dice/CardDeck.cpp | 21 ++++++++++---------- Dice/CardDeck.h | 1 + Dice/Dice.cpp | 2 ++ Dice/DiceEvent.h | 49 ++++++++++++++++++++++++++++++++++++++++------ Dice/GlobalVar.cpp | 3 +++ 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Dice/CardDeck.cpp b/Dice/CardDeck.cpp index a303eaf1..857e89e0 100644 --- a/Dice/CardDeck.cpp +++ b/Dice/CardDeck.cpp @@ -26,7 +26,7 @@ namespace CardDeck {"英雄天赋",{"肉体天赋1 明察秋毫 进行侦查检定时获得一个奖励骰。","肉体天赋2 快速愈合 自然回复增加至每日3HP。","肉体天赋3 昏暗视觉 降低夜间侦查检定的难度等级,忽略在夜间射击时的惩罚骰。","肉体天赋4 耐力卓绝 进行体质检定时获得一个奖励骰,包括建立追逐时。","肉体天赋5 天生神力 进行力量检定时获得一个奖励骰,比如用来举起某人某物。","肉体天赋6 千杯不醉 可以花费5点幸运来避免过度饮酒带来的效果(无视技能惩罚)。","肉体天赋7 强健体魄 可以花费10点幸运使疾病和毒药的伤害和效果减半。","肉体天赋8 铁骨铮铮 可以花费10点幸运来吸收在一轮中收到的5点伤害。","肉体天赋9 耳听八方 进行聆听检定时获得一个奖励骰。","肉体天赋10 魅力四射 进行魅惑检定时获得一个奖励骰。","精神天赋1 坚定不移 无视攻击人类、目睹惨烈创伤或尸体的理智损失。","精神天赋2 百折不挠 可以花费幸运来避免等量的理智损失。","精神天赋3 钢铁意志 进行意志检定时获得一个奖励骰。","精神天赋4 一目十行 阅读书籍和神话典籍时,泛读和精读花费的时间减半。","精神天赋5 语言学家 可以了解遇到的是哪种语言或文字;进行语言检定时获得一个奖励骰。","精神天赋6 魔法亲和 学习法术花费的时间减半;进行施法检定时获得一个奖励骰。","精神天赋7 过目不忘 能够记住事件的诸多细节;进行知识(教育)检定时获得一个奖励骰。","精神天赋8 博学多才 获得学问技能的一个专攻项,如梦境学问、吸血鬼学问、狼人学问;需要向该技能分配职业或兴趣点数。","精神天赋9 灵能觉醒 获得一项灵能,如通灵、占卜、灵媒、心灵感应、念动力,见第六章;需要向该技能分配职业或兴趣点数。","精神天赋10 足智多谋 能够迅速整理线索;进行智力(不是灵感)检定时获得一个奖励骰。","战斗天赋1 处变不惊 不会被突袭。","战斗天赋2 专注打击 在格斗中,可以花费10点幸运来获得额外伤害骰,数量取决于所用武器。如徒手攻击+1D3,剑+1D6。","战斗天赋3 快速装填 选择一种武器,忽略使用该武器在同一回合装填并击发产生的惩罚骰。","战斗天赋4 身手敏捷 应对枪械而寻找掩体时,不会失去攻击机会。","战斗天赋5 目光如炬 忽略瞄准体型较小目标(体格-2)时产生的惩罚骰;忽略瞄准近战中的目标时产生的惩罚骰。","战斗天赋6 技巧卓绝 使用战技时,角色的体格视为+1。","战斗天赋7 疾风连击 在格斗中,可以花费10点幸运再进行一次攻击。","战斗天赋8 动如脱兔 在一整场战斗中,可以花费10点幸运来避免寡不敌众。","战斗天赋9 快速瞄准 决定回合轮次时,即使未准备好进行射击,亦视为获得+50DEX。","战斗天赋10 手枪专精 忽略手枪连射带来的惩罚骰。","其他天赋1 凶神恶煞 进行恐吓检定时降低一级难度等级,或者获得一个奖励骰,由守秘人判断。","其他天赋2 奇妙道具 游戏开始时获得一个奇妙道具,见怪奇技术。","其他天赋3 吉人天相 回复幸运时,额外投一个1D10。","其他天赋4 神话知识 游戏开始时获得10点克苏鲁神话技能。","其他天赋5 怪奇技术 可以制造和修理怪奇技术制品,见怪奇技术。","其他天赋6 遁入暗影 进行潜行检定时降低一级难度等级,或者获得一个奖励骰,由守秘人判断。如果目标未能察觉,在暴露之前可以进行两次突袭。","其他天赋7 能工巧匠 进行操作重型机械、机械维修和电气维修检定时降低一级难度等级,或者获得一个奖励骰,由守秘人判断。","其他天赋8 动物朋友 游戏开始时获得一只可靠的动物伙伴,比如猫、狗、鹦鹉;进行驯兽检定时获得一个奖励骰。","其他天赋9 伪装大师 进行乔装或技艺(表演)检定时,可以花费10点幸运来获得一个奖励骰;可以使用腹语,让声音听起来是从别处发出的;如果有人试图看穿伪装,其侦查或心理学检定提升为困难难度。","其他天赋10 早有准备 需要的东西似乎总在手边;可以花费10点幸运(而非幸运检定)在附近找到有用的道具,如手电筒、够长的绳索、武器等。"}}, {"调查员职业",{"会计师","杂技演员","演员-戏剧演员","演员-电影演员","事务所侦探、保安","精神病医生(古典)","动物训练师","文物学家(原作向)","古董商","考古学家(原作向)","建筑师","艺术家","精神病院看护","运动员","作家(原作向)","酒保","猎人","书商","赏金猎人","拳击手、摔跤手","管家、男仆、女仆","神职人员","程序员、电子工程师(现代)","黑客/骇客(现代)","牛仔","工匠","罪犯-刺客","罪犯-银行劫匪","罪犯-打手、暴徒","罪犯-窃贼","罪犯-欺诈师","罪犯-独行罪犯","罪犯-女飞贼(古典)","罪犯-赃物贩子","罪犯-赝造者","罪犯-走私者","罪犯-混混","教团首领","除魅师(现代)","设计师","业余艺术爱好者(原作向)","潜水员","医生(原作向)","流浪者","司机-私人司机","司机-司机","司机-出租车司机","编辑","政府官员","工程师","艺人","探险家(古典)","农民","联邦探员","消防员","驻外记者","法医","赌徒","黑帮-黑帮老大","黑帮-马仔","绅士、淑女","游民","勤杂护工","记者(原作向)-调查记者","记者(原作向)-通讯记者","法官","实验室助理","工人-非熟练工人","工人-伐木工","工人-矿工","律师","图书馆管理员(原作向)","技师","军官","传教士","登山家","博物馆管理员","音乐家","护士","神秘学家","旅行家","超心理学家","药剂师","摄影师-摄影师","摄影师-摄影记者","飞行员-飞行员","飞行员-特技飞行员(古典)","警方(原作向)-警探","警方(原作向)-巡警","私家侦探","教授(原作向)","淘金客","性工作者","精神病学家","心理学家、精神分析学家","研究员","海员-军舰海员","海员-民船海员","推销员","科学家","秘书","店老板","士兵、海军陆战队士兵","间谍","学生、实习生","替身演员","部落成员","殡葬师","工会活动家","服务生","白领工人-职员、主管","白领工人-中高层管理人员","狂热者","饲养员"}}, {"调查员背景",{"个人描述:{个人描述}、{个人描述}、{个人描述}\n思想信念:{思想信念}\n重要之人:{重要之人}\n重要之人理由:{重要之人理由}\n意义非凡之地:{意义非凡之地}\n宝贵之物:{宝贵之物}\n特点:{调查员特点}"}}, - {"煤气灯",{"任意选择一个有(D)记号的特征。","高龄(D):年龄追加[1D3*10+10]岁,参照6版标准规则,超过30岁后开始获得EDU加值,40岁以后开始对于身体属性造成减值。","优雅的岁数: 40岁开始对身体能力造成减值的规则改为从50岁开始。","白化病患者(D):STR,CON,SIZ,DEX,POW,APP中的任意一项减少3点。在明亮阳光下时【侦察】技能值减少[1D4-1]点,长时间受到光照的话会受到1点以上的HP伤害。白化病人在人群中很显眼并可能被他人用有色目光看待。","酒精中毒(D):CON-1。STR,DEX,POW,APP中任意一项减少1点。为了避免陷入酩酊大醉需要通过一个SAN CHECK。陷入疯狂的情况下,调查员可能会寻求酒精来逃避现实。","警戒:不易被惊吓到。潜伏时一直都保持着能够随时【侦察】或者【聆听】的状态。","同盟者:投掷一个D100=[d100]来决定同盟的力量/数量和出现的频率(D100的出点越大可能能够获得越有利的同盟)。用途不限。","双手灵活:调查员可以灵活的使用他的任意一只手而不会受到非惯用手的惩罚。","讨厌动物(D):技能和动物有关时技能成功率减少[1D6*5]点。","艺术天才:音乐,写作之类的艺术技能增加【INT*5】%。","运动:运动系技能获得加值=选择一个技能+30%,或者选择两个技能各+20%,或者选择三个技能各+10%。","夜视强化:日落西山后视觉相关惩罚只有常人的一半。","累赘(D):调查员出生于世家但是却没能达到家人的期待,或者不服管教。对于交涉系技能可能会造成影响而减少[1D3*10]%。","领导者资质:POW+[1D2],交涉系技能+【INT】*5%。","打斗者:【拳击】或者【擒拿】+[1D4*5]%,每回合可以进行两次【拳击】或者【擒拿】,攻击成功时+1点伤害。","笨拙(D):大失败的几率变成通常的2倍,并且大失败时可能会招致灾难。","收藏家:调查员有收集硬币,书,昆虫,艺术作品,宝石,古董之类的爱好。","身体障碍(D):失去了身体的一部分。投掷一个D6=[d6]。1~2=脚,3~4=手,5=头部(投掷D6=[d6],1~3=眼睛,4~6=耳朵),6=玩家自己选择。失去脚的话DEX-3,STR或者CON-1,MOVE只有常人的一半,所有运动系技能-25%。失去手腕的话STR-1,DEX-2,所有的操作系技能-15%,使用武器会受到限制。失去眼睛的话【侦察】和火器技能等全部-35%,另外投掷一个【幸运】,失败的话APP-[1D2]。失去耳朵的话APP-[1D3],【聆听】等和耳朵有关的技能全部-30%。","再投掷三次,由玩家选择其中一个作为特征。","再投掷三次,玩家和KP各选择一个特征。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","诅咒(D):调查员被吉普赛人,魔女,法师,外国原住民等施予了诅咒,诅咒效果等同【邪眼】咒文或者由KP决定。KP也可以决定解除诅咒的条件。","黑暗先祖(D):调查员具有邪恶的一族,外国人,食人族,甚至神话生物的血统。投掷一个D100=[d100],出点越大,血统也越可怖。","听觉障碍(D):【聆听】减少[1D4*5]%。","绝症缠身(D):调查员身患绝症(癌症,失明,梅毒,结核等),绝症对调查员造成恶劣影响,至少也失去了1点CON,如果病情继续恶化的话还会继续失去其他能力值。投掷一个D100=[d100]来决定剩余寿命,出点越大寿命越长。","钟楼怪人(D):调查员具有巨大的伤痕或者身体变形等特征,对APP造成至少减少[1D4]点影响。对交涉系技能也可能也造成影响【(失去的APP)*5%】。","酒豪:不易喝醉。酒精作为毒素处理的情况下, POT值只有他人的一半。","鹰眼:【侦察】增加[2D3*5]%。","敌人(D):有对调查员不利的敌人存在,投掷一个D100=[d100]来决定敌人的力量/数量,数值越大越恶劣。用途不限。","擅长武器:火器类射程+50%。近战类武器成功率+5%或者伤害增加[1D2]。并且武器不易被破坏(具有更多的耐久度),或者入手的武器具有比一般的武器更高的品质。","传家宝:调查员拥有绘画,书籍,武器,家具等具有高价值的宝物。也可能是模组中追加的宝物的持有人。","俊足:DEX+1。再投掷一个D6=[d6],1~4时MOVE+1,5~6时MOVE+2。","赌徒(D?):进行一次【幸运】鉴定。成功的话调查员获得【(INT+POW)*2】%的【赌博】技能。失败的话只有【INT或者POW*1】%的技能值,资产减少[1D6*10]%,并且调查员遇到赌博时需要通过一个SAN CHECK才能克制自己。","擅长料理:获得【(INT或者EDU)*5】%的【手艺(料理)】技能。","听力良好:【聆听】+[2D3*5]%。","洞察人心:【心理学】+ [2D3*5]%。","反应灵敏:投掷1D6=[d6]。1~3=DEX+1,4~5=DEX+2,6=DEX+3。","驱使动物:技能和动物有关时获得[1D6*5+5]的加值,例如骑马,驾驶马车,特定情况的藏匿,潜行等。","没有特征但是可以选择任意技能(可多选)获得总计[3D20]点技能加值。","玩家自己选择一个特征。","再投掷三次,玩家和KP各选择一个。","贪婪(D):对调查员来说金钱至上。任何状况下都优先考虑金钱。为此欺骗他人也是正常的,欺骗对象也包含其他调查员。","悲叹人生:SAN-[1D10],玩家和KP给调查员设定一个背景(失去爱人,子孙或者其他血亲的悲剧)。","憎恶(D):玩家和KP商议决定,调查员对于特定的国籍,人种或者宗教具有无理由的反感。调查员接触此类人群时会表现出敌意。","比马还要健壮:CON+[1D3]。","快乐主义者:追求个人的喜悦(美食,饮品,性,衣装,音乐,家具等)。为此浪费了[1D4*10+20]%的资产。通过一个【幸运】鉴定,失败的话因为这种放纵的生活而失去1点STR,CON,INT,POW,DEX或者APP。","骑手:[骑马]技能+[(1D6+1)*10]%。","易冲动(D):有不考虑后果轻率的行动的倾向。根据情况可能需要通过一个减半的【灵感】鉴定来使头脑冷静。","巧妙:二选一。A)【灵感】+10%,获得可以临时组装或者发明一些装置的能力。B)武器以外的操纵系技能获得加值,只选择一个技能的话+30%,选择2个技能各+20%,3个各+10%。","疯狂(D):SAN-[1D8]。玩家和KP商议给予调查员一个精神障碍。","土地勘测员:调查员对某一篇地域了解的非常详细(例:建筑配置,道路,商业,住民,历史等)。对应的区域应为都市某一块区域或者单个农村之类的较狭小的范围。对于这篇区域的详细情况调查员通过【知识】或者【灵感】鉴定即可知晓。","意志顽强:POW+[1D3],san也获得对应的上升。","花花公子:APP+[1D3],和异性交往有关的交涉技能+[1D3*10]%。","持有高额财产:调查员拥有某种具有巨大价值的东西(例:船只,工厂,房屋,矿山,大块的土地等)。这些东西可能需要调查员花费很大的时间和精力在这里,玩家和KP要慎重的决定。","语言学家:调查员即使语言不通也有可能和对象成功的交流,增加一个辅助技能【语言学家】,初期技能值为【INT或者EDU】*1%。","家人失踪:调查员有着失踪很久的家人,有可能会在模组中登场(例:兄弟/姐妹/或者其他亲人遭遇海难,死在海外,被其他亲戚带走等情况)。","忠诚:调查员不会抛弃自己的家人,朋友,伙伴,在力所能及的范围内一定会帮助他们。这种性格也使他和自己周围的人群交涉时获得10%的加值。","魔术素质:学习咒文时只需要正常的一半时间,成功率也增加【INT*1】%。","虽然没有特侦但是职业技能值获得额外的[3D20]的技能点。","玩家自己选择一个特征。","虽然没有特征,但是调查员的持有现金为通常规则的2倍。","魔术道具:KP可以给予调查员一个魔术道具(可以杀伤神话生物的附魔武器,召唤神话生物的专用道具,占卜用品,POW储藏器等等)。调查员如果想要知道这件道具的详细性质需要通过一个【POW*1】的鉴定。","射击名人(手枪,步枪以及霰弹枪中选择一项):选择的这项火器技能+[2D3*5]%。","认错人:调查员被频繁的被误认为其他人,通常都会是些有着恶评的人物(罪犯,身怀丑闻的恶人之类的)。模组中在合适的情况下【幸运】可能会被降为原本的一半(简单来说,调查员因为某些理由获得其他人的犯罪历史,恶名,通过诈骗获得的财富或者权力这样的身份或者特征)。","天气预报:通过一个【灵感】鉴定调查员就可以得知[1D6+1]小时里的正确天气情况。有多大的降雨量,下雨的场所,风级,持续时间等等。","对外观的强迫观念(D):APP+1,但是调查员为了让自己看起来亮丽动人而花费大量的金钱来购买华贵的服饰和饰物。储蓄和资产减半。","古书:调查员拥有和模组有关的重要书籍资料或者它的复印(例:杂志,黑魔术书籍,历史书,圣经,神话魔导书,地图等等)。KP可以决定这件道具的性质和价值。","试炼生还者(D):SAN-[1D6]。调查员拥有从恐怖环境中生还的经验(海难,战争,恐怖分子劫持,地震等等)。因为这个经历可能给调查员带来某种长久的影响(通常程度的恐怖症状,或者其他的精神障碍等)。","孤儿:调查员相依为命的家人都不在了,或者不知道自己真正的家人是谁。","其他语言:调查员可以追加获得一项其他语言技能。技能值为[1D4]*INT%。","野外活动爱好者:【导航】,【自然史】,【追踪】各增加[2D3*5+5]%、[2D3*5+5]%、[2D3*5+5]%。","寄托爱意:模组中登场的某位角色对调查员怀有憧憬。由KP决定是哪位角色,为什么以及怀有何种程度。","心怀爱意(D):调查员对其他角色怀有憧憬。由KP决定喜欢谁,为什么以及何种程度。","麻痹(D):调查员因精神,疾病等原因苦于身体抽搐,扭曲等症状。各鉴定一次【幸运】,失败的话减少[1D2]点DEX和1点APP。","超常现象经历:调查员曾经经历过难以说明的遭遇(幽灵,黑魔术,神话生物,超能力等)。玩家和KP讨论决定其内容并失去最多[1D6]点SAN值。","大肚子(D):这位调查员怎么说也太胖了点。鉴定一次【幸运】,失败的话投掷一个D6=[d6],1~3 CON-1,4~6 APP-1。","说服力:【劝说】+[2D3*5+5]%。","宠物:调查员有养狗,猫或者鸟类。","虽然没有特征但是任意技能获得[3D20]点技能点。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","虽然没有特征但是职业技能值额外获得[3D20]点技能点。","恐怖症/疯狂(D):调查员身患恐怖症状或者疯狂症状。参考6版标准规则随机决定症状,或者选择想要的症状。遭遇到自身症状根源的恐怖或者物品时,如果SAN CHECK失败,那么调查员将无法抑制自己的恐怖或者被魅惑。","权力/阶级/企业地位:调查员在政治,经济或者甚至军事环境里持有某种程度的权力。投掷D100=[d100],出点越大权力越大。企业地位影响融资,政治地位可能所属某种政府机关,军队地位远超本身拥有的军衔也说不定。【信用】+25%。详细的情况和KP商议决定。","以前的经验:玩家可以选择获得【(INT或者EDU)*5】%的职业技能点数。","预知梦:由KP决定,游戏中玩家会做一个预言未来的梦。这大概会需要一个【POW*3】的鉴定。梦境没有必须符合现实的必要,如果梦境中见到的景象十分恐怖的话那么会失去一些SAN值(现实中见到相同景象失去SAN值的10%左右)。鉴定失败的话玩家会获得错误的预言。","繁荣:调查员的年收入和资产变成2倍。[信用]增加[1D4*5]%。调查员的事业很成功,或者调查员给富翁,持有权力的人做事或者与他们共事。","心理测量:接触某些物体时(或者抵达某个地方时),通过一个POW*1的鉴定,成功的话可以窥视到这个物品/地方的过去。这个能力的正确度由KP决定。这个能力消耗1D6点MP。因为幻觉也可能失去SAN值(和上述的”预知梦”类似,损失通常的10%左右)。","健谈者:【快读交谈】+[2D4*5]%。调查员有着非常厉害的语言术,可以通过讲故事获得朋友的信任,降低敌人的敌意,赚到一顿免费的餐点也是可能的。","罕见的技能:调查员通过一个【INT*4】%的鉴定的话,可能会持有一些生活中完全不常见,或者一般来说不会有的技能。罕见的语言,格斗技,驾驶热气球之类,和KP商议决定。","红发:调查员有着一头好像燃烧着一般的红发,非常显眼(没有其他效果)。","评价(D?):鉴定一次【幸运】。成功的话调查员被人尊敬(设定其理由),调查员在自家所在的村子/都市中所有的交涉系技能获得15%的加值。【幸运】失败的话调查员获得极坏的评价,所有的交涉系技能-15%。KP也可以决定通过良好的业绩来抵消这个恶评。","报复追求者:调查员相信自己受到了不公正的待遇并且对导致自己受到这种恶意的对象进行报复行为。玩家和KP讨论决定敌人的真身。投掷一个D100=[D100]来决定敌人的强度和调查员受到这种不公正的程度。","伤痕:鉴定一次【幸运】。成功的话伤痕没有影响调查员的外观,甚至彰显其英勇也说不定。失败的话失去[1D3]点APP,交涉系技能也减少[1D3*5]%。","科学的精神:【灵感】+5%。并且选择一个思考类技能+30%并再选择2个思考系技能+20%或者所有其他思考系技能+10%。","秘密(D?):调查员有着决不能告诉别人的秘密。调查员的邻居可能会有些线索也说不定。调查员可能是个罪犯,间谍,或者卖国贼之类的也说不定。内容由玩家和KP商议决定。","秘密结社:调查员所属于秘密主义的团体,可能会是共济会,蔷薇十字团,神志主义者,炼金术师结社,光明会之类团体的一员。或者是地下医学研究者之类的犯罪/阴谋组织的一员。","自学:EDU+[1D3],并增加因此获得的技能值。","可疑的过去/绯闻(D):调查员过去曾经做过一些惹人怀疑的事情(卖淫,偷人等),或者曾经犯下过某些重大罪行。所有的交涉系技能减少[1D3*10]%。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","再投掷两次并获得那两个特征。","投掷三次,玩家和KP各选择一个特征。","病弱(D):CON-[1D3]。","巧妙的手法:[钳工]技能增加【DEX*5】%,可以在偷窃或者魔术的时候使用。","迟缓(D):MOVE-1。","失去名誉(D):探索者因为国籍,性别,人种,宗教或者过去的犯罪记录等原因失去了社会上的名誉地位。作为其影响,调查员可能减少自由活动时间甚至所有的交涉系技能减少[1D4*10]%甚至更多。具体的影响玩家和KP商议决定。","元军人:调查员获得【INT*5】点的技能点加到士兵的职业技能上。","咒文知识:由KP决定!调查员最多可以获知[1D3]种咒文。SAN值减少[1D6]点。","胆小(D):调查员见到血液或者流血就会感觉到身体不适,失去更多的SAN值。也可能因为疾病的原因无法靠近或通过流血现场。","坚毅:调查员不受到现实中的血迹或者流血的影响。遭遇血迹和流血时SAN损失为最小值,即使见到最残虐的场合(大量被撕裂的人,被猎奇杀死的尸体等)也最多只减少通常的一半。","比公牛还要强韧:STR+[1D3]。","迷信(D):调查员迷信不疑,依赖着护身符,仪式或者愚蠢的信念。遭遇超自然现象的时候比通常多损失1点SAN值,即使原本不损失的情况下可能变成损失1点。","同情心:调查员选择一个交涉系技能+30%或者选择两个各+20%,然后额外再选择一个+10%。","意外的帮手:调查员因为一些缘由拥有一个对自己忠实并帮助自己的协助者。KP来决定这个协助者的真身和影响(依旧可以D100来决定)。并且D100也决定其频率。","看不见的财产:调查员有一笔自己不知道的财产。这可能是亲人遗赠的或者理事会之类授予的。这可能会是一块土地,房屋或者事业。这依旧可以用D100来决定去价值程度。","虚弱(D):STR-[1D3]。","戴眼镜(D):调查员要看清东西必须戴眼镜。鉴定一个【幸运】,成功的话眼镜只在读书或者进行精细工作的时候才需要。失败的话会在激烈运动等情况时会感觉到不能自由行动。不戴眼镜的话和视觉关联的技能减少[1D3*10]%(这个惩罚即使幸运成功也一样)。","彬彬有礼:调查员的【信用】+10%,真是个有礼貌的绅士(淑女)。","孩子(D):调查员的年龄变成[10+2D3]岁。最大EDU变成【年龄的1/2+2】,DEX+1,STR,CON,APP中任意一项+1。玩家和KP商议决定,调查员大概依旧和家人住在一起,职业等也需要重新修正。","任意选择一项特征。","投掷两次,玩家任意选择其中一项特征。"}}, + {"煤气灯",{"任意选择一个有(D)记号的特征。","高龄(D):年龄追加[1D3*10+10]岁,参照6版标准规则,超过30岁后开始获得EDU加值,40岁以后开始对于身体属性造成减值。","优雅的岁数: 40岁开始对身体能力造成减值的规则改为从50岁开始。","白化病患者(D):STR,CON,SIZ,DEX,POW,APP中的任意一项减少3点。在明亮阳光下时【侦察】技能值减少[1D4-1]点,长时间受到光照的话会受到1点以上的HP伤害。白化病人在人群中很显眼并可能被他人用有色目光看待。","酒精中毒(D):CON-1。STR,DEX,POW,APP中任意一项减少1点。为了避免陷入酩酊大醉需要通过一个SAN CHECK。陷入疯狂的情况下,调查员可能会寻求酒精来逃避现实。","警戒:不易被惊吓到。潜伏时一直都保持着能够随时【侦察】或者【聆听】的状态。","同盟者:投掷一个D100=[d100]来决定同盟的力量/数量和出现的频率(D100的出点越大可能能够获得越有利的同盟)。用途不限。","双手灵活:调查员可以灵活的使用他的任意一只手而不会受到非惯用手的惩罚。","讨厌动物(D):技能和动物有关时技能成功率减少[1D6*5]点。","艺术天才:音乐,写作之类的艺术技能增加【INT*5】%。","运动:运动系技能获得加值=选择一个技能+30%,或者选择两个技能各+20%,或者选择三个技能各+10%。","夜视强化:日落西山后视觉相关惩罚只有常人的一半。","累赘(D):调查员出生于世家但是却没能达到家人的期待,或者不服管教。对于交涉系技能可能会造成影响而减少[1D3*10]%。","领导者资质:POW+[1D2],交涉系技能+【INT】*5%。","打斗者:【拳击】或者【擒拿】+[1D4*5]%,每回合可以进行两次【拳击】或者【擒拿】,攻击成功时+1点伤害。","笨拙(D):大失败的几率变成通常的2倍,并且大失败时可能会招致灾难。","收藏家:调查员有收集硬币,书,昆虫,艺术作品,宝石,古董之类的爱好。","身体障碍(D):失去了身体的一部分。投掷一个D6=[d6]。1~2=脚,3~4=手,5=头部(投掷D6=[d6],1~3=眼睛,4~6=耳朵),6=玩家自己选择。失去脚的话DEX-3,STR或者CON-1,MOVE只有常人的一半,所有运动系技能-25%。失去手腕的话STR-1,DEX-2,所有的操作系技能-15%,使用武器会受到限制。失去眼睛的话【侦察】和火器技能等全部-35%,另外投掷一个【幸运】,失败的话APP-[1D2]。失去耳朵的话APP-[1D3],【聆听】等和耳朵有关的技能全部-30%。","再投掷三次,由玩家选择其中一个作为特征。","再投掷三次,玩家和KP各选择一个特征。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","诅咒(D):调查员被吉普赛人,魔女,法师,外国原住民等施予了诅咒,诅咒效果等同【邪眼】咒文或者由KP决定。KP也可以决定解除诅咒的条件。","黑暗先祖(D):调查员具有邪恶的一族,外国人,食人族,甚至神话生物的血统。投掷一个D100=[d100],出点越大,血统也越可怖。","听觉障碍(D):【聆听】减少[1D4*5]%。","绝症缠身(D):调查员身患绝症(癌症,失明,梅毒,结核等),绝症对调查员造成恶劣影响,至少也失去了1点CON,如果病情继续恶化的话还会继续失去其他能力值。投掷一个D100=[d100]来决定剩余寿命,出点越大寿命越长。","钟楼怪人(D):调查员具有巨大的伤痕或者身体变形等特征,对APP造成至少减少[1D4]点影响。对交涉系技能也可能也造成影响【(失去的APP)*5%】。","酒豪:不易喝醉。酒精作为毒素处理的情况下, POT值只有他人的一半。","鹰眼:【侦察】增加[2D3*5]%。","敌人(D):有对调查员不利的敌人存在,投掷一个D100=[d100]来决定敌人的力量/数量,数值越大越恶劣。用途不限。","擅长武器:火器类射程+50%。近战类武器成功率+5%或者伤害增加[1D2]。并且武器不易被破坏(具有更多的耐久度),或者入手的武器具有比一般的武器更高的品质。","传家宝:调查员拥有绘画,书籍,武器,家具等具有高价值的宝物。也可能是模组中追加的宝物的持有人。","俊足:DEX+1。再投掷一个D6=[d6],1~4时MOVE+1,5~6时MOVE+2。","赌徒(D?):进行一次【幸运】鉴定。成功的话调查员获得【(INT+POW)*2】%的【赌博】技能。失败的话只有【INT或者POW*1】%的技能值,资产减少[1D6*10]%,并且调查员遇到赌博时需要通过一个SAN CHECK才能克制自己。","擅长料理:获得【(INT或者EDU)*5】%的【手艺(料理)】技能。","听力良好:【聆听】+[2D3*5]%。","洞察人心:【心理学】+ [2D3*5]%。","反应灵敏:投掷1D6=[d6]。1~3=DEX+1,4~5=DEX+2,6=DEX+3。","驱使动物:技能和动物有关时获得[1D6*5+5]的加值,例如骑马,驾驶马车,特定情况的藏匿,潜行等。","没有特征但是可以选择任意技能(可多选)获得总计[3D20]点技能加值。","玩家自己选择一个特征。","再投掷三次,玩家和KP各选择一个。","贪婪(D):对调查员来说金钱至上。任何状况下都优先考虑金钱。为此欺骗他人也是正常的,欺骗对象也包含其他调查员。","悲叹人生:SAN-[1D10],玩家和KP给调查员设定一个背景(失去爱人,子孙或者其他血亲的悲剧)。","憎恶(D):玩家和KP商议决定,调查员对于特定的国籍,人种或者宗教具有无理由的反感。调查员接触此类人群时会表现出敌意。","比马还要健壮:CON+[1D3]。","快乐主义者:追求个人的喜悦(美食,饮品,性,衣装,音乐,家具等)。为此浪费了[1D4*10+20]%的资产。通过一个【幸运】鉴定,失败的话因为这种放纵的生活而失去1点STR,CON,INT,POW,DEX或者APP。","骑手:[骑马]技能+[(1D6+1)*10]%。","易冲动(D):有不考虑后果轻率的行动的倾向。根据情况可能需要通过一个减半的【灵感】鉴定来使头脑冷静。","巧妙:二选一。A)【灵感】+10%,获得可以临时组装或者发明一些装置的能力。B)武器以外的操纵系技能获得加值,只选择一个技能的话+30%,选择2个技能各+20%,3个各+10%。","疯狂(D):SAN-[1D8]。玩家和KP商议给予调查员一个精神障碍。","土地勘测员:调查员对某一篇地域了解的非常详细(例:建筑配置,道路,商业,住民,历史等)。对应的区域应为都市某一块区域或者单个农村之类的较狭小的范围。对于这篇区域的详细情况调查员通过【知识】或者【灵感】鉴定即可知晓。","意志顽强:POW+[1D3],san也获得对应的上升。","花花公子:APP+[1D3],和异性交往有关的交涉技能+[1D3*10]%。","持有高额财产:调查员拥有某种具有巨大价值的东西(例:船只,工厂,房屋,矿山,大块的土地等)。这些东西可能需要调查员花费很大的时间和精力在这里,玩家和KP要慎重的决定。","语言学家:调查员即使语言不通也有可能和对象成功的交流,增加一个辅助技能【语言学家】,初期技能值为【INT或者EDU】*1%。","家人失踪:调查员有着失踪很久的家人,有可能会在模组中登场(例:兄弟/姐妹/或者其他亲人遭遇海难,死在海外,被其他亲戚带走等情况)。","忠诚:调查员不会抛弃自己的家人,朋友,伙伴,在力所能及的范围内一定会帮助他们。这种性格也使他和自己周围的人群交涉时获得10%的加值。","魔术素质:学习咒文时只需要正常的一半时间,成功率也增加【INT*1】%。","虽然没有特侦但是职业技能值获得额外的[3D20]的技能点。","玩家自己选择一个特征。","虽然没有特征,但是调查员的持有现金为通常规则的2倍。","魔术道具:KP可以给予调查员一个魔术道具(可以杀伤神话生物的附魔武器,召唤神话生物的专用道具,占卜用品,POW储藏器等等)。调查员如果想要知道这件道具的详细性质需要通过一个【POW*1】的鉴定。","射击名人(手枪,步枪以及霰弹枪中选择一项):选择的这项火器技能+[2D3*5]%。","认错人:调查员被频繁的被误认为其他人,通常都会是些有着恶评的人物(罪犯,身怀丑闻的恶人之类的)。模组中在合适的情况下【幸运】可能会被降为原本的一半(简单来说,调查员因为某些理由获得其他人的犯罪历史,恶名,通过诈骗获得的财富或者权力这样的身份或者特征)。","天气预报:通过一个【灵感】鉴定调查员就可以得知[1D6+1]小时里的正确天气情况。有多大的降雨量,下雨的场所,风级,持续时间等等。","对外观的强迫观念(D):APP+1,但是调查员为了让自己看起来亮丽动人而花费大量的金钱来购买华贵的服饰和饰物。储蓄和资产减半。","古书:调查员拥有和模组有关的重要书籍资料或者它的复印(例:杂志,黑魔术书籍,历史书,圣经,神话魔导书,地图等等)。KP可以决定这件道具的性质和价值。","试炼生还者(D):SAN-[1D6]。调查员拥有从恐怖环境中生还的经验(海难,战争,恐怖分子劫持,地震等等)。因为这个经历可能给调查员带来某种长久的影响(通常程度的恐怖症状,或者其他的精神障碍等)。","孤儿:调查员相依为命的家人都不在了,或者不知道自己真正的家人是谁。","其他语言:调查员可以追加获得一项其他语言技能。技能值为[1D4]*INT%。","野外活动爱好者:【导航】,【自然史】,【追踪】各增加[2D3*5+5]%、[2D3*5+5]%、[2D3*5+5]%。","寄托爱意:模组中登场的某位角色对调查员怀有憧憬。由KP决定是哪位角色,为什么以及怀有何种程度。","心怀爱意(D):调查员对其他角色怀有憧憬。由KP决定喜欢谁,为什么以及何种程度。","麻痹(D):调查员因精神,疾病等原因苦于身体抽搐,扭曲等症状。各鉴定一次【幸运】,失败的话减少[1D2]点DEX和1点APP。","超常现象经历:调查员曾经经历过难以说明的遭遇(幽灵,黑魔术,神话生物,超能力等)。玩家和KP讨论决定其内容并失去最多[1D6]点SAN值。","大肚子(D):这位调查员怎么说也太胖了点。鉴定一次【幸运】,失败的话投掷一个D6=[d6],1~3 CON-1,4~6 APP-1。","说服力:【劝说】+[2D3*5+5]%。","宠物:调查员有养狗,猫或者鸟类。","虽然没有特征但是任意技能获得[3D20]点技能点。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","虽然没有特征但是职业技能值额外获得[3D20]点技能点。","恐怖症/疯狂(D):调查员身患恐怖症状或者疯狂症状。参考6版标准规则随机决定症状,或者选择想要的症状。遭遇到自身症状根源的恐怖或者物品时,如果SAN CHECK失败,那么调查员将无法抑制自己的恐怖或者被魅惑。","权力/阶级/企业地位:调查员在政治,经济或者甚至军事环境里持有某种程度的权力。投掷D100=[d100],出点越大权力越大。企业地位影响融资,政治地位可能所属某种政府机关,军队地位远超本身拥有的军衔也说不定。【信用】+25%。详细的情况和KP商议决定。","以前的经验:玩家可以选择获得【(INT或者EDU)*5】%的职业技能点数。","预知梦:由KP决定,游戏中玩家会做一个预言未来的梦。这大概会需要一个【POW*3】的鉴定。梦境没有必须符合现实的必要,如果梦境中见到的景象十分恐怖的话那么会失去一些SAN值(现实中见到相同景象失去SAN值的10%左右)。鉴定失败的话玩家会获得错误的预言。","繁荣:调查员的年收入和资产变成2倍。[信用]增加[1D4*5]%。调查员的事业很成功,或者调查员给富翁,持有权力的人做事或者与他们共事。","心理测量:接触某些物体时(或者抵达某个地方时),通过一个POW*1的鉴定,成功的话可以窥视到这个物品/地方的过去。这个能力的正确度由KP决定。这个能力消耗1D6点MP。因为幻觉也可能失去SAN值(和上述的”预知梦”类似,损失通常的10%左右)。","健谈者:【快读交谈】+[2D4*5]%。调查员有着非常厉害的语言术,可以通过讲故事获得朋友的信任,降低敌人的敌意,赚到一顿免费的餐点也是可能的。","罕见的技能:调查员通过一个【INT*4】%的鉴定的话,可能会持有一些生活中完全不常见,或者一般来说不会有的技能。罕见的语言,格斗技,驾驶热气球之类,和KP商议决定。","红发:调查员有着一头好像燃烧着一般的红发,非常显眼(没有其他效果)。","评价(D?):鉴定一次【幸运】。成功的话调查员被人尊敬(设定其理由),调查员在自家所在的村子/都市中所有的交涉系技能获得15%的加值。【幸运】失败的话调查员获得极坏的评价,所有的交涉系技能-15%。KP也可以决定通过良好的业绩来抵消这个恶评。","报复追求者:调查员相信自己受到了不公正的待遇并且对导致自己受到这种恶意的对象进行报复行为。玩家和KP讨论决定敌人的真身。投掷一个D100=[D100]来决定敌人的强度和调查员受到这种不公正的程度。","伤痕:鉴定一次【幸运】。成功的话伤痕没有影响调查员的外观,甚至彰显其英勇也说不定。失败的话失去[1D3]点APP,交涉系技能也减少[1D3*5]%。","科学的精神:【灵感】+5%。并且选择一个思考类技能+30%并再选择2个思考系技能+20%或者所有其他思考系技能+10%。","秘密(D?):调查员有着决不能告诉别人的秘密。调查员的邻居可能会有些线索也说不定。调查员可能是个罪犯,间谍,或者卖国贼之类的也说不定。内容由玩家和KP商议决定。","秘密结社:调查员所属于秘密主义的团体,可能会是共济会,蔷薇十字团,神志主义者,炼金术师结社,光明会之类团体的一员。或者是地下医学研究者之类的犯罪/阴谋组织的一员。","自学:EDU+[1D3],并增加因此获得的技能值。","可疑的过去/绯闻(D):调查员过去曾经做过一些惹人怀疑的事情(卖淫,偷人等),或者曾经犯下过某些重大罪行。所有的交涉系技能减少[1D3*10]%。","再投掷一次,获得那个特征:特征具有(D)时,玩家可以再额外选择一个其他任意特征获得。特征没有(D)时,玩家必须再同时选择一个(D)特征。","再投掷两次并获得那两个特征。","投掷三次,玩家和KP各选择一个特征。","病弱(D):CON-[1D3]。","巧妙的手法:【钳工】技能增加【DEX*5】%,可以在偷窃或者魔术的时候使用。","迟缓(D):MOVE-1。","失去名誉(D):探索者因为国籍,性别,人种,宗教或者过去的犯罪记录等原因失去了社会上的名誉地位。作为其影响,调查员可能减少自由活动时间甚至所有的交涉系技能减少[1D4*10]%甚至更多。具体的影响玩家和KP商议决定。","元军人:调查员获得【INT*5】点的技能点加到士兵的职业技能上。","咒文知识:由KP决定!调查员最多可以获知[1D3]种咒文。SAN值减少[1D6]点。","胆小(D):调查员见到血液或者流血就会感觉到身体不适,失去更多的SAN值。也可能因为疾病的原因无法靠近或通过流血现场。","坚毅:调查员不受到现实中的血迹或者流血的影响。遭遇血迹和流血时SAN损失为最小值,即使见到最残虐的场合(大量被撕裂的人,被猎奇杀死的尸体等)也最多只减少通常的一半。","比公牛还要强韧:STR+[1D3]。","迷信(D):调查员迷信不疑,依赖着护身符,仪式或者愚蠢的信念。遭遇超自然现象的时候比通常多损失1点SAN值,即使原本不损失的情况下可能变成损失1点。","同情心:调查员选择一个交涉系技能+30%或者选择两个各+20%,然后额外再选择一个+10%。","意外的帮手:调查员因为一些缘由拥有一个对自己忠实并帮助自己的协助者。KP来决定这个协助者的真身和影响(依旧可以D100来决定)。并且D100也决定其频率。","看不见的财产:调查员有一笔自己不知道的财产。这可能是亲人遗赠的或者理事会之类授予的。这可能会是一块土地,房屋或者事业。这依旧可以用D100来决定去价值程度。","虚弱(D):STR-[1D3]。","戴眼镜(D):调查员要看清东西必须戴眼镜。鉴定一个【幸运】,成功的话眼镜只在读书或者进行精细工作的时候才需要。失败的话会在激烈运动等情况时会感觉到不能自由行动。不戴眼镜的话和视觉关联的技能减少[1D3*10]%(这个惩罚即使幸运成功也一样)。","彬彬有礼:调查员的【信用】+10%,真是个有礼貌的绅士(淑女)。","孩子(D):调查员的年龄变成[10+2D3]岁。最大EDU变成【年龄的1/2+2】,DEX+1,STR,CON,APP中任意一项+1。玩家和KP商议决定,调查员大概依旧和家人住在一起,职业等也需要重新修正。","任意选择一项特征。","投掷两次,玩家任意选择其中一项特征。"}}, {"个人描述",{"结实的","英俊的","笨拙的","机灵的","迷人的","娃娃脸","聪明的","邋遢的","死人脸","肮脏的","耀眼的","书呆子","年轻的","疲倦脸","肥胖的","啤酒肚","长头发","苗条的","优雅的","稀烂的","矮壮的","苍白的","阴沉的","平庸的","乐观的","棕褐色","皱纹人","古板的","狐臭的","狡猾的","健壮的","娇俏的","筋肉人","魁梧的","迟钝的","虚弱的"}}, {"思想信念",{"1:你信仰并祈并一位大能。(例如毗沙门天、耶稣基督、海尔·塞拉西一世)","2:人类无需上帝。(例如坚定的无神论者,人文主义者,世俗主义者)","3:科学万能!科学万岁!你将选择其中之一。(例如进化论,低温学,太空探索)","4:命中注定。(例如因果报应,种姓系统,超自然存在)","5:社团或秘密结社的一员。(例如共济会,女协,匿名者)","6:社会坏掉了,而你将成为正义的伙伴。应斩除之物是?(例如毒品,暴力,种族歧视)","7:神秘依然在。(例如占星术,招魂术,塔罗)","8:诸君,我喜欢政治。(例如保守党,共产党,自由党)","9:“金钱就是力量,我的朋友,我将竭尽全力获取我能看到的一切。”(例如贪婪心,进取心,冷酷心)","10:竞选者/激进主义者。(例如女权运动人,平等主义家,工会权柄)"}}, {"重要之人",{"1:父辈。(例如母亲,父亲,继母)","2:祖父辈。(例如外祖母,祖父)","3:兄弟。(例如妹妹,半血亲妹妹,无血缘妹妹)","4:孩子。(儿子或女儿)","5:另一半。(例如配偶,未婚夫,爱人)","6那位指引你人生技能的人。指明该技能和该人。(例如学校教师,师傅,父亲)","7:青梅竹马。(例如同学,邻居,幼驯染)","8:名人。偶像或者英雄。当然也许你从未见过他。(例如电影明星,政治家,音乐家。)","9:游戏中的另一位调查员伙伴。随机或自选。","10:游戏中另一外NPC。详情咨询你的守秘人"}}, @@ -50,9 +50,6 @@ namespace CardDeck {"amgc特技1",{"1复合武装(+1对应属性)","2武术训练(+1STR/AGI)","3强化武器","4秘术神器(+1MAG)","5专精天赋(+1任意属性)","6弹性躯体(+1AGI)","7强化变身(+1MAG)","8伪装神器(+1LCK)","9鲜血魔法(+1AGI/MAG)","10储物背包(+1LCK)","11维生强化(+1VIT)","12强化套装(+1VIT)","13治愈神器(+1VIT)","14随行盟友","15魔物变形(+1STR/VIT)","16巫术大师(+1MAG)","17背生双翼(+1AGI)","18净化神器(+1MAG)","19时刻警觉(+1AGI)","20法力神器(+1STR/MAG)"}}, {"amgc特技2",{"1次元旅者(+1任意属性)","2不存在者(+1LCK)","3天选之人(+1LCK)","4精通领域","5次元住所","6隐姓埋名(+AGI/MAG/LCK)","7密封环境(+1VIT)","8牢狱逃脱(+1LCK)","9英雄救美(+1任意属性)","10完美定向(+1LCK)","11特大背包(+1VIT)","12自然成长(+1VIT)","13男子气概(+1LCK)","14上城转移(+1LCK)","15额外收入(+1LCK)","16获得魔宠(+1任意属性)","17瓶中灵魂(+1任意属性)","18永恒形态","19绝地反击(-1VIT,+1任意属性,+1任意属性)","20虚假双亲(+1任意属性)"}}, {"amgc特技3",{"1万能胶布(+1VIT)","2记忆链接(+1MAG)","3活化武器(+1对应属性)","4背水一战(+1VIT)","5主角时刻","6好运常伴(+1LCK)","7强健体魄(+1VIT)","8保卫专精(+1VIT)","9小姐做派(+1任意属性)","10形体变化(+1AGI/MAG)","11被监护人(+1MAG)","12法力引导(+1MAG)","13镜像行动","14双重引导(+1任意属性)","15骷髅钥匙(+1LCK)","16超级地图(+1LCK)","17快照解析(+1LCK)","18星界投射(+1MAG)","19自主规制(+1任意属性)","20忠诚坐骑(+1AGI)"}}, - {"麻将",{"一万","一索","一筒","二万","二索","二筒","三万","三索","三筒","四万","四索","四筒","赤五万","赤五索","赤五筒","六万","六索","六筒","七万","七索","七筒","八万","八索","八筒","九万","九索","九筒","东","南","西","北","中","发","白","一万","一索","一筒","二万","二索","二筒","三万","三索","三筒","四万","四索","四筒","五万","五索","五筒","六万","六索","六筒","七万","七索","七筒","八万","八索","八筒","九万","九索","九筒","东","南","西","北","中","发","白","一万","一索","一筒","二万","二索","二筒","三万","三索","三筒","四万","四索","四筒","五万","五索","五筒","六万","六索","六筒","七万","七索","七筒","八万","八索","八筒","九万","九索","九筒","东","南","西","北","中","发","白","一万","一索","一筒","二万","二索","二筒","三万","三索","三筒","四万","四索","四筒","五万","五索","五筒","六万","六索","六筒","七万","七索","七筒","八万","八索","八筒","九万","九索","九筒","东","南","西","北","中","发","白"}}, - {"扑克花色",{"红桃","黑桃","方片","梅花"}}, - {"扑克",{"红桃A","红桃2","红桃3","红桃4","红桃5","红桃6","红桃7","红桃8","红桃9","红桃10","红桃J","红桃Q","红桃K","黑桃A","黑桃2","黑桃3","黑桃4","黑桃5","黑桃6","黑桃7","黑桃8","黑桃9","黑桃10","黑桃J","黑桃Q","黑桃K","方片A","方片2","方片3","方片4","方片5","方片6","方片7","方片8","方片9","方片10","方片J","方片Q","方片K","梅花A","梅花2","梅花3","梅花4","梅花5","梅花6","梅花7","梅花8","梅花9","梅花10","梅花J","梅花Q","梅花K","大王","小王"}}, {"塔罗牌",{"【0】愚者","【1】魔术师","【2】女祭司","【3】女皇","【4】皇帝","【5】教皇","【6】恋人","【7】战车","【8】力量","【9】隐者","【10】命运之轮","【11】正义","【12】倒吊人","【13】死神","【14】节制","【15】恶魔","【16】塔","【17】星星","【18】月亮","【19】太阳","【20】审判","【21】世界"}}, {"正逆",{"正位","逆位"}}, {"塔罗牌占卜",{"随机牌阵:{塔罗牌阵}"}}, @@ -64,6 +61,8 @@ namespace CardDeck {"六芒星牌阵",{"\n起因:{塔罗牌} {%正逆}\n现状:{塔罗牌} {%正逆}\n未来:{塔罗牌} {%正逆}\n对策:{塔罗牌} {%正逆}\n周遭:{塔罗牌} {%正逆}\n态度:{塔罗牌} {%正逆}\n结果:{塔罗牌} {%正逆}"}}, {"凯尔特十字牌阵",{"\n问题现状:{塔罗牌} {%正逆}\n障碍助力:{塔罗牌} {%正逆}\n理想状况:{塔罗牌} {%正逆}\n基础条件:{塔罗牌} {%正逆}\n过去状况:{塔罗牌} {%正逆}\n未来发展:{塔罗牌} {%正逆}\n自身现状:{塔罗牌} {%正逆}\n周围环境:{塔罗牌} {%正逆}\n希望恐惧:{塔罗牌} {%正逆}\n最终结果:{塔罗牌} {%正逆}"}}, }; + // + std::map> mReplyDeck{}; //群聊牌堆 std::map> mGroupDeck; //群聊临时牌堆 @@ -107,19 +106,19 @@ namespace CardDeck strReply = TempDeck[ans]; if(!isBack)TempDeck.erase(TempDeck.begin() + ans); } - while (strReply.find('{') != std::string::npos) { - int lq = strReply.find('{'); - int rq = strReply.find('}'); + int intCnt = 0; + while (strReply.find('{', intCnt) != std::string::npos) { + int lq = strReply.find('{',intCnt); + int rq = strReply.find('}',lq); + if (rq == std::string::npos)break; + intCnt = rq; bool isTmpBack = false; string strTempName = strReply.substr(lq + 1, rq - lq - 1); if (strTempName[0] == '%') { isTmpBack = true; strTempName = strTempName.substr(1); } - if (mPublicDeck.count(strTempName) == 0) { - strReply += "\n"+ strTempName +"?发现未知牌堆名"; - break; - } + if (mPublicDeck.count(strTempName) == 0) continue; else if (TempDeckList.count(strTempName)==0|| TempDeckList[strTempName].empty()) { TempDeckList[strTempName] = mPublicDeck[strTempName]; } diff --git a/Dice/CardDeck.h b/Dice/CardDeck.h index 7c2eed21..878b14a5 100644 --- a/Dice/CardDeck.h +++ b/Dice/CardDeck.h @@ -13,6 +13,7 @@ namespace CardDeck { extern std::map> mPublicDeck; + extern std::map> mReplyDeck; //群聊牌堆 extern std::map> mGroupDeck; //群聊临时牌堆 diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index 9cf2d565..bb91a796 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -201,6 +201,7 @@ void dataBackUp() { saveJMap(strFileLoc + "GroupDeckTmp.json", CardDeck::mGroupDeckTmp); saveJMap(strFileLoc + "PrivateDeck.json", CardDeck::mPrivateDeck); saveJMap(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); + saveJMap(strFileLoc + "ReplyDeck.json", CardDeck::mReplyDeck); } EVE_Enable(eventEnable) { @@ -576,6 +577,7 @@ EVE_Enable(eventEnable) loadJMap(strFileLoc + "PrivateDeckTmp.json", CardDeck::mPrivateDeckTmp); loadJMap(strFileLoc + "PublicDeck.json", CardDeck::mPublicDeck); loadJMap(strFileLoc + "ExternDeck.json", CardDeck::mPublicDeck); + loadJMap(strFileLoc + "ReplyDeck.json", CardDeck::mReplyDeck); //读取替身模式 ifstream ifstreamStandByMe(strFileLoc + "StandByMe.RDconf"); if (ifstreamStandByMe) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index f3bc015f..7734f221 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -576,6 +576,7 @@ class FromMsg { return 0; } int DiceReply() { + if (strMsg[0] != '.')return 0; intMsgCnt++ ; int intT = (int)fromType; while (isspace(static_cast(strMsg[intMsgCnt]))) @@ -741,8 +742,8 @@ class FromMsg { if (intT == PrivateT)reply(GlobalMsg["strGlobalOff"]); return 1; } - if (!isCalled && (intT == GroupT && DisabledGroup.count(fromGroup)))return 0; - if (!isCalled && (intT == DiscussT && DisabledDiscuss.count(fromGroup)))return 0; + if (!isCalled && (intT == GroupT && DisabledGroup.count(fromGroup)))return 1; + if (!isCalled && (intT == DiscussT && DisabledDiscuss.count(fromGroup)))return 1; if (strLowerMessage.substr(intMsgCnt, 7) == "helpdoc"&&isAdmin) { intMsgCnt += 7; @@ -1055,6 +1056,33 @@ class FromMsg { } return 1; } + else if (strLowerMessage.substr(intMsgCnt, 5) == "reply") { + intMsgCnt += 5; + if (!isAdmin) { + reply(GlobalMsg["strNotAdmin"]); + return -1; + } + string strReplyName = readUntilSpace(); + vector *Deck = NULL; + if (strReplyName.empty()) { + reply(GlobalMsg["strParaEmpty"]); + return -1; + } + else { + CardDeck::mReplyDeck[strReplyName] = {}; + Deck = &CardDeck::mReplyDeck[strReplyName]; + } + while (intMsgCnt != strMsg.length()) { + string item = readItem(); + if(!item.empty())Deck->push_back(item); + } + if (Deck->empty()) { + reply(format(GlobalMsg["strReplyDel"], { strReplyName })); + CardDeck::mReplyDeck.erase(strReplyName); + } + else reply(format(GlobalMsg["strReplySet"], { strReplyName })); + return 1; +} else if (strLowerMessage.substr(intMsgCnt, 5) == "rules") { intMsgCnt += 5; @@ -1255,7 +1283,7 @@ class FromMsg { } while (intMsgCnt != strMsg.length()) { string item = readItem(); - DeckPro->push_back(item); + if (!item.empty())DeckPro->push_back(item); } reply(GlobalMsg["strDeckProNew"]); return 1; @@ -3295,6 +3323,14 @@ class FromMsg { } return 0; } + int CustomReply(){ + string strKey = readRest(); + if (CardDeck::mReplyDeck.count(strKey)) { + reply(CardDeck::drawCard(CardDeck::mReplyDeck[strKey], true)); + return 1; + } + else return 0; + } //判断是否响应 bool DiceFilter() { init(strMsg); @@ -3318,12 +3354,13 @@ class FromMsg { } } init2(strMsg); - if (strMsg[0] != '.')return 0; + if (strMsg[0] != '.'&&CardDeck::mReplyDeck.count(strMsg) == 0)return 0; if (fromType == Private) isCalled = true; isMaster = fromQQ == masterQQ && boolMasterMode; isAdmin = isMaster || AdminQQ.count(fromQQ); isAuth = isAdmin || fromType != Group || getGroupMemberInfo(fromGroup, fromQQ).permissions > 1; - return DiceReply(); + if (DiceReply())return 1; + else return CustomReply(); } private: @@ -3419,7 +3456,7 @@ class FromMsg { string readItem() { string strMum; while (isspace(static_cast(strMsg[intMsgCnt])) || strMsg[intMsgCnt] == '|')intMsgCnt++; - while (!isspace(static_cast(strMsg[intMsgCnt])) && strMsg[intMsgCnt] != '|'&& intMsgCnt != strMsg.length()) { + while (strMsg[intMsgCnt] != '|'&& intMsgCnt != strMsg.length()) { strMum += strMsg[intMsgCnt]; intMsgCnt++; } diff --git a/Dice/GlobalVar.cpp b/Dice/GlobalVar.cpp index 9cd99ad9..b07dd98b 100644 --- a/Dice/GlobalVar.cpp +++ b/Dice/GlobalVar.cpp @@ -64,6 +64,9 @@ const std::string Dice_Full_Ver = Dice_Short_Ver + " [UNKNOWN COMPILER]" std::map GlobalMsg { + {"strParaEmpty","参数不能为空×"}, //偷懒用万能回复 + {"strReplySet","关键词{0}的回复已设置"}, + {"strReplyDel","关键词{0}的回复已清除"}, {"strStModify","已记录{0}的属性变化:"}, //存在技能值变化情况时,优先使用此文本 {"strStDetail","已设置{0}的属性:"}, //存在掷骰时,使用此文本(暂时无用) {"strStValEmpty","未记录{0}原值×"}, //{0}为属性名 From b436fe216051e60587702e93204f4422b0348f48 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Mon, 22 Jul 2019 18:44:34 +0800 Subject: [PATCH 31/33] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dwarning=E7=9A=84?= =?UTF-8?q?=E8=A7=A3=E6=9E=90Bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 淇warning鍥犵己灏戦敭鍊煎嚭閿欑殑闂 --- Dice/DiceConsole.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 59b88f5e..05c92824 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -218,18 +218,19 @@ void warningHandler() { } if (!warning.strMsg.empty()) { long long blackQQ, blackGroup; - nlohmann::json jInfo = { {"type","Unknown"},{"fromGroup",0},{"time","Unknown"},{"fromQQ",0},{"note","" } }; + string type, time, note; + nlohmann::json jInfo; try { jInfo = nlohmann::json::parse(GBKtoUTF8(warning.strMsg)); - blackQQ = jInfo["fromQQ"]; - blackGroup = jInfo["fromGroup"]; + jInfo.count("fromQQ") ? blackQQ = jInfo["fromQQ"] : blackQQ = 0; + jInfo.count("fromGroup") ? blackGroup = jInfo["fromGroup"] : blackGroup = 0; + jInfo.count("type") ? type = readJKey(jInfo["type"]) : type = "Unknown"; + //jInfo.count("time") ? time = readJKey(jInfo["time"]) : time = "Unknown"; + jInfo.count("note") ? note = readJKey(jInfo["note"]) : note = ""; } catch (...) { continue; } - string type = readJKey(jInfo["type"]); - string time = readJKey(jInfo["time"]); - string note = readJKey(jInfo["note"]); if (type != "ban" && type != "kick" || (!blackGroup || BlackGroup.count(blackGroup)) && (!blackQQ || BlackQQ.count(blackQQ))) { continue; } From b60910af4a0fff1001cf1c5f3aad2b5fb9242d7f Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Tue, 23 Jul 2019 09:22:01 +0800 Subject: [PATCH 32/33] =?UTF-8?q?.ri=E5=85=81=E8=AE=B8=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=A1=A8=E8=BE=BE=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 鐜板湪鍏堟敾鍏佽澶氶鍙栧ぇ --- Dice/DiceEvent.h | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 7734f221..6d1b6c1b 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -2435,7 +2435,7 @@ class FromMsg { else if (strLowerMessage.substr(intMsgCnt, 2) == "ri"&&intT) { intMsgCnt += 2; - while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; + readSkipSpace(); string strinit = "D20"; if (strLowerMessage[intMsgCnt] == '+' || strLowerMessage[intMsgCnt] == '-') { @@ -2443,23 +2443,16 @@ class FromMsg { intMsgCnt++; while (isspace(static_cast(strLowerMessage[intMsgCnt])))intMsgCnt++; } - else if (isdigit(static_cast(strLowerMessage[intMsgCnt]))) - strinit += '+'; - while (isdigit(static_cast(strLowerMessage[intMsgCnt]))) - { - strinit += strLowerMessage[intMsgCnt]; - intMsgCnt++; - } - while (isspace(static_cast(strLowerMessage[intMsgCnt]))) - { - intMsgCnt++; + else if (isRollDice()){ + strinit = readDice(); } + readSkipSpace(); string strname = strMsg.substr(intMsgCnt); if (strname.empty()) strname = strNickName; else strname = strip(strname); - RD initdice(strinit); + RD initdice(strinit, 20); const int intFirstTimeRes = initdice.Roll(); if (intFirstTimeRes == Value_Err) { @@ -3414,6 +3407,20 @@ class FromMsg { if (strGroup.empty()) return 0; return stoll(strGroup); } + //是否可看做掷骰表达式 + bool isRollDice() { + readSkipSpace(); + if (isdigit(static_cast(strLowerMessage[intMsgCnt])) + || strLowerMessage[intMsgCnt] == 'd' || strLowerMessage[intMsgCnt] == 'k' + || strLowerMessage[intMsgCnt] == 'p' || strLowerMessage[intMsgCnt] == 'b' + || strLowerMessage[intMsgCnt] == 'f' + || strLowerMessage[intMsgCnt] == '+' || strLowerMessage[intMsgCnt] == '-' + || strLowerMessage[intMsgCnt] == 'a' + || strLowerMessage[intMsgCnt] == 'x' || strLowerMessage[intMsgCnt] == '*') { + return true; + } + else return false; + } //读取掷骰表达式 string readDice(){ string strDice; @@ -3426,7 +3433,7 @@ class FromMsg { || strLowerMessage[intMsgCnt] == 'a' || strLowerMessage[intMsgCnt] == 'x' || strLowerMessage[intMsgCnt] == '*') { - strDice += strLowerMessage[intMsgCnt]; + strDice += strMsg[intMsgCnt]; intMsgCnt++; } return strDice; From 0c71ac25bc6ab002c52a74d4bd94e31f1ea8c309 Mon Sep 17 00:00:00 2001 From: "string.Empty" Date: Wed, 24 Jul 2019 22:28:06 +0800 Subject: [PATCH 33/33] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E4=BA=86=E8=AE=A8?= =?UTF-8?q?=E8=AE=BA=E7=BB=84=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 瀹炶返涓璁虹粍鍒楄〃骞朵笉鑳藉彂鎸ヤ粈涔堜綔鐢紝浜庢槸鍙栨秷璇ヨ瀹 --- Dice/Dice.cpp | 19 ------------------- Dice/DiceConsole.cpp | 30 ++++++++++++++++-------------- Dice/DiceConsole.h | 2 -- Dice/DiceEvent.h | 2 -- 4 files changed, 16 insertions(+), 37 deletions(-) diff --git a/Dice/Dice.cpp b/Dice/Dice.cpp index bb91a796..c386bc4d 100644 --- a/Dice/Dice.cpp +++ b/Dice/Dice.cpp @@ -168,13 +168,6 @@ void dataBackUp() { ofstreamBlackQQ << it << std::endl; } ofstreamBlackQQ.close(); - //备份讨论组列表 - ofstream ofstreamDiscussList(strFileLoc + "DiscussList.map", ios::out | ios::trunc); - for (auto it : DiscussList) - { - ofstreamDiscussList << it.first << "\n" << it.second << std::endl; - } - ofstreamDiscussList.close(); //备份聊天列表 ofstream ofstreamLastMsgList(strFileLoc + "LastMsgList.MYmap", ios::out | ios::trunc); for (auto it : mLastMsgList) @@ -500,18 +493,6 @@ EVE_Enable(eventEnable) } } ifstreamBlackQQ.close(); - //读取讨论组列表 - ifstream ifstreamDiscussList(strFileLoc + "DiscussList.map"); - if (ifstreamDiscussList) - { - long long llDiscuss; - time_t tNow; - while (ifstreamDiscussList >> llDiscuss >> tNow) - { - DiscussList[llDiscuss]=tNow; - } - } - ifstreamDiscussList.close(); //读取聊天列表 ifstream ifstreamLastMsgList(strFileLoc + "LastMsgList.MYmap"); if (ifstreamLastMsgList) diff --git a/Dice/DiceConsole.cpp b/Dice/DiceConsole.cpp index 05c92824..7d005982 100644 --- a/Dice/DiceConsole.cpp +++ b/Dice/DiceConsole.cpp @@ -45,8 +45,6 @@ std::mapboolConsole = { {"DisabledGlobal",false}, {"KickedBanInviter",true} }; //骰娘列表 std::map mDiceList; - //讨论组消息记录 - std::map DiscussList; //群邀请者 std::map mGroupInviter; //个性化语句 @@ -302,6 +300,22 @@ void warningHandler() { int intDayLim = stoi(strPara); string strDayLim = to_string(intDayLim); time_t tNow = time(NULL);; + for (auto eachChat : mLastMsgList) { + if (eachChat.first.second == Private)continue; + int intDay = (int)(tNow - eachChat.second) / 86400; + if (intDay > intDayLim) { + strReply += printChat(eachChat.first) + ":" + to_string(intDay) + "天\n"; + AddMsgToQueue(format(GlobalMsg["strOverdue"], { GlobalMsg["strSelfName"], to_string(intDay) }), eachChat.first.first, eachChat.first.second); + Sleep(100); + if (eachChat.first.second == Group) { + setGroupLeave(eachChat.first.first); + if (GroupList.count(eachChat.first.first))GroupList.erase(eachChat.first.first); + } + else setDiscussLeave(eachChat.first.first); + mLastMsgList.erase(eachChat.first); + intCnt++; + } + } for (auto eachGroup : GroupList) { int intDay = (int)(tNow - getGroupMemberInfo(eachGroup.first, getLoginQQ()).LastMsgTime)/86400; if (intDay > intDayLim) { @@ -313,18 +327,6 @@ void warningHandler() { intCnt++; } } - for (auto eachDiscuss : DiscussList) { - int intDay = (int)(tNow - eachDiscuss.second) / 86400; - if (intDay > intDayLim){ - strReply += printChat({ eachDiscuss.first,Discuss }) + ":" + to_string(intDay) + "天\n"; - AddMsgToQueue(format(GlobalMsg["strOverdue"], { GlobalMsg["strSelfName"], to_string(intDay) }), eachDiscuss.first, Group); - Sleep(10); - setDiscussLeave(eachDiscuss.first); - DiscussList.erase(eachDiscuss.first); - mLastMsgList.erase({ eachDiscuss.first ,Discuss }); - intCnt++; - } - } strReply += GlobalMsg["strSelfName"] + "已筛除潜水" + strDayLim + "天群聊" + to_string(intCnt) + "个√"; AddMsgToQueue(strReply,masterQQ); } diff --git a/Dice/DiceConsole.h b/Dice/DiceConsole.h index cbe7fd78..3cdd8ff1 100644 --- a/Dice/DiceConsole.h +++ b/Dice/DiceConsole.h @@ -25,8 +25,6 @@ extern std::mapboolConsole; //骰娘列表 extern std::map mDiceList; - //讨论组消息记录 - extern std::map DiscussList; //个性化语句 extern std::map PersonalMsg; //botoff的群 diff --git a/Dice/DiceEvent.h b/Dice/DiceEvent.h index 6d1b6c1b..484a7e9f 100644 --- a/Dice/DiceEvent.h +++ b/Dice/DiceEvent.h @@ -123,7 +123,6 @@ class FromMsg { + "全局.me开关:" + (boolConsole["DisabledMe"] ? "禁用" : "启用") + "\n" + "全局.jrrp开关:" + (boolConsole["DisabledJrrp"] ? "禁用" : "启用"); if (isAdmin) strReply += "\n所在群聊数:" + to_string(getGroupList().size()) + "\n" - + (DiscussList.size() ? "有记录的讨论组数:" + to_string(DiscussList.size()) + "\n" : "") + "黑名单用户数:" + to_string(BlackQQ.size()) + "\n" + "黑名单群数:" + to_string(BlackGroup.size()) + "\n" + "白名单用户数:" + to_string(WhiteQQ.size()) + "\n" @@ -351,7 +350,6 @@ class FromMsg { else if (llTargetID > 1000000000 && setDiscussLeave(llTargetID) == 0) { mLastMsgList.erase({ llTargetID ,Discuss }); AdminNotify("已令" + GlobalMsg["strSelfName"] + "退出讨论组" + to_string(llTargetID) + "√"); - DiscussList.erase(llTargetID); } else { reply(GlobalMsg["strGroupGetErr"]);