diff --git a/appleauth/auth.cpp b/appleauth/auth.cpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/appleauth/auth.cpp @@ -0,0 +1 @@ + diff --git a/appleauth/build.cpp b/appleauth/build.cpp new file mode 100644 index 0000000..4034d01 --- /dev/null +++ b/appleauth/build.cpp @@ -0,0 +1,74 @@ +#include "helper.h" +#include "c.h" +#include "ld.h" +#include "tier1/utlstring.h" +#include "tier1/commandline.h" + +ADD_DEPENDENCY_BUILD_FILE(tier0, "../tier0/build.cpp") +ADD_DEPENDENCY_BUILD_FILE(tier1, "../tier1/build.cpp") +ADD_DEPENDENCY_BUILD_FILE(tier2, "../tier2/build.cpp") +ADD_DEPENDENCY_BUILD_FILE(http, "../http/build.cpp") + +DECLARE_BUILD_STAGE(appleauth) +{ + CProject_t compileProject = {}; + LinkProject_t ldProject = {}; + + compileProject.m_szName = "appleauth"; + compileProject.files = { + "auth.cpp" + }; + compileProject.includeDirectories = {"../public"}; + compileProject.bFPIC = true; + ldProject = ccompiler->Compile(&compileProject); + ldProject.objects.AppendTail({GET_PROJECT_LIBRARY(tier1, "tier1")}); + ldProject.objects.AppendTail({GET_PROJECT_LIBRARY(tier2, "tier2")}); + ldProject.linkType = ELINK_DYNAMIC_LIBRARY; + + CUtlString szOutputProject = linker->Link(&ldProject); + + ADD_OUTPUT_OBJECT("appleauth", szOutputProject) + + return 0; +}; + +DECLARE_BUILD_STAGE(appleauth_test) +{ + + CProject_t compileProject = {}; + LinkProject_t ldProject = {}; + + filesystem2->MakeDirectory("build"); + filesystem2->CopyFile("build",GET_PROJECT_LIBRARY(funnyhttp, "funnyhttp")); + filesystem2->CopyFile("build",GET_PROJECT_LIBRARY(appleauth, "appleauth")); + filesystem2->CopyFile("build",GET_PROJECT_LIBRARY(tier0, "tier0")); + + compileProject.m_szName = "appleauth"; + compileProject.files = { + "test.cpp" + }; + compileProject.includeDirectories = {"../public"}; + compileProject.bFPIC = true; + ldProject = ccompiler->Compile(&compileProject); + ldProject.libraryObjects = { + GET_PROJECT_LIBRARY(tier1, "tier1"), + GET_PROJECT_LIBRARY(tier2, "tier2"), + }; + ldProject.libraries = { + "tier0", + }; + ldProject.libraryDirectories = { + "build", + }; + ldProject.linkType = ELINK_EXECUTABLE; + CUtlString szOutputDir = linker->Link(&ldProject); + + filesystem2->CopyFile("build",szOutputDir); + + + CUtlVector args = {}; + runner->Run("build/appleauth", args); + runner->Wait(); + + return 0; +}; diff --git a/appleadi/auth.cpp b/appleauth/test.cpp similarity index 100% rename from appleadi/auth.cpp rename to appleauth/test.cpp diff --git a/fpc/build.cpp b/fpc/build.cpp index 7a65bdb..23eab5c 100644 --- a/fpc/build.cpp +++ b/fpc/build.cpp @@ -7,7 +7,7 @@ ADD_DEPENDENCY_BUILD_FILE(tier0, "../tier0/build.cpp"); ADD_DEPENDENCY_BUILD_FILE(tier1, "../tier1/build.cpp"); ADD_DEPENDENCY_BUILD_FILE(tier2, "../tier2/build.cpp"); -ADD_DEPENDENCY_BUILD_FILE(apple, "apple/build.cpp"); +ADD_DEPENDENCY_BUILD_FILE(appleauth, "../appleauth/build.cpp"); CUtlVector g_fpcFiles = { @@ -139,14 +139,9 @@ DECLARE_BUILD_STAGE(install) CUtlString szTier0 = GET_PROJECT_LIBRARY(tier0, "tier0"); CUtlString szTier1 = GET_PROJECT_LIBRARY(tier1, "tier1"); CUtlString szTier2 = GET_PROJECT_LIBRARY(tier2, "tier2"); - CUtlString xtool = GET_PROJECT_LIBRARY(xtool_cpp, "xtool"); filesystem2->CopyFile("build/fpc_temp", szExe); filesystem2->CopyFile("build/libfpc_temp.so", szLibFpc); - if (xtool) - { - filesystem2->CopyFile("build", xtool); - } /* filesystem2->CopyFile("build/libtier1.a", szTier1); diff --git a/fpc/library/ld.cpp b/fpc/library/ld.cpp index 4a4585b..dea45e9 100644 --- a/fpc/library/ld.cpp +++ b/fpc/library/ld.cpp @@ -82,6 +82,14 @@ CUtlString ILinker::Link( LinkProject_t *pProject ) break; } } + for (auto object: pProject->libraryObjects) + { + if (filesystem2->ShouldRecompile(object,szOutputFile)) + { + shouldRecompile = true; + break; + } + } if (!shouldRecompile) goto compiled; diff --git a/http/build.cpp b/http/build.cpp index 5c62439..3b6f62b 100644 --- a/http/build.cpp +++ b/http/build.cpp @@ -35,42 +35,3 @@ DECLARE_BUILD_STAGE(funnyhttp) return 0; }; -DECLARE_BUILD_STAGE(test) -{ - - CProject_t compileProject = {}; - LinkProject_t ldProject = {}; - - filesystem2->MakeDirectory("build"); - filesystem2->CopyFile("build",GET_PROJECT_LIBRARY(funnyhttp, "funnyhttp")); - filesystem2->CopyFile("build",GET_PROJECT_LIBRARY(tier0, "tier0")); - - compileProject.m_szName = "funnyhttptest"; - compileProject.files = { - "test.cpp" - }; - compileProject.includeDirectories = {"../public"}; - compileProject.bFPIC = true; - ldProject = ccompiler->Compile(&compileProject); - ldProject.libraryObjects = { - GET_PROJECT_LIBRARY(tier1, "tier1"), - GET_PROJECT_LIBRARY(tier2, "tier2"), - }; - ldProject.libraries = { - "tier0", - }; - ldProject.libraryDirectories = { - "build", - }; - ldProject.linkType = ELINK_EXECUTABLE; - CUtlString szOutputDir = linker->Link(&ldProject); - - filesystem2->CopyFile("build",szOutputDir); - - - CUtlVector args = {}; - runner->Run("build/funnyhttptest", args); - runner->Wait(); - - return 0; -}; diff --git a/http/client.cpp b/http/client.cpp index 3f0341c..b19c38a 100644 --- a/http/client.cpp +++ b/http/client.cpp @@ -1,3 +1,4 @@ + #include "http/http.h" #include "tier1/interface.h" #include "tier1/utlstring.h" @@ -6,18 +7,34 @@ #include "fcntl.h" #include "openssl/ssl.h" #include "openssl/err.h" +#include "arpa/inet.h" abstract_class CHTTPClient: public IHTTPClient { public: - virtual void Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const char *data ) override; + void ConnectToServer(); + void CloseConnection(); + + virtual void Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const void *data ) override; virtual void Get( const char *szResource, HTTPHeader_t *pHeader ) override; virtual HTTPResponse_t GetResponse() override; - HTTPResponse_t ParseResponse( const char *szMessage ); + virtual bool WebSocket_Connect( const char *szResource ) override; + virtual void WebSocket_Close( void ) override; + virtual void WebSocket_SendText( const char *szData ) override; + virtual CUtlString WebSocket_RecvText() override; + virtual void WebSocket_SendBinary( size_t uSize, const void *pData ) override; + virtual WebSocketPacket_t WebSocket_RecvBinary() override; + + ssize_t Write( void *pData, ssize_t uSize ); + ssize_t Read( void *pData, ssize_t uSize ); + + HTTPResponse_t ParseResponse( const char *szMessage, uint32_t uDataSize ); const char *GetVersion(); + HTTPHeaderParam_t ParseHeaderParams( const char *szHeaderLine ); const char *m_szHostName; + uint16_t m_uPort; bool m_bIsSecure; SSL *m_pSSL; SSL_CTX *m_pSSLCtx; @@ -25,9 +42,37 @@ public: int m_iFileDescriptor; }; -void CHTTPClient::Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const char *data ) +void CHTTPClient::Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const void *data ) { + if (pHeader == NULL) + return; + ConnectToServer(); + + CUtlString szMessage = CUtlString( + "POST %s HTTP/%s\r\n", + szResource, GetVersion()); + CUtlString szHeader = CUtlString( + "Host: %s\r\n" + "Content-Length: %u\r\n", + m_szHostName, + uDataSize + ); + + CUtlString szCombined; + int i = 0; + + for ( i = 0; i < pHeader->m_nParamCount; i++ ) + { + szHeader.AppendTail(CUtlString("%s: %s\r\n", pHeader->m_params[i].m_szParamName.GetString(), pHeader->m_params[i].m_szValue.GetString())); + } + + szCombined = szMessage; + szCombined.AppendTail(szHeader); + szCombined.AppendTail("\r\n"); + + Write(szCombined.GetString(), szCombined.GetLenght()); + Write((void*)data, uDataSize); } void CHTTPClient::Get( const char *szResource, HTTPHeader_t *pHeader ) @@ -35,6 +80,8 @@ void CHTTPClient::Get( const char *szResource, HTTPHeader_t *pHeader ) if (pHeader == NULL) return; + ConnectToServer(); + CUtlString szMessage = CUtlString( "GET %s HTTP/%s\r\n", szResource, GetVersion()); @@ -48,53 +95,54 @@ void CHTTPClient::Get( const char *szResource, HTTPHeader_t *pHeader ) for ( i = 0; i < pHeader->m_nParamCount; i++ ) { - szHeader.AppendTail(CUtlString("%s: %s\r\n", pHeader->m_params[i].m_szParamName, pHeader->m_params[i].m_szValue)); + szHeader.AppendTail(CUtlString("%s: %s\r\n", pHeader->m_params[i].m_szParamName.GetString(), pHeader->m_params[i].m_szValue.GetString())); } szCombined = szMessage; szCombined.AppendTail(szHeader); szCombined.AppendTail("\r\n"); - if (m_bIsSecure) - SSL_write(m_pSSL, szCombined.GetString(), szCombined.GetLenght()); - else - write(m_iFileDescriptor, szCombined.GetString(), szCombined.GetLenght()); + Write(szCombined.GetString(), szCombined.GetLenght()); } HTTPResponse_t CHTTPClient::GetResponse() { CUtlResizableBuffer szCharBuffer(0); - char response[4096]; + char response[4096] = {}; int n; int nPreviousSize = 0; - if (m_bIsSecure) +readSocket: + + n = Read(response, sizeof(response)); + if (n == -1) + goto responseDone; + + + szCharBuffer.Resize(nPreviousSize+n); + V_memcpy((char*)szCharBuffer.GetMemory()+nPreviousSize, response, n); + nPreviousSize += n; + V_printf("%s\n",response); + + // HTTP 1.0 reacts either to socket being closed or Content-Lenght + // HTTP 1.1 has Transfer-Encoding: chunked, which we need to respect + // Still some response codes may not include a body + if ( n > 0 ) { -secureRead: - n = SSL_read(m_pSSL, response, sizeof(response)); - szCharBuffer.Resize(nPreviousSize+n); - V_memcpy((char*)szCharBuffer.GetMemory()+nPreviousSize, response, n); - nPreviousSize += n; - if (SSL_pending(m_pSSL)>0) - goto secureRead; - } - else { -httpRead: - n = read(m_iFileDescriptor, response, sizeof(response)); - V_printf("%i\n",n); - szCharBuffer.Resize(nPreviousSize+n+1); - szCharBuffer[nPreviousSize+n] = 0; - V_memcpy((char*)szCharBuffer.GetMemory()+nPreviousSize, response, n); - nPreviousSize += n; - goto httpRead; - } + HTTPResponse_t r = ParseResponse(szCharBuffer, szCharBuffer.GetSize()); + if (r.m_bIsComplete) + goto responseDone; + // these do not provide body + } + // there is some data so go and read back again + goto readSocket; +responseDone: - szCharBuffer.Resize(n+1); - return ParseResponse(szCharBuffer); + return ParseResponse(szCharBuffer, szCharBuffer.GetSize()); } -HTTPResponse_t CHTTPClient::ParseResponse( const char *szMessage ) +HTTPResponse_t CHTTPClient::ParseResponse( const char *szMessage, uint32_t uDataSize ) { char cPreviousCharacter = 0; char cCurrentCharacter = 0; @@ -115,12 +163,18 @@ HTTPResponse_t CHTTPClient::ParseResponse( const char *szMessage ) if (bIsMessage) { uint32_t uResult = 0; - V_sscanf(szBuffer, "HTTP/1.1 %i", &uResult); + while (szBuffer[0] != ' ') + szBuffer.RemoveHead(1); + while (szBuffer[0] == ' ') + szBuffer.RemoveHead(1); + V_sscanf(szBuffer, "%i", &uResult); response.m_uCode = uResult; } + if (szBuffer == "") + break; + if (!bIsMessage) + headers.AppendTail(ParseHeaderParams(szBuffer)); bIsMessage = false; - if (szBuffer == "") - break; szBuffer = ""; cPreviousCharacter = 0; cCurrentCharacter = *pcCurrentCharacter++; @@ -133,12 +187,73 @@ HTTPResponse_t CHTTPClient::ParseResponse( const char *szMessage ) cPreviousCharacter = cCurrentCharacter; }; + switch (response.m_uCode) + { + case 100: + case 101: + case 204: + case 205: + case 304: + response.m_bIsComplete = true; + return response; + default: + break; + } + + bool bParseInChunks = false; + uint64_t uBodySize; + // check content lenght + for ( int i = 0; i < response.m_params.GetSize(); i++ ) + { + if ( !V_stricmp( response.m_params[i].m_szParamName, "Content-Length" ) ) + { + uBodySize = atoll(response.m_params[i].m_szValue); + }; + + + if ( !V_stricmp( response.m_params[i].m_szParamName, "Transfer-Encoding" ) ) + { + if ( !V_stricmp( response.m_params[i].m_szValue, "Chunked" ) ) + { + bParseInChunks = true; + }; + }; + } pcCurrentCharacter++; - uint32_t nDataLen = V_strlen(pcCurrentCharacter); - data = CUtlBuffer(nDataLen+1); - V_strcpy(data.GetMemory(), pcCurrentCharacter); - data[nDataLen] = 0; - response.m_message = data; + if ( !bParseInChunks ) + { + uint32_t nDataLen = uDataSize-(pcCurrentCharacter-szMessage); + data = CUtlBuffer(nDataLen+1); + V_memcpy(data.GetMemory(), pcCurrentCharacter, nDataLen); + data[nDataLen] = 0; + response.m_params = CUtlBuffer(headers.GetSize()); + for (int i = 0; i < headers.GetSize(); i++ ) + { + response.m_params[i] = headers[i]; + } + response.m_message = data; + + } else { + szBuffer = ""; + while (*pcCurrentCharacter) + { + + cCurrentCharacter = *pcCurrentCharacter; + if ( cPreviousCharacter == '\r') + { + if ( cCurrentCharacter == '\n') + { + uint32_t uChunkSize; + uChunkSize = strtol(szBuffer, NULL, 0); + } + } + if (cPreviousCharacter != 0) + szBuffer.AppendTail(cPreviousCharacter); + pcCurrentCharacter++; + + cPreviousCharacter = cCurrentCharacter; + } + } return response; } @@ -148,57 +263,76 @@ const char *CHTTPClient::GetVersion() return "1.1"; } -abstract_class CHTTPClientManager: public IHTTPClientManager +HTTPHeaderParam_t CHTTPClient::ParseHeaderParams( const char *szHeaderLine ) { -public: - CHTTPClientManager(); - virtual IHTTPClient *Connect( const char *szUrl, bool bSecure ) override; - virtual void Disconnect( IHTTPClient *szConnection ) override; -}; + const char *psz = szHeaderLine; + CUtlString szName; + CUtlString szValue; -IHTTPClient *CHTTPClientManager::Connect( const char *szUrl, bool bSecure ) + int stage = 0; + while (*psz) + { + if (stage == 0) + { + if (*psz == ':') + stage = 1; + else + szName.AppendTail(*psz); + } else if (stage == 1) + { + if (*psz != ' ') + break; + } + psz++; + } + szValue = psz; + return {szName, szValue}; +} +void CHTTPClient::ConnectToServer() { struct hostent *pServerHostName = NULL; struct sockaddr_in serverAddress; int fd = 0; int err; - CHTTPClient *pClient; SSL_CTX *ctx; SSL *ssl; - pServerHostName = gethostbyname(szUrl); - if (!pServerHostName) - return NULL; + if (V_strcmp(m_szHostName, "localhost")) + { + pServerHostName = gethostbyname(m_szHostName); + if (!pServerHostName) + return; + } fd = socket(AF_INET, SOCK_STREAM, 0); if ( fd < 0 ) - return NULL; + return; V_memset(&serverAddress, 0, sizeof(serverAddress)); serverAddress.sin_family = AF_INET; - V_memcpy(&serverAddress.sin_addr.s_addr, pServerHostName->h_addr, pServerHostName->h_length); + if (!V_strcmp(m_szHostName, "localhost")) + inet_pton(AF_INET, "127.0.0.1", &serverAddress.sin_addr); + else + V_memcpy(&serverAddress.sin_addr.s_addr, pServerHostName->h_addr, pServerHostName->h_length); // https - if ( bSecure ) - serverAddress.sin_port = htons(443); - else - serverAddress.sin_port = htons(80); + serverAddress.sin_port = htons(m_uPort); err = connect(fd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)); if (err < 0) - return NULL; + return; - if (bSecure) + if (m_bIsSecure) { ctx = SSL_CTX_new(TLS_client_method()); if (!ctx) - return NULL; + return; ssl =SSL_new(ctx); if (!ssl) - return NULL; + return; SSL_set_fd(ssl, fd); - SSL_set_tlsext_host_name(ssl, szUrl); + SSL_set_tlsext_host_name(ssl, m_szHostName); int r = SSL_connect(ssl); if (r <= 0) @@ -206,19 +340,192 @@ IHTTPClient *CHTTPClientManager::Connect( const char *szUrl, bool bSecure ) ERR_print_errors_fp(stdout); SSL_free(ssl); SSL_CTX_free(ctx); - return NULL; + return; } }; - pClient = new CHTTPClient(); - pClient->m_iFileDescriptor = fd; - pClient->m_szHostName = szUrl; - if (bSecure) + m_iFileDescriptor = fd; + if (m_bIsSecure) { - pClient->m_bIsSecure = bSecure; - pClient->m_pSSL = ssl; - pClient->m_pSSLCtx = ctx; + m_pSSL = ssl; + m_pSSLCtx = ctx; } + + +} + +void CHTTPClient::CloseConnection() +{ + +} +bool CHTTPClient::WebSocket_Connect( const char *szResource ) +{ + HTTPResponse_t stResponse; + HTTPHeaderParam_t params[] = { + {"Upgrade", "websocket"}, + {"Connection", "Upgrade"}, + {"Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="}, + {"Sec-WebSocket-Protocol", "chat, superchat"}, + {"Sec-WebSocket-Version", "13"}, + }; + HTTPHeader_t stHeader = { + sizeof(params)/sizeof(params[0]), + params + }; + Get(szResource, &stHeader); + stResponse = GetResponse(); + // According to spec 101 is a good sign + if (stResponse.m_uCode == 101) + return true; + return false; +} + + +void CHTTPClient::WebSocket_Close( void ) +{ + +} + +enum EWebSocketOp +{ + WEBSOCKET_CONTINUE = 0, + WEBSOCKET_TEXT = 1, + WEBSOCKET_BINARY = 2, + WEBSOCKET_CLOSE = 8, + WEBSOCKET_PING = 9, + WEBSOCKET_PONG = 10, +}; + +struct WebSocketFrame_t +{ + EWebSocketOp nOpCode: 4; + uint8_t nReserved: 3; + uint8_t bFin: 1; + uint8_t nPayloadLenght: 7; + uint8_t bMasked: 1; +}; + +void CHTTPClient::WebSocket_SendText( const char *szData ) +{ + size_t uLen; + WebSocketFrame_t stFrame; + uLen = V_strlen(szData); + stFrame = (WebSocketFrame_t){ + .nOpCode = WEBSOCKET_TEXT, + .bFin = 1, + .bMasked = 1, + }; + // im too lazy to mask it + int iMask = 0; + + if ( uLen <= 125 ) + { + stFrame.nPayloadLenght = uLen; + Write(&stFrame, 2); + Write(&iMask, 4); + } + else if ( uLen <= 65535 ) + { + stFrame.nPayloadLenght = 126; + Write(&stFrame, 2); + uint16_t uLenN = htons(uLen); + Write(&uLenN, 2); + Write(&iMask, 4); + } + else + { + stFrame.nPayloadLenght = 127; + Write(&stFrame, 2); + Write(&iMask, 4); + Write(&uLen, 8); + } + Write((void*)szData, uLen); + +} + +CUtlString CHTTPClient::WebSocket_RecvText() +{ + WebSocketFrame_t stFrame; + size_t uLen = 0; + CUtlBuffer szText; + Read(&stFrame, 2); + if (stFrame.nPayloadLenght == 126) + { + Read(&uLen, 2); + } else if (stFrame.nPayloadLenght == 127) + { + Read(&uLen, 8); + } else { + uLen = stFrame.nPayloadLenght; + } + szText = CUtlBuffer(uLen+1); + Read(szText, uLen); + szText[uLen] = 0; + return szText.GetMemory(); +} + +void CHTTPClient::WebSocket_SendBinary( size_t uSize, const void *pData ) +{ + +} + +WebSocketPacket_t CHTTPClient::WebSocket_RecvBinary() +{ + +} + + +ssize_t CHTTPClient::Write( void *pData, ssize_t uSize ) +{ + if (m_bIsSecure) + return SSL_write(m_pSSL, pData, uSize); + else + return write(m_iFileDescriptor, pData, uSize); +} + +ssize_t CHTTPClient::Read( void *pData, ssize_t uSize ) +{ + ssize_t n; + if ( m_bIsSecure ) + { + n = SSL_read(m_pSSL, pData, uSize); + if (n == 0) + return -1; + } + else + { + n = read(m_iFileDescriptor, pData, uSize); + if (n == -1) + return -1; + } + return n; +} + + + +abstract_class CHTTPClientManager: public IHTTPClientManager +{ +public: + CHTTPClientManager(); + virtual IHTTPClient *Connect( const char *szUrl, bool bSecure, uint16_t *pPort ) override; + virtual void Disconnect( IHTTPClient *szConnection ) override; +}; + +IHTTPClient *CHTTPClientManager::Connect( const char *szUrl, bool bSecure, uint16_t *pPort ) +{ + CHTTPClient *pClient; + pClient = new CHTTPClient(); + if (pPort) + pClient->m_uPort = *pPort; + else + { + if (bSecure) + pClient->m_uPort = 443; + else + pClient->m_uPort = 80; + } + pClient->m_szHostName = szUrl; + pClient->m_bIsSecure = bSecure; return pClient; } @@ -238,3 +545,4 @@ CHTTPClientManager::CHTTPClientManager() CHTTPClientManager s_HttpClientManager; EXPOSE_INTERFACE_GLOBALVAR(IHTTPClientManager, CHTTPClientManager, HTTP_CLIENT_INTERFACE_VERSION, s_HttpClientManager); + diff --git a/http/test.cpp b/http/test.cpp index b78b908..dc2294d 100644 --- a/http/test.cpp +++ b/http/test.cpp @@ -9,7 +9,7 @@ int main() g_pHttpClientMgr = (IHTTPClientManager*)pHttpFactory(HTTP_CLIENT_INTERFACE_VERSION, NULL); if ( !g_pHttpClientMgr ) return 0; - IHTTPClient *pClient = g_pHttpClientMgr->Connect("ani.sidestore.io", true); + IHTTPClient *pClient = g_pHttpClientMgr->Connect("www.example.com", true, NULL); printf("%p\n",pClient); if ( pClient == NULL ) return 0; diff --git a/public/appleauth/iauth.h b/public/appleauth/iauth.h new file mode 100644 index 0000000..6bc5f9b --- /dev/null +++ b/public/appleauth/iauth.h @@ -0,0 +1,16 @@ +#ifndef APPLE_AUTH_H +#define APPLE_AUTH_H + +#include "tier0/platform.h" +#include "tier2/iappsystem.h" + +abstract_class IAppleAuth: public IAppSystem +{ +public: + virtual void SubmitLoginData( const char *szEmail, const char *szPassword ) = 0; + virtual void Submit2FA( const char *szCode ) = 0; +}; + +IAppleAuth *AppleAuth(); + +#endif diff --git a/public/http/http.h b/public/http/http.h index d5c30d5..812fbe9 100644 --- a/public/http/http.h +++ b/public/http/http.h @@ -3,11 +3,12 @@ #include "tier0/platform.h" #include "tier1/utlvector.h" +#include "tier1/utlstring.h" struct HTTPHeaderParam_t { - const char *m_szParamName; - const char *m_szValue; + CUtlString m_szParamName; + CUtlString m_szValue; }; struct HTTPHeader_t @@ -21,21 +22,35 @@ struct HTTPResponse_t CUtlBuffer m_params; CUtlBuffer m_message; uint32_t m_uCode; - bool bIsValid; + bool m_bIsComplete; +}; + +struct WebSocketPacket_t +{ + size_t m_uSize; + void *m_pData; }; abstract_class IHTTPClient { public: - virtual void Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const char *data ) = 0; + virtual void Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const void *data ) = 0; virtual void Get( const char *szResource, HTTPHeader_t *pHeader ) = 0; + + virtual bool WebSocket_Connect( const char *szResource ) = 0; + virtual void WebSocket_Close( void ) = 0; + virtual void WebSocket_SendText( const char *szData ) = 0; + virtual CUtlString WebSocket_RecvText() = 0; + virtual void WebSocket_SendBinary( size_t uSize, const void *pData ) = 0; + virtual WebSocketPacket_t WebSocket_RecvBinary() = 0; + virtual HTTPResponse_t GetResponse() = 0; }; abstract_class IHTTPClientManager { public: - virtual IHTTPClient *Connect( const char *szUrl, bool bSecure ) = 0; + virtual IHTTPClient *Connect( const char *szUrl, bool bSecure, uint16_t *pPort ) = 0; virtual void Disconnect( IHTTPClient *pClient ) = 0; }; diff --git a/public/tier0/platform.h b/public/tier0/platform.h index e106cf6..4d1c140 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -54,6 +54,23 @@ #define POSIX #endif +#define SWAP16(x) (uint16_t)((((x) >> 8) & 0x00FF) | \ + (((x) << 8) & 0xFF00)) + +#define SWAP32(x) (uint32_t)((((x) >> 24) & 0x000000FF) | \ + (((x) >> 8) & 0x0000FF00) | \ + (((x) << 8) & 0x00FF0000) | \ + (((x) << 24) & 0xFF000000)) + +#define SWAP64(x) ((uint64_t)( \ + (((x) >> 56) & 0x00000000000000FFULL) | \ + (((x) >> 40) & 0x000000000000FF00ULL) | \ + (((x) >> 24) & 0x0000000000FF0000ULL) | \ + (((x) >> 8) & 0x00000000FF000000ULL) | \ + (((x) << 8) & 0x000000FF00000000ULL) | \ + (((x) << 24) & 0x0000FF0000000000ULL) | \ + (((x) << 40) & 0x00FF000000000000ULL) | \ + (((x) << 56) & 0xFF00000000000000ULL) )) #define abstract_class class diff --git a/public/tier2/fileformats/json.h b/public/tier2/fileformats/json.h index e69de29..c1e14f2 100644 --- a/public/tier2/fileformats/json.h +++ b/public/tier2/fileformats/json.h @@ -0,0 +1,78 @@ +#ifndef TIER2_JSON_H +#define TIER2_JSON_H + +#include "tier0/platform.h" + +class IJSONObject; +class IJSONArray; +class IJSONValue; + +enum EJSONParameterType +{ + JSON_PARAMETER_NULL, + JSON_PARAMETER_STRING, + JSON_PARAMETER_NUMBER, + JSON_PARAMETER_BOOLEAN, + JSON_PARAMETER_ARRAY, + JSON_PARAMETER_OBJECT, +}; + +abstract_class IJSONArray +{ +public: + virtual uint32_t GetCount() = 0; + virtual IJSONObject *GetParameter( uint32_t i ) = 0; + + virtual void SetArray( uint32_t uCount, IJSONValue *pValue ) = 0; + + virtual void CopyTo( IJSONArray *pObject ) = 0; + virtual void Free() = 0; +}; + +abstract_class IJSONValue +{ +public: + virtual EJSONParameterType GetType( void ) = 0; + virtual const char *GetStringValue() = 0; + virtual float GetNumberValue() = 0; + virtual bool GetBooleanValue() = 0; + virtual IJSONArray *GetArray() = 0; + virtual IJSONObject *GetObject() = 0; + + virtual void MakeNULL() = 0; + virtual void SetStringValue( const char *szString ) = 0; + virtual void SetNumberValue( float fValue ) = 0; + virtual void SetBooleanValue( bool bValue ) = 0; + virtual void SetArrayValue( IJSONArray *pValue ) = 0; + virtual void SetObjectValue( IJSONObject *pValue ) = 0; + + virtual void CopyTo( IJSONValue *pObject ) = 0; + virtual void Free() = 0; +}; + +abstract_class IJSONObject +{ +public: + virtual IJSONValue *GetValue( const char *szName ) = 0; + virtual void SetValue( const char *szName, IJSONValue *pValue ) = 0; + + virtual void CopyTo( IJSONObject *pObject ) = 0; + virtual void Free() = 0; +}; + +abstract_class IJSONManager +{ +public: + virtual IJSONObject *CreateObject( ) = 0; + virtual void FreeObject( IJSONObject *pObject ) = 0; + virtual IJSONArray *CreateArray( ) = 0; + virtual void FreeArray( IJSONArray *pArray ) = 0; + virtual IJSONValue *CreateValue( ) = 0; + virtual void FreeValue( IJSONValue *pValue ) = 0; + + virtual IJSONObject *ReadString( const char *szString ) = 0; +}; + +IJSONManager *JSONManager(); + +#endif diff --git a/public/tier2/fileformats/plist.h b/public/tier2/fileformats/plist.h new file mode 100644 index 0000000..e115466 --- /dev/null +++ b/public/tier2/fileformats/plist.h @@ -0,0 +1,13 @@ +#ifndef TIER2_PLIST_H +#define TIER2_PLIST_H + +#include "tier2/fileformats/json.h" + +abstract_class IPropertyListManager +{ +public: + virtual IJSONObject *ReadString( const char *psz ) = 0; +}; + +IPropertyListManager *PropertyListManager(); +#endif diff --git a/public/tier2/fileformats/xml.h b/public/tier2/fileformats/xml.h new file mode 100644 index 0000000..fc062d3 --- /dev/null +++ b/public/tier2/fileformats/xml.h @@ -0,0 +1,69 @@ +#ifndef TIER2_XML_H +#define TIER2_XML_H + +#include "tier0/platform.h" +#include "tier1/utlstring.h" + +struct XMLParam_t +{ + CUtlString m_szName; + CUtlString m_szValue; +}; + +enum EXMLObjectType +{ + XML_OBJECT_ELEMENT, + XML_OBJECT_TEXT, + XML_OBJECT_COMMENT, + XML_OBJECT_CDATA, + XML_OBJECT_PROCESSING_INSTRUCTION, + XML_OBJECT_DOCUMENT_TYPE, +}; + +abstract_class IXMLObject +{ +public: + virtual EXMLObjectType GetType() = 0; + virtual const char *GetValue() = 0; + virtual void SetType( EXMLObjectType eType ) = 0; + virtual void SetValue( const char *psz ) = 0; + + virtual CUtlVector &GetParams() = 0; + + virtual CUtlVector &GetChildren() = 0; + + virtual void Free() = 0; + + inline IXMLObject *FindFirstTag( const char *szName ) + { + for ( auto &c: GetChildren() ) + { + if ( c->GetType() != XML_OBJECT_ELEMENT ) continue; + if ( V_strcmp(c->GetValue(), szName) ) continue; + return c; + } + return NULL; + }; +}; + +struct XMLFile_t +{ + IXMLObject *m_pRoot; + CUtlString m_szRootObjectName; + CUtlString m_szFPI; + CUtlString m_szURI; +}; + +abstract_class IXMLManager +{ +public: + virtual XMLFile_t ReadString( const char *szData ) = 0; + virtual CUtlString WriteString( IXMLObject *pObject ) = 0; + + virtual IXMLObject *CreateObject() = 0; + virtual void FreeObject( IXMLObject *pObject ) = 0; +}; + +IXMLManager *XMLManager(); + +#endif diff --git a/public/tier2/tokenizer.h b/public/tier2/tokenizer.h new file mode 100644 index 0000000..6fadea2 --- /dev/null +++ b/public/tier2/tokenizer.h @@ -0,0 +1,21 @@ +#ifndef TIER2_TOKENIZER_H +#define TIER2_TOKENIZER_H +#include "tier0/platform.h" +#include "tier1/utlstring.h" +#include "tier1/utlvector.h" + +struct Token_t +{ + CUtlString m_szValue; + bool m_bIsQuoted; + + uint32_t m_iLine; + uint32_t m_iCharacter; +}; + +typedef bool( *fnIsAlphabetSymbol )( char c ); +CUtlVector Tokenize( const char *szString ); +CUtlVector Tokenize( const char *szString, fnIsAlphabetSymbol pfnIsAlphabetSymbol ); + + +#endif diff --git a/appleadi/build.cpp b/public/tier2/uuid.h similarity index 100% rename from appleadi/build.cpp rename to public/tier2/uuid.h diff --git a/tier2/build.cpp b/tier2/build.cpp index 2f1e8b8..cd52ef0 100644 --- a/tier2/build.cpp +++ b/tier2/build.cpp @@ -7,6 +7,9 @@ CUtlVector tier2_CompiledFiles = { "fileformats/ini.cpp", "fileformats/json.cpp", + "fileformats/xml.cpp", + "fileformats/plist.cpp", + "tokenizer.cpp", "filesystem.cpp", }; diff --git a/tier2/fileformats/ini.cpp b/tier2/fileformats/ini.cpp index 1bb042c..33c83cb 100644 --- a/tier2/fileformats/ini.cpp +++ b/tier2/fileformats/ini.cpp @@ -142,8 +142,10 @@ IINIFile *CINIManager::ReadString( const char *psz ) if (bIsQuoted) { + // text within "" if (bIsSlash) { + // reading \n \t etc. bIsSlash = false; switch (c) { @@ -157,8 +159,9 @@ IINIFile *CINIManager::ReadString( const char *psz ) szStringValue.AppendTail('\n'); continue; case 't': - szStringValue.AppendTail('\n'); + szStringValue.AppendTail('\t'); continue; + // allow for strings to go to next line with by ending with backward slash case '\n': szStringValue.AppendTail('\n'); continue; @@ -167,16 +170,22 @@ IINIFile *CINIManager::ReadString( const char *psz ) continue; } } else { + // react to special symbols witin a string switch (c) { + // enables reading \n \t etc. case '\\': bIsSlash = true; continue; case '\n': + // newline + // we do want to end it to prevent parsing errors + // and there is no standart V_printf("line %i: new line was found but the string wasn't finished, did you forget to place \" in the end of the line?\n", nCurrentLine); case '"': + // end string bIsQuoted = false; if (szStringValue == 0) continue; @@ -190,6 +199,7 @@ IINIFile *CINIManager::ReadString( const char *psz ) } } else { + // " makes it use a string if (c == '"') { bIsQuoted = true; @@ -210,6 +220,9 @@ IINIFile *CINIManager::ReadString( const char *psz ) }; + // tokenize + // shitty tokenize + // must be reworked for ( int i = 0; i < tokens.GetSize(); i++ ) { if (tokens[i] == "]") diff --git a/tier2/fileformats/json.cpp b/tier2/fileformats/json.cpp index e69de29..46e0a5d 100644 --- a/tier2/fileformats/json.cpp +++ b/tier2/fileformats/json.cpp @@ -0,0 +1,401 @@ +#include "tier2/fileformats/json.h" +#include "tier2/tokenizer.h" + +abstract_class CJSONArray: public IJSONArray +{ +public: + virtual uint32_t GetCount() override; + virtual IJSONObject *GetParameter( uint32_t i ) override; + + virtual void SetArray( uint32_t uCount, IJSONValue *pValue ) override; + + virtual void CopyTo( IJSONArray *pObject ) override; + virtual void Free() override; +}; + +uint32_t CJSONArray::GetCount() +{ + +} + +IJSONObject *CJSONArray::GetParameter( uint32_t i ) +{ + +} + + +void CJSONArray::SetArray( uint32_t uCount, IJSONValue *pValue ) +{ + +} + +void CJSONArray::CopyTo( IJSONArray *pObject ) +{ + +} + +void CJSONArray::Free() +{ + +} + +abstract_class CJSONValue: public IJSONValue +{ +public: + virtual EJSONParameterType GetType( void ) override; + virtual const char *GetStringValue() override; + virtual float GetNumberValue() override; + virtual bool GetBooleanValue() override; + virtual IJSONArray *GetArray() override; + virtual IJSONObject *GetObject() override; + + virtual void MakeNULL() override; + virtual void SetStringValue( const char *szString ) override; + virtual void SetNumberValue( float fValue ) override; + virtual void SetBooleanValue( bool bValue ) override; + virtual void SetArrayValue( IJSONArray *pValue ) override; + virtual void SetObjectValue( IJSONObject *pValue ) override; + + virtual void CopyTo( IJSONValue *pObject ) override; + virtual void Free() override; + + EJSONParameterType m_eType; + CUtlString m_szString; + float m_fValue; + bool m_bValue; + IJSONArray *m_pArray; + IJSONObject *m_pObject; +}; + +EJSONParameterType CJSONValue::GetType( void ) +{ + return m_eType; +} + +const char * CJSONValue::GetStringValue() +{ + return m_szString; +} + +float CJSONValue::GetNumberValue() +{ + return m_fValue; +} + +bool CJSONValue::GetBooleanValue() +{ + return m_fValue; +} + +IJSONArray *CJSONValue::GetArray() +{ + return m_pArray; +} + +IJSONObject *CJSONValue::GetObject() +{ + return m_pObject; +} + + +void CJSONValue::MakeNULL() +{ + if ( GetType() == JSON_PARAMETER_OBJECT ) + { + JSONManager()->FreeObject(m_pObject); + m_pObject = NULL; + } + if ( GetType() == JSON_PARAMETER_ARRAY ) + { + + JSONManager()->FreeArray(m_pArray); + m_pArray = NULL; + } + if ( GetType() == JSON_PARAMETER_STRING ) + m_szString = NULL; +} + +void CJSONValue::SetStringValue( const char *szString ) +{ + MakeNULL(); + m_szString = szString; +} + +void CJSONValue::SetNumberValue( float fValue ) +{ + MakeNULL(); + m_fValue = fValue; +} + +void CJSONValue::SetBooleanValue( bool bValue ) +{ + MakeNULL(); + +} + +void CJSONValue::SetArrayValue( IJSONArray *pValue ) +{ + MakeNULL(); + +} + +void CJSONValue::SetObjectValue( IJSONObject *pValue ) +{ + MakeNULL(); + m_pObject = pValue; +} + + +void CJSONValue::CopyTo( IJSONValue *pObject ) +{ + MakeNULL(); +} + +void CJSONValue::Free() +{ + MakeNULL(); +} + + +abstract_class CJSONObject: public IJSONObject +{ +public: + virtual IJSONValue *GetValue( const char *szName ) override; + virtual void SetValue( const char *szName, IJSONValue *pValue ) override; + + virtual void CopyTo( IJSONObject *pObject ) override; + virtual void Free() override; + + struct JSONObjectParam_t + { + CUtlString m_szName; + IJSONValue *m_pValue; + }; + CUtlVector m_params; +}; + +IJSONValue *CJSONObject::GetValue( const char *szName ) +{ + int i; + JSONObjectParam_t *pParam; + for ( i = 0; i < m_params.GetSize(); i++ ) + { + if ( m_params[i].m_szName != szName ) + continue; + return m_params[i].m_pValue; + } + return NULL; + +} + +void CJSONObject::SetValue( const char *szName, IJSONValue *pValue ) +{ + int i; + JSONObjectParam_t *pParam; + for ( i = 0; i < m_params.GetSize(); i++ ) + { + if ( m_params[i].m_szName != szName ) + continue; + + + // Scary + if ( pValue == NULL ) + m_params.RemoveAt(i); + else + m_params[i].m_pValue = pValue; + return; + } + if ( pValue == NULL ) + return; + m_params.AppendTail({szName, pValue}); +} + + +void CJSONObject::CopyTo( IJSONObject *pObject ) +{ + +} + +void CJSONObject::Free() +{ + +} + +abstract_class CJSONManager: public IJSONManager +{ +public: + virtual IJSONObject *CreateObject( ) override; + virtual void FreeObject( IJSONObject *pObject ) override; + virtual IJSONArray *CreateArray( ) override; + virtual void FreeArray( IJSONArray *pArray ) override; + virtual IJSONValue *CreateValue( ) override; + virtual void FreeValue( IJSONValue *pValue ) override; + +private: + static bool ExpectedToken( Token_t &token, const char *szValue ); + static CUtlString GetQuotedToken( Token_t &token ); + IJSONObject *ParseObject( Token_t *&pToken, const Token_t *pEnding ); + IJSONArray *ParseArray( Token_t *&pToken, const Token_t *pEnding ); + IJSONValue *ParseValue( Token_t *&pToken, const Token_t *pEnding ); + virtual IJSONObject *ReadString( const char *szString ) override; +}; + +IJSONObject *CJSONManager::CreateObject( ) +{ + return new CJSONObject; +} + +void CJSONManager::FreeObject( IJSONObject *pObject ) +{ + +} + +IJSONArray *CJSONManager::CreateArray( ) +{ + +} + +void CJSONManager::FreeArray( IJSONArray *pArray ) +{ + +} + +IJSONValue *CJSONManager::CreateValue( ) +{ + return new CJSONValue; +} + +void CJSONManager::FreeValue( IJSONValue *pValue ) +{ + +} + +#define NEXT_TOKEN() \ +pToken++; \ +if (pToken == pEnding) \ + goto eof \ + +bool CJSONManager::ExpectedToken( Token_t &token, const char *szValue ) +{ + if ( token.m_szValue == szValue && !token.m_bIsQuoted ) + return true; + return false; +} +CUtlString CJSONManager::GetQuotedToken( Token_t &token ) +{ + if ( token.m_bIsQuoted ) + return token.m_szValue; + return NULL; +} + +IJSONObject *CJSONManager::ParseObject( Token_t *&pToken, const Token_t *pEnding ) +{ + IJSONObject *pObject; + CUtlString szParamName; + IJSONValue *pValue; + + if ( !ExpectedToken(*(pToken), "{") ) + return NULL; + NEXT_TOKEN(); + pObject = CreateObject(); + + // object might be empty + if ( ExpectedToken(*pToken, "}") ) + { + NEXT_TOKEN(); + return pObject; + } + + while(true) + { + szParamName = NULL; + pValue = NULL; + if ( GetQuotedToken(*pToken) == NULL ) + goto not_quoted; + + szParamName = pToken->m_szValue; + NEXT_TOKEN(); + + if ( !ExpectedToken(*pToken, ":") ) + goto not_colon; + NEXT_TOKEN(); + + pValue = ParseValue(pToken, pEnding); + pObject->SetValue(szParamName, pValue); + + if ( !ExpectedToken(*pToken, ",") ) + { + if ( !ExpectedToken(*pToken, "}") ) + { + goto not_comma; + } + return pObject; + } + NEXT_TOKEN(); + } + return pObject; +not_comma: + V_printf("%i: comma (,) or } was expected but got %s\n", pToken->m_iLine, pToken->m_szValue.GetString()); + return NULL; +not_colon: + V_printf("%i: colon (:)was expected but got %s\n", pToken->m_iLine, pToken->m_szValue.GetString()); + return NULL; + +not_quoted: + V_printf("%s was not quoted\n", szParamName.GetString()); + return NULL; + +eof: + V_printf("EOF\n"); + return NULL; +} + +IJSONArray *CJSONManager::ParseArray( Token_t *&pToken, const Token_t *pEnding ) +{ + return NULL; +eof: + V_printf("EOF\n"); + return NULL; +} + +IJSONValue *CJSONManager::ParseValue( Token_t *&pToken, const Token_t *pEnding ) +{ + IJSONObject *pObject = ParseObject(pToken, pEnding); + IJSONArray *pArray = NULL; + IJSONValue *pValue = CreateValue(); + if (pObject) + { + pValue->SetObjectValue(pObject); + return pValue; + } + if ( GetQuotedToken(*pToken) != NULL ) + { + pValue->SetStringValue(pToken->m_szValue); + NEXT_TOKEN(); + return pValue; + } + return NULL; +eof: + V_printf("EOF\n"); + return NULL; +} + + +IJSONObject *CJSONManager::ReadString( const char *psz ) +{ + CUtlVector tokens; + CUtlVector stack; + IJSONObject *pGlobalObject = NULL; + + tokens = Tokenize(psz); + Token_t *pCurrentToken = tokens.GetData(); + pGlobalObject = ParseObject(pCurrentToken, tokens.end().m_pCurrent); + + return pGlobalObject; +}; + +IJSONManager *JSONManager() +{ + static CJSONManager mgr; + return &mgr; +} diff --git a/tier2/fileformats/plist.cpp b/tier2/fileformats/plist.cpp new file mode 100644 index 0000000..06fe2fd --- /dev/null +++ b/tier2/fileformats/plist.cpp @@ -0,0 +1,69 @@ +#include "tier2/fileformats/xml.h" +#include "tier2/fileformats/plist.h" + +class CPropertyListManager: public IPropertyListManager +{ +public: + IJSONObject *ReadDict( IXMLObject *pDict ); + virtual IJSONObject *ReadString( const char *psz ) override; +}; + +IJSONObject *CPropertyListManager::ReadString( const char *psz ) +{ + XMLFile_t file = XMLManager()->ReadString(psz); + IJSONObject *pObject; + + IXMLObject *pList = file.m_pRoot->FindFirstTag(file.m_szRootObjectName); + if (pList == NULL) + return NULL; + + IXMLObject *pDict = pList->FindFirstTag("dict"); + if (pDict == NULL) + return NULL; + + + pObject = ReadDict(pDict); + return pObject; +} +IJSONObject *CPropertyListManager::ReadDict( IXMLObject *pDict ) +{ + CUtlString szKeyToCreate = NULL; + IJSONObject *pObject = JSONManager()->CreateObject(); + for ( auto &c: pDict->GetChildren() ) + { + if (c->GetType() != XML_OBJECT_ELEMENT) + continue; + if ( !V_strcmp(c->GetValue(), "key")) + { + szKeyToCreate = c->GetChildren()[0]->GetValue(); + } + if ( !V_strcmp(c->GetValue(), "string")) + { + if ( szKeyToCreate == NULL ) + continue; + IJSONValue *pVal = JSONManager()->CreateValue(); + if (c->GetChildren().GetSize()>0) + pVal->SetStringValue(c->GetChildren()[0]->GetValue()); + else + pVal->SetStringValue(""); + pObject->SetValue(szKeyToCreate, pVal); + szKeyToCreate = NULL; + } + if ( !V_strcmp(c->GetValue(), "dict")) + { + if ( szKeyToCreate == NULL ) + continue; + IJSONValue *pVal = JSONManager()->CreateValue(); + pVal->SetObjectValue(ReadDict(c)); + pObject->SetValue(szKeyToCreate, pVal); + szKeyToCreate = NULL; + } + } + return pObject; +} + +IPropertyListManager *PropertyListManager() +{ + static CPropertyListManager mgr = {}; + return &mgr; +} diff --git a/tier2/fileformats/xml.cpp b/tier2/fileformats/xml.cpp new file mode 100644 index 0000000..d3cc753 --- /dev/null +++ b/tier2/fileformats/xml.cpp @@ -0,0 +1,420 @@ +#include "tier2/fileformats/xml.h" +#include "tier2/tokenizer.h" + +class CXMLObject: public IXMLObject +{ +public: + virtual EXMLObjectType GetType() override; + virtual const char *GetValue() override; + virtual void SetType( EXMLObjectType eType ) override; + virtual void SetValue( const char *psz ) override; + virtual CUtlVector &GetChildren() override; + virtual CUtlVector &GetParams() override; + virtual void Free() override; + + EXMLObjectType m_eType; + CUtlString m_szValue; + CUtlVector m_children; + CUtlVector m_params; +}; + +EXMLObjectType CXMLObject::GetType() +{ + return m_eType; +} + +const char *CXMLObject::GetValue() +{ + return m_szValue.GetString(); +} + +void CXMLObject::SetType( EXMLObjectType eType ) +{ + m_eType = eType; +} + +void CXMLObject::SetValue( const char *psz ) +{ + m_szValue = psz; +} + + +CUtlVector &CXMLObject::GetChildren() +{ + return m_children; +} + +CUtlVector &CXMLObject::GetParams() +{ + return m_params; +} + +void CXMLObject::Free() +{ + +} + + +class CXMLManager: public IXMLManager +{ +public: + virtual XMLFile_t ReadString( const char *szData ) override; + virtual CUtlString WriteString( IXMLObject *pObject ) override; + + virtual IXMLObject *CreateObject() override; + virtual void FreeObject( IXMLObject *pObject ) override; + + IXMLObject *ReadTagParams( CUtlString szTag ); + XMLFile_t ReadDoctype( const char *szData ); + + bool BIsValidAtStart( char c ); + bool BIsValidAtMid( char c ); + void SkipWhiteSpaces( const char *&psz ); +}; + +static char XML_TAG[] = "<"; +static char XML_TAG_END[] = ">"; +static char XML_SELF_CLOSE_END[] = "/>"; +static char XML_CLOSE_TAG[] = ""; + +XMLFile_t CXMLManager::ReadString( const char *szString ) +{ + CUtlString szTagStack = {}; + CUtlString szRootObjectName; + IXMLObject *pRootObject = CreateObject(); + IXMLObject *pLastObject = pRootObject; + CUtlVector stack = {pRootObject}; + + enum EXMLParsingMode + { + XML_PARSING_MODE_TEXT, + XML_PARSING_MODE_PREPROCESS_TAG, + XML_PARSING_MODE_TAG, + XML_PARSING_MODE_CLOSE_TAG, + XML_PARSING_MODE_DOCTYPE, + XML_PARSING_MODE_COMMENT, + } eMode = XML_PARSING_MODE_TEXT; + + const char *psz = szString; + CUtlString szTag = ""; + CUtlString szText = ""; + XMLFile_t stFile = {}; + while (*psz) + { + switch (eMode) + { + case XML_PARSING_MODE_TEXT: + if (!V_strncmp(XML_DOCTYPE, psz, sizeof(XML_DOCTYPE)-1)) + { + psz+=sizeof(XML_DOCTYPE)-1; + szTag = NULL; + + eMode = XML_PARSING_MODE_DOCTYPE; + if (szText != NULL) + { + IXMLObject *pText = CreateObject(); + pText->SetType(XML_OBJECT_TEXT); + pText->SetValue(szText); + pLastObject->GetChildren().AppendTail(pText); + szText = NULL; + } + + break; + } + if (!V_strncmp(XML_PREPROCESSOR_BEGIN, psz, sizeof(XML_PREPROCESSOR_BEGIN)-1)) + { + psz+=sizeof(XML_PREPROCESSOR_BEGIN)-1; + szTag = NULL; + + eMode = XML_PARSING_MODE_PREPROCESS_TAG; + if (szText != NULL) + { + IXMLObject *pText = CreateObject(); + pText->SetType(XML_OBJECT_TEXT); + pText->SetValue(szText); + pLastObject->GetChildren().AppendTail(pText); + szText = NULL; + } + break; + } + if (!V_strncmp(XML_CLOSE_TAG, psz, sizeof(XML_CLOSE_TAG)-1)) + { + psz+=sizeof(XML_CLOSE_TAG)-1; + szTag = NULL; + + eMode = XML_PARSING_MODE_CLOSE_TAG; + if (szText != NULL) + { + IXMLObject *pText = CreateObject(); + pText->SetType(XML_OBJECT_TEXT); + pText->SetValue(szText); + pLastObject->GetChildren().AppendTail(pText); + szText = NULL; + } + break; + } + if (!V_strncmp(XML_TAG, psz, sizeof(XML_TAG)-1)) + { + psz+=sizeof(XML_TAG)-1; + szTag = NULL; + + eMode = XML_PARSING_MODE_TAG; + if (szText != NULL) + { + IXMLObject *pText = CreateObject(); + pText->SetType(XML_OBJECT_TEXT); + pText->SetValue(szText); + pLastObject->GetChildren().AppendTail(pText); + szText = NULL; + } + break; + } + szText.AppendTail(*psz); + psz++; + break; + case XML_PARSING_MODE_PREPROCESS_TAG: + if (!V_strncmp(XML_PREPROCESSOR_END, psz, sizeof(XML_PREPROCESSOR_END)-1)) + { + psz+=sizeof(XML_PREPROCESSOR_END)-1; + eMode = XML_PARSING_MODE_TEXT; + V_printf("preprocess: %s\n", szTag.GetString()); + break; + } + szTag.AppendTail(*psz); + psz++; + break; + case XML_PARSING_MODE_TAG: + if (!V_strncmp(XML_SELF_CLOSE_END, psz, sizeof(XML_SELF_CLOSE_END)-1)) + { + psz+=sizeof(XML_SELF_CLOSE_END)-1; + eMode = XML_PARSING_MODE_TEXT; + IXMLObject *pObject = ReadTagParams(szTag); + pLastObject->GetChildren().AppendTail(pObject); + + break; + } + + if (!V_strncmp(XML_TAG_END, psz, sizeof(XML_TAG_END)-1)) + { + psz+=sizeof(XML_TAG_END)-1; + eMode = XML_PARSING_MODE_TEXT; + IXMLObject *pObject = ReadTagParams(szTag); + stack.AppendTail(pObject); + pLastObject->GetChildren().AppendTail(pObject); + pLastObject = pObject; + break; + } + + szTag.AppendTail(*psz); + psz++; + break; + case XML_PARSING_MODE_CLOSE_TAG: + if (!V_strncmp(XML_TAG_END, psz, sizeof(XML_TAG_END)-1)) + { + psz+=sizeof(XML_TAG_END)-1; + eMode = XML_PARSING_MODE_TEXT; + + + if (!V_strcmp(pLastObject->GetValue(), szTag)) + { + stack.RemoveTail(); + pLastObject = stack[stack.GetSize()-1]; + } + else + V_printf("\"%s\" != \"%s\"\n",pLastObject->GetValue(), szTag.GetString()); + break; + } + szTag.AppendTail(*psz); + psz++; + break; + case XML_PARSING_MODE_DOCTYPE: + if (!V_strncmp(XML_TAG_END, psz, sizeof(XML_TAG_END)-1)) + { + psz+=sizeof(XML_TAG_END)-1; + eMode = XML_PARSING_MODE_TEXT; + + stFile = ReadDoctype(szTag); + break; + } + szTag.AppendTail(*psz); + psz++; + break; + case XML_PARSING_MODE_COMMENT: + break; + }; + }; + stFile.m_pRoot = pRootObject; + return stFile; +} +CUtlString CXMLManager::WriteString( IXMLObject *pObject ) +{ +}; + +IXMLObject *CXMLManager::ReadTagParams( CUtlString szTag ) +{ + const char *psz = szTag; + CUtlVector params; + CUtlString szTagName = NULL; + CUtlString szParamName = NULL; + IXMLObject *pObject = CreateObject(); + // Read tag name + if (!BIsValidAtStart(*psz)) + { + V_printf("tag must start with letter or _"); + FreeObject(pObject); + return NULL; + } + + szTagName.AppendTail(*psz++); + while (BIsValidAtMid(*psz)) + { + szTagName.AppendTail(*psz); + psz++; + } + pObject->SetType(XML_OBJECT_ELEMENT); + pObject->SetValue(szTagName); + + while (*psz) + { + while (V_isspace(*psz)) + { + psz++; + continue; + } + if (*psz && (!V_isalpha(*psz) || *psz == '_')) + { + V_printf("parameter must start with letter or _\n"); + return {}; + } + while (*psz && (*psz != ' ' || *psz != '=')) + { + psz++; + continue; + } + while (V_isspace(*psz)) + { + psz++; + continue; + } + szParamName.AppendTail(*psz); + }; + return pObject; +}; + +static bool XMLGetWordSymbol( char c ) +{ + if (V_isalnum(c)) + return true; + switch(c) + { + case ':': + return true; + case '.': + return true; + case '_': + return true; + case '-': + return true; + default: + break; + } + return false; +}; + +XMLFile_t CXMLManager::ReadDoctype( const char *szData ) +{ + const char *psz = szData; + XMLFile_t stFile = {}; + CUtlString dtdType = NULL; + CUtlVector tokens; + int i = 0; + + if (!V_isspace(*psz)) + return stFile; + + SkipWhiteSpaces(psz); + + tokens = Tokenize(psz, XMLGetWordSymbol); + if ( tokens.GetSize() < i + 1 ) + return stFile; + if ( tokens[i].m_bIsQuoted ) + return stFile; + + stFile.m_szRootObjectName = tokens[i++].m_szValue; + + // parse ddt + if ( tokens.GetSize() < i + 1 ) + return stFile; + + if ( tokens[i].m_szValue == "PUBLIC" && !tokens[i].m_bIsQuoted ) + { + i++; + if ( tokens.GetSize() < i + 2 ) + return stFile; + if (!tokens[i].m_bIsQuoted || !tokens[i+1].m_bIsQuoted) + return stFile; + stFile.m_szFPI = tokens[i++].m_szValue; + stFile.m_szURI = tokens[i++].m_szValue; + } else if ( tokens[i].m_szValue == "SYSTEM" && !tokens[i].m_bIsQuoted ) + { + } else + { + + } + + + + // read root element + return stFile; +} + +bool CXMLManager::BIsValidAtStart( char c ) +{ + if (V_isalpha(c)) + return true; + if (c == '_') + return true; + return false; +} + +bool CXMLManager::BIsValidAtMid( char c ) +{ + if (V_isalnum(c)) + return true; + if (c == '_') + return true; + if (c == '-') + return true; + if (c == '.') + return true; + return false; +} +void CXMLManager::SkipWhiteSpaces( const char *&psz ) +{ + while (V_isspace(*psz)) + { + psz++; + continue; + } +} + +IXMLObject *CXMLManager::CreateObject() +{ + return new CXMLObject; +} + +void CXMLManager::FreeObject( IXMLObject *pObject ) +{ + pObject->Free(); + delete (CXMLObject*)pObject; +} + + +IXMLManager *XMLManager() +{ + static CXMLManager mgr; + return &mgr; +}; diff --git a/tier2/tokenizer.cpp b/tier2/tokenizer.cpp new file mode 100644 index 0000000..009a504 --- /dev/null +++ b/tier2/tokenizer.cpp @@ -0,0 +1,124 @@ +#include "tier2/tokenizer.h" + +static bool IsWordSymbol( char c ) +{ + if (V_isalnum(c)) + return true; + switch (c) + { + case '_': + return true; + default: + return false; + } +} + +CUtlVector Tokenize( const char *psz ) +{ + return Tokenize(psz, IsWordSymbol); +} + +CUtlVector Tokenize( const char *psz, fnIsAlphabetSymbol fnIsAlphabetSymbol ) +{ + CUtlVector tokens = {}; + size_t i = 0; + char c; + uint32_t nCurrentLine = 0; + uint32_t nCurrentCharacter = 0; + bool bIsQuoted = false; + bool bIsSlash = false; + CUtlString szStringValue; + + while (true) + { + c = psz[i]; + i++; + if (c == '\0') + break; + if (c == '\n') + { + nCurrentCharacter = 0; + nCurrentLine++; + } + + + if (bIsQuoted) + { + // text within "" + if (bIsSlash) + { + // reading \n \t etc. + bIsSlash = false; + switch (c) + { + case '\\': + szStringValue.AppendTail('\\'); + continue; + case '"': + szStringValue.AppendTail('"'); + continue; + case 'n': + szStringValue.AppendTail('\n'); + continue; + case 't': + szStringValue.AppendTail('\t'); + continue; + // allow for strings to go to next line with by ending with backward slash + case '\n': + szStringValue.AppendTail('\n'); + continue; + default: + szStringValue.AppendTail(c); + continue; + } + } else { + // react to special symbols witin a string + switch (c) + { + + // enables reading \n \t etc. + case '\\': + bIsSlash = true; + continue; + + case '\n': + // newline + // we do want to end it to prevent parsing errors + // and there is no standart + V_printf("line %i: new line was found but the string wasn't finished, did you forget to place \" in the end of the line?\n", nCurrentLine); + case '"': + // end string + bIsQuoted = false; + if (szStringValue == 0) + continue; + tokens.AppendTail({szStringValue, true, nCurrentLine}); + szStringValue = 0; + continue; + default: + szStringValue.AppendTail(c); + continue; + } + } + + } else { + // " makes it use a string + if (c == '"') + { + bIsQuoted = true; + } + + if (fnIsAlphabetSymbol(c)) + { + szStringValue.AppendTail(c); + continue; + } else { + if (szStringValue != 0) + tokens.AppendTail({szStringValue, false, nCurrentLine}); + szStringValue = 0; + if (V_isgraph(c) && c != '"') + tokens.AppendTail({CUtlString("%c", c), false, nCurrentLine}); + } + } + }; + return tokens; +}; diff --git a/tier2/uuid.cpp b/tier2/uuid.cpp new file mode 100644 index 0000000..e69de29