diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index d21c2ee0d4..8c7b6bb578 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -224,3 +224,139 @@ std::string TabsToSpaces(int tab_size, const std::string &in) return out; } + +std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) +{ + while(1) + { + const int pos = result.find(src); + if (pos == -1) break; + result.replace(pos, src.size(), dest); + } + return result; +} + +// UriDecode and UriEncode are from http://www.codeguru.com/cpp/cpp/string/conversions/print.php/c12759 +// by jinq0123 (November 2, 2006) + +// Uri encode and decode. +// RFC1630, RFC1738, RFC2396 + +//#include +//#include + +const char HEX2DEC[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,-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, -1,-1,-1,-1, + /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, + + /* 4 */ -1,10,11,12, 13,14,15,-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,10,11,12, 13,14,15,-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 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +std::string UriDecode(const std::string & sSrc) +{ + // Note from RFC1630: "Sequences which start with a percent sign + // but are not followed by two hexadecimal characters (0-9, A-F) are reserved + // for future extension" + + const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); + const int SRC_LEN = sSrc.length(); + const unsigned char * const SRC_END = pSrc + SRC_LEN; + const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' + + char * const pStart = new char[SRC_LEN]; + char * pEnd = pStart; + + while (pSrc < SRC_LAST_DEC) + { + if (*pSrc == '%') + { + char dec1, dec2; + if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)]) + && -1 != (dec2 = HEX2DEC[*(pSrc + 2)])) + { + *pEnd++ = (dec1 << 4) + dec2; + pSrc += 3; + continue; + } + } + + *pEnd++ = *pSrc++; + } + + // the last 2- chars + while (pSrc < SRC_END) + *pEnd++ = *pSrc++; + + std::string sResult(pStart, pEnd); + delete [] pStart; + return sResult; +} + +// Only alphanum is safe. +const char SAFE[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, 0,0,0,0, 0,0,0,0, + /* 1 */ 0,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 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, + + /* 4 */ 0,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,0, 0,0,0,0, + /* 6 */ 0,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,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 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 +}; + +std::string UriEncode(const std::string & sSrc) +{ + const char DEC2HEX[16 + 1] = "0123456789ABCDEF"; + const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); + const int SRC_LEN = sSrc.length(); + unsigned char * const pStart = new unsigned char[SRC_LEN * 3]; + unsigned char * pEnd = pStart; + const unsigned char * const SRC_END = pSrc + SRC_LEN; + + for (; pSrc < SRC_END; ++pSrc) + { + if (SAFE[*pSrc]) + *pEnd++ = *pSrc; + else + { + // escape this char + *pEnd++ = '%'; + *pEnd++ = DEC2HEX[*pSrc >> 4]; + *pEnd++ = DEC2HEX[*pSrc & 0x0F]; + } + } + + std::string sResult((char *)pStart, (char *)pEnd); + delete [] pStart; + return sResult; +} diff --git a/Source/Core/Common/Src/StringUtil.h b/Source/Core/Common/Src/StringUtil.h index f81026f894..102ae2d5fb 100644 --- a/Source/Core/Common/Src/StringUtil.h +++ b/Source/Core/Common/Src/StringUtil.h @@ -93,5 +93,8 @@ void SplitString(const std::string& str, char delim, std::vector& o bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); +std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); +std::string UriDecode(const std::string & sSrc); +std::string UriEncode(const std::string & sSrc); #endif // _STRINGUTIL_H_ diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.cpp b/Source/Core/DolphinWX/Src/GameListCtrl.cpp index ee5a8e3e85..b4c1de4d21 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/Src/GameListCtrl.cpp @@ -124,6 +124,7 @@ BEGIN_EVENT_TABLE(CGameListCtrl, wxListCtrl) EVT_LIST_COL_BEGIN_DRAG(LIST_CTRL, CGameListCtrl::OnColBeginDrag) EVT_LIST_COL_CLICK(LIST_CTRL, CGameListCtrl::OnColumnClick) EVT_MENU(IDM_PROPERTIES, CGameListCtrl::OnProperties) + EVT_MENU(IDM_GAMEWIKI, CGameListCtrl::OnWiki) EVT_MENU(IDM_OPENCONTAININGFOLDER, CGameListCtrl::OnOpenContainingFolder) EVT_MENU(IDM_OPENSAVEFOLDER, CGameListCtrl::OnOpenSaveFolder) EVT_MENU(IDM_EXPORTSAVE, CGameListCtrl::OnExportSave) @@ -998,6 +999,7 @@ void CGameListCtrl::OnRightClick(wxMouseEvent& event) { wxMenu* popupMenu = new wxMenu; popupMenu->Append(IDM_PROPERTIES, _("&Properties")); + popupMenu->Append(IDM_GAMEWIKI, _("&Wiki")); popupMenu->AppendSeparator(); if (selected_iso->GetPlatform() != GameListItem::GAMECUBE_DISC) @@ -1166,6 +1168,22 @@ void CGameListCtrl::OnProperties(wxCommandEvent& WXUNUSED (event)) Update(); } +void CGameListCtrl::OnWiki(wxCommandEvent& WXUNUSED (event)) +{ + const GameListItem *iso = GetSelectedISO(); + if (!iso) + return; + + std::string wikiUrl = "http://api.dolphin-emulator.com/wiki.html?id=[GAME_ID]&name=[GAME_NAME]"; + wikiUrl = ReplaceAll(wikiUrl, "[GAME_ID]", UriEncode(iso->GetUniqueID())); + if (UriEncode(iso->GetName(0)).length() < 100) + wikiUrl = ReplaceAll(wikiUrl, "[GAME_NAME]", UriEncode(iso->GetName(0))); + else + wikiUrl = ReplaceAll(wikiUrl, "[GAME_NAME]", ""); + + WxUtils::Launch(wikiUrl.c_str()); +} + void CGameListCtrl::OnInstallWAD(wxCommandEvent& WXUNUSED (event)) { const GameListItem *iso = GetSelectedISO(); diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.h b/Source/Core/DolphinWX/Src/GameListCtrl.h index e7eaa8abc6..8a9a993140 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.h +++ b/Source/Core/DolphinWX/Src/GameListCtrl.h @@ -98,6 +98,7 @@ private: void OnKeyPress(wxListEvent& event); void OnSize(wxSizeEvent& event); void OnProperties(wxCommandEvent& event); + void OnWiki(wxCommandEvent& event); void OnOpenContainingFolder(wxCommandEvent& event); void OnOpenSaveFolder(wxCommandEvent& event); void OnExportSave(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index d336447504..bbaa9bb9ad 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -92,6 +92,7 @@ enum IDM_RESTART, IDM_CHANGEDISC, IDM_PROPERTIES, + IDM_GAMEWIKI, IDM_LOAD_WII_MENU, IDM_INSTALL_WII_MENU, IDM_CONNECT_WIIMOTE1,