void KeyValues::RecursiveLoadFromBuffer(char const *resourceName, CUtlBuffer &buf) { CKeyErrorContext errorReport(this); bool wasQuoted; CKeyErrorContext errorKey(INVALID_KEY_SYMBOL); while (1) { const char *name = ReadToken(buf, wasQuoted); if (!name) { g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got EOF instead of keyname"); break; } if (!*name) { g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got empty keyname"); break; } if (*name == '}' && !wasQuoted ) break; KeyValues *dat = CreateKey(name); errorKey.Reset(dat->GetNameSymbol()); const char *value = ReadToken(buf, wasQuoted); if (!value) { g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got NULL key"); break; } if (*value == '}' && !wasQuoted) { g_KeyValuesErrorStack.ReportError("RecursiveLoadFromBuffer: got } in key"); break; } if (*value == '{' && !wasQuoted) { errorKey.Reset(INVALID_KEY_SYMBOL); dat->RecursiveLoadFromBuffer(resourceName, buf); } else { if (dat->m_sValue) { delete [] dat->m_sValue; dat->m_sValue = NULL; } int len = Q_strlen(value); char *pIEnd; char *pFEnd; const char *pSEnd = value + len; int ival = strtol(value, &pIEnd, 10); float fval = (float)strtod(value, &pFEnd); if (*value == 0) { dat->m_iDataType = TYPE_STRING; } else if ((18 == len) && (value[0] == '0') && (value[1] == 'x')) { int64 retVal = 0; for (int i = 2; i < 2 + 16; i++) { char digit = value[i]; if (digit >= 'a') digit -= 'a' - ('9' + 1); else if (digit >= 'A') digit -= 'A' - ('9' + 1); retVal = (retVal * 16) + (digit - '0'); } dat->m_sValue = new char [sizeof(uint64)]; *((uint64 *)dat->m_sValue) = retVal; dat->m_iDataType = TYPE_UINT64; } else if ((pFEnd > pIEnd) && (pFEnd == pSEnd)) { dat->m_flValue = fval; dat->m_iDataType = TYPE_FLOAT; } else if (pIEnd == pSEnd) { dat->m_iValue = ival; dat->m_iDataType = TYPE_INT; } else { dat->m_iDataType = TYPE_STRING; } if (dat->m_iDataType == TYPE_STRING) { dat->m_sValue = new char[len + 1]; Q_memcpy(dat->m_sValue, value, len + 1); } } } }
bool KeyValues::LoadFromBuffer(char const *resourceName, CUtlBuffer &buf, IFileSystem *pFileSystem, const char *pPathID) { KeyValues *pPreviousKey = NULL; KeyValues *pCurrentKey = this; CUtlVector<KeyValues *> includedKeys; CUtlVector<KeyValues *> baseKeys; bool wasQuoted; g_KeyValuesErrorStack.SetFilename(resourceName); do { const char *s = ReadToken(buf, wasQuoted); if (!buf.IsValid() || !s || *s == 0) break; if (!Q_stricmp(s, "#include")) { s = ReadToken(buf, wasQuoted); if (!s || *s == 0) { g_KeyValuesErrorStack.ReportError("#include is NULL "); } else { ParseIncludedKeys(resourceName, s, pFileSystem, pPathID, includedKeys); } continue; } else if (!Q_stricmp(s, "#base")) { s = ReadToken(buf, wasQuoted); if (!s || *s == 0) { g_KeyValuesErrorStack.ReportError("#base is NULL "); } else { ParseIncludedKeys(resourceName, s, pFileSystem, pPathID, baseKeys); } continue; } if (!pCurrentKey) { pCurrentKey = new KeyValues(s); Assert(pCurrentKey); pCurrentKey->UsesEscapeSequences(m_bHasEscapeSequences != 0); if (pPreviousKey) { pPreviousKey->SetNextKey(pCurrentKey); } } else { pCurrentKey->SetName(s); } s = ReadToken(buf, wasQuoted); if (s && *s == '{' && !wasQuoted) { pCurrentKey->RecursiveLoadFromBuffer(resourceName, buf); } else { g_KeyValuesErrorStack.ReportError("LoadFromBuffer: missing {"); } pPreviousKey = pCurrentKey; pCurrentKey = NULL; } while (buf.IsValid()); AppendIncludedKeys(includedKeys); { for (int i = includedKeys.Count() - 1; i > 0; i--) { KeyValues *kv = includedKeys[i]; kv->deleteThis(); } } MergeBaseKeys(baseKeys); { for (int i = baseKeys.Count() - 1; i >= 0; i--) { KeyValues *kv = baseKeys[i]; kv->deleteThis(); } } g_KeyValuesErrorStack.SetFilename(""); return true; }