{"id":413,"date":"2012-04-06T23:05:56","date_gmt":"2012-04-06T15:05:56","guid":{"rendered":"http:\/\/newbiecoder.0ginr.com\/blog\/?p=413"},"modified":"2012-04-15T17:16:02","modified_gmt":"2012-04-15T09:16:02","slug":"qq%e5%af%b9%e6%88%98%e5%b9%b3%e5%8f%b0%e6%9c%ac%e5%9c%b0%e5%a5%bd%e5%8f%8b%e7%bc%96%e8%be%91%e5%99%a8","status":"publish","type":"post","link":"https:\/\/newbiecoder.0ginr.com\/blog\/?p=413","title":{"rendered":"QQ\u5bf9\u6218\u5e73\u53f0\u672c\u5730\u597d\u53cb\u7f16\u8f91\u5668"},"content":{"rendered":"<p>QQ\u5bf9\u6218\u5e73\u53f0\u7684\u672c\u5730\u597d\u53cb\u4fe1\u606f\u50a8\u5b58\u5728%QQBattleZone%\\%UIN%\\Friend.dat\uff0c\u683c\u5f0f\u6bd4\u8f83\u7b80\u5355\uff0c\u4e00\u5f00\u59cb\u662f\u4e00\u4e2aDWORD\uff0c\u770b\u8d77\u6765\u603b\u662f\u4e3a0\uff0c\u540e\u9762\u662f\u4e00\u5806FriendObject\uff08\u53c2\u8003\u4ee3\u7801\u4e2d\u7684\u5b9a\u4e49\uff09\u3002<\/p>\n<p>\u5728\u5e73\u53f0\u4e0a\u597d\u8c61\u6ca1\u6709\u67e5\u627e\u597d\u53cb\u7684\u529f\u80fd\uff0c\u53ea\u80fd\u6dfb\u52a0\u540c\u4e00\u4e2a\u623f\u5b50\u7684\uff0c\u6240\u4ee5\u5c31\u5199\u4e86\u8fd9\u4e48\u4e2a\u4ee3\u7801\u6765\u81ea\u7531\u6dfb\u52a0\u3002<\/p>\n<p>\u4ee3\u7801\u597d\u50cf\u5199\u7684\u6bd4\u8f83\u70c2\uff0c\u6bd4\u5982\u8bf4\u6dfb\u52a0\u597d\u53cb\u5c31\u8be5\u5355\u72ec\u5199\u4e00\u4e2a\u51fd\u6570\uff0c\u5077\u4e2a\u61d2\uff0c\u5404\u4f4d\u52c9\u5f3a\u770b\u5427\u3002<\/p>\n<p><pre><code class=\"preserve-code-formatting\">\/*\n  Description\n    \n    A simple tool to manage local friends in QQ game platform.\n    \n  Author\n  \n    NewbieCoder@0GiNr\n  \n  Revision\n    \n    None\n    \n*\/\n\n#include &lt;cstdio&gt;\n#include &lt;cstring&gt;\n\n#include &lt;iostream&gt;\n#include &lt;string&gt;\n#include &lt;vector&gt;\n#include &lt;iomanip&gt;\n#include &lt;fstream&gt;\n#include &lt;algorithm&gt;\n\nstruct FriendObject {\n  int uin;\n  char nickName[20];\n  \n  \/\/\n  \/\/ Except for a DWORD at the beginning, which may be face icon?\n  \/\/ All the remaining bytes seem to always be zero.\n  \/\/\n  \n  char unknown[36];\n  \n  explicit FriendObject() {\n    memset(this, 0, sizeof(*this));\n  }\n};\n\nstd::vector&lt;FriendObject&gt; friends;\n\n\/\/\n\/\/ Binary read.\n\/\/\n\ntemplate&lt;class type&gt; std::istream&amp; binaryRead(std::istream &amp;istreamObject, type &amp;object) {\n  return istreamObject.read((char *)&amp;object, sizeof(object));\n}\n\n\/\/\n\/\/ Binary write.\n\/\/\n\ntemplate&lt;class type&gt; std::ostream&amp; binaryWrite(std::ostream &amp;ostreamObject, type object) {\n  return ostreamObject.write((char *)&amp;object, sizeof(object));\n}\n\n\/\/\n\/\/ Load friends information from &#039;Friend.dat&#039;\n\/\/\n\/\/ File structure:\n\/\/    DWORD unknow -- Always zero.\n\/\/    One or more FriendObject follows.\n\/\/\n\nvoid loadFriends(std::istream &amp;istreamObject) {\n  FriendObject friendObject;\n  int temp;\n  \n  friends.clear();\n  \n  \/\/\n  \/\/ Always zero?\n  \/\/\n  \n  binaryRead(istreamObject, temp);\n  \n  \/\/\n  \/\/ Function binaryRead simplifies the work much.\n  \/\/\n  \n  while (binaryRead(istreamObject, friendObject)) {\n    friends.push_back(friendObject);\n  }\n}\n\n\/\/\n\/\/ List the friends information.\n\/\/\n\nvoid dumpFriends() {\n  for (FriendObject friendObject : friends) {\n    std::cout &lt;&lt; std::setw(10) &lt;&lt; std::left &lt;&lt; friendObject.uin &lt;&lt; &quot; &quot; &lt;&lt;\n      std::setw(25) &lt;&lt; std::left &lt;&lt; friendObject.nickName &lt;&lt; std::endl;\n  }\n}\n\n\/\/\n\/\/ Write friends information back.\n\/\/\n\nvoid saveFriends(std::ostream &amp;ostreamObject) {\n  \n  \/\/\n  \/\/ Always be zero.\n  \/\/\n  \n  binaryWrite(ostreamObject, (int)0);\n  \n  \/\/\n  \/\/ Write them back one by one.\n  \/\/\n  \n  for (FriendObject friendObject : friends) {\n    binaryWrite(ostreamObject, friendObject);\n  }\n}\n\nint main(int argc, char **argv) {\n  std::string command;\n  std::string fileName = &quot;Friend.dat&quot;;\n  std::ifstream inputFileStream;\n  std::ofstream outputFileStream;\n  bool informationModified = false;\n  \n  \/\/\n  \/\/ TODO: Validate arguments.\n  \/\/\n  \n  command = argv[1];\n  \n  inputFileStream.open(fileName, std::ios::binary);\n  if (!inputFileStream) {\n    std::cerr &lt;&lt; &quot;Unable to open Friend.dat.&quot; &lt;&lt; std::endl;\n    \n    return -1;\n  }\n  \n  loadFriends(inputFileStream);\n  inputFileStream.close();\n  \n  if (command == &quot;-list&quot;) {\n    dumpFriends();\n  } else if (command == &quot;-add&quot;) {\n    FriendObject friendObject;\n    std::vector&lt;FriendObject&gt;::iterator friendPointer;\n    \n    \/\/\n    \/\/ Data should be write back.\n    \/\/\n    \n    informationModified = true;\n\n    sscanf(argv[2], &quot;%d&quot;, &amp;friendObject.uin);\n    strncpy(friendObject.nickName, argv[3], sizeof(friendObject.nickName));;\n    \n    \/\/\n    \/\/ Check if we have to add a new entry.\n    \/\/\n    \n    friendPointer = std::find_if(friends.begin(), friends.end(), \n      [friendObject] (FriendObject const &amp;current) -&gt; bool {\n      return current.uin == friendObject.uin;\n    });\n    \n    if (friendPointer == friends.end()) {\n      friends.push_back(friendObject);\n    } else {\n      *friendPointer = friendObject;\n    }\n  } else if (command == &quot;-delete&quot;) {\n    int uin;\n    \n    sscanf(argv[2], &quot;%d&quot;, &amp;uin);\n    \n    informationModified = true;\n    \n    \/\/\n    \/\/ Find the corresponding entry and remove it if one exists.\n    \/\/\n    \n    friends.erase(std::remove_if(friends.begin(), friends.end(), \n      [uin] (FriendObject const &amp;current) -&gt; bool {\n      return current.uin == uin;\n    }), friends.end());\n  } else if (command == &quot;-clear&quot;) {\n    informationModified = true;\n    friends.clear();\n  }\n  \n  \/\/\n  \/\/ Operation &#039;-add&#039; and &#039;-delete&#039; requires writting data back.\n  \/\/\n  \n  if (informationModified) {  \n    outputFileStream.open(fileName, std::ios::binary | std::ios::trunc);\n    if (!outputFileStream) {\n      std::cerr &lt;&lt; &quot;Unable to write back to Friend.dat.&quot; &lt;&lt; std::endl;\n      \n      return -1;\n    }\n    \n    saveFriends(outputFileStream);\n    \n    outputFileStream.close();\n  }\n}<\/code><\/pre><\/p>\n","protected":false},"excerpt":{"rendered":"<p>QQ\u5bf9\u6218\u5e73\u53f0\u7684\u672c\u5730\u597d\u53cb\u4fe1\u606f\u50a8\u5b58\u5728%QQBattleZone%\\%UIN%\\Friend.dat\uff0c\u683c\u5f0f\u6bd4\u8f83\u7b80\u5355\uff0c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-413","post","type-post","status-publish","format-standard","hentry","category-1"],"_links":{"self":[{"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=413"}],"version-history":[{"count":4,"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/413\/revisions"}],"predecessor-version":[{"id":474,"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/413\/revisions\/474"}],"wp:attachment":[{"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/newbiecoder.0ginr.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}