//----------------------------------------------------------------------------- // Binary buffer attribute //----------------------------------------------------------------------------- bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src ) { int nLength = src.Length(); if ( !buf.IsText() ) { buf.PutInt( nLength ); if ( nLength != 0 ) { buf.Put( src.Get(), nLength ); } return buf.IsValid(); } // Writes out uuencoded binaries for ( int i = 0; i < nLength; ++i ) { if ( (i % 40) == 0 ) { buf.PutChar( '\n' ); } char b1 = src[i] & 0xF; char b2 = src[i] >> 4; char c1 = ( b1 <= 9 ) ? b1 + '0' : b1 - 10 + 'A'; char c2 = ( b2 <= 9 ) ? b2 + '0' : b2 - 10 + 'A'; buf.PutChar( c2 ); buf.PutChar( c1 ); } buf.PutChar( '\n' ); return buf.IsValid(); }
bool Unserialize( CUtlBuffer &buf, int &dest ) { if ( buf.IsText() ) { int nRetVal = buf.Scanf( "%d", &dest ); return (nRetVal == 1) && buf.IsValid(); } dest = buf.GetInt( ); return buf.IsValid(); }
//----------------------------------------------------------------------------- // Serialization //----------------------------------------------------------------------------- bool CVTFTexture::Serialize( CUtlBuffer &buf ) { if (!m_pImageData) { Warning("*** Unable to serialize... have no image data!\n"); return false; } VTFFileHeader_t header; Q_strncpy( header.fileTypeString, "VTF", 4 ); header.version[0] = VTF_MAJOR_VERSION; header.version[1] = VTF_MINOR_VERSION; header.headerSize = sizeof(VTFFileHeader_t); header.width = m_nWidth; header.height = m_nHeight; header.flags = m_nFlags; header.numFrames = m_nFrameCount; header.numMipLevels = m_nMipCount; header.imageFormat = m_Format; VectorCopy( m_vecReflectivity, header.reflectivity ); header.bumpScale = m_flBumpScale; // FIXME: Why is this needed? header.startFrame = m_iStartFrame; header.lowResImageWidth = m_nLowResImageWidth; header.lowResImageHeight = m_nLowResImageHeight; header.lowResImageFormat = m_LowResImageFormat; buf.Put( &header, sizeof(VTFFileHeader_t) ); if (!buf.IsValid()) return false; // Write the low-res image if (m_pLowResImageData) { int iLowResImageSize = ImageLoader::GetMemRequired( m_nLowResImageWidth, m_nLowResImageHeight, m_LowResImageFormat, false ); buf.Put( m_pLowResImageData, iLowResImageSize ); if (!buf.IsValid()) return false; } else { // If we have a non-zero image size, we better have bits! Assert((m_nLowResImageWidth == 0) || (m_nLowResImageHeight == 0)); } // Write out the image WriteImageData( buf ); return buf.IsValid(); }
bool Unserialize( CUtlBuffer &buf, float &dest ) { if ( buf.IsText() ) { // FIXME: Print this in a way that we never lose precision int nRetVal = buf.Scanf( "%f", &dest ); return (nRetVal == 1) && buf.IsValid(); } dest = buf.GetFloat( ); return buf.IsValid(); }
bool Unserialize( CUtlBuffer &buf, Vector2D &dest ) { if ( buf.IsText() ) { // FIXME: Print this in a way that we never lose precision int nRetVal = buf.Scanf( "%f %f", &dest.x, &dest.y ); return (nRetVal == 2) && buf.IsValid(); } dest.x = buf.GetFloat( ); dest.y = buf.GetFloat( ); return buf.IsValid(); }
bool Unserialize( CUtlBuffer &buf, bool &dest ) { if ( buf.IsText() ) { int nValue = 0; int nRetVal = buf.Scanf( "%d", &nValue ); dest = ( nValue != 0 ); return (nRetVal == 1) && buf.IsValid(); } dest = ( buf.GetChar( ) != 0 ); return buf.IsValid(); }
bool Unserialize( CUtlBuffer &buf, Color &dest ) { if ( buf.IsText() ) { int r = 0, g = 0, b = 0, a = 255; int nRetVal = buf.Scanf( "%d %d %d %d", &r, &g, &b, &a ); dest.SetColor( r, g, b, a ); return (nRetVal == 4) && buf.IsValid(); } dest[0] = buf.GetUnsignedChar( ); dest[1] = buf.GetUnsignedChar( ); dest[2] = buf.GetUnsignedChar( ); dest[3] = buf.GetUnsignedChar( ); return buf.IsValid(); }
static int CountBinaryBytes( CUtlBuffer &buf, int *pEndGet ) { // This counts the number of bytes in the uuencoded text int nStartGet = buf.TellGet(); buf.EatWhiteSpace(); *pEndGet = buf.TellGet(); int nByteCount = 0; while ( buf.IsValid() ) { char c1 = buf.GetChar(); char c2 = buf.GetChar(); bool bIsNum1 = ( c1 >= '0' ) && ( c1 <= '9' ); bool bIsNum2 = ( c2 >= '0' ) && ( c2 <= '9' ); bool bIsAlpha1 = (( c1 >= 'A' ) && ( c1 <= 'F' )) || (( c1 >= 'a' ) && ( c1 <= 'f' )); bool bIsAlpha2 = (( c2 >= 'A' ) && ( c2 <= 'F' )) || (( c2 >= 'a' ) && ( c2 <= 'f' )); if ( !(bIsNum1 || bIsAlpha1) || !(bIsNum2 || bIsAlpha2) ) break; buf.EatWhiteSpace(); *pEndGet = buf.TellGet(); ++nByteCount; } buf.SeekGet( CUtlBuffer::SEEK_HEAD, nStartGet ); return nByteCount; }
bool Unserialize( CUtlBuffer &buf, CUtlString &dest ) { int nLen = buf.PeekDelimitedStringLength( s_pConv ); dest.SetLength( nLen - 1 ); // -1 because the length returned includes space for \0 buf.GetDelimitedString( s_pConv, dest.Get(), nLen ); return buf.IsValid(); }
//----------------------------------------------------------------------------- // Unserialization of low-res data //----------------------------------------------------------------------------- bool CVTFTexture::LoadLowResData( CUtlBuffer &buf ) { // Allocate low-res bits InitLowResImage( m_nLowResImageWidth, m_nLowResImageHeight, m_LowResImageFormat ); int nLowResImageSize = ImageLoader::GetMemRequired( m_nLowResImageWidth, m_nLowResImageHeight, m_LowResImageFormat, false ); buf.Get( m_pLowResImageData, nLowResImageSize ); return buf.IsValid(); }
//----------------------------------------------------------------------------- // Unserialization of image data //----------------------------------------------------------------------------- bool CVTFTexture::LoadImageData( CUtlBuffer &buf, const VTFFileHeader_t &header, int nSkipMipLevels ) { // Fix up the mip count + size based on how many mip levels we skip... if (nSkipMipLevels > 0) { Assert( m_nMipCount > nSkipMipLevels ); if (header.numMipLevels < nSkipMipLevels) { // NOTE: This can only happen with older format .vtf files Warning("Warning! Encountered old format VTF file; please rebuild it!\n"); return false; } ComputeMipLevelDimensions( nSkipMipLevels, &m_nWidth, &m_nHeight ); m_nMipCount -= nSkipMipLevels; } // read the texture image (including mipmaps if they are there and needed.) int iImageSize = ComputeFaceSize( ); iImageSize *= m_nFaceCount * m_nFrameCount; // For backwards compatibility, we don't read in the spheremap fallback on // older format .VTF files... int nFacesToRead = m_nFaceCount; if (IsCubeMap()) { if ((header.version[0] == 7) && (header.version[1] < 1)) nFacesToRead = 6; } // NOTE: We load the bits this way because we store the bits in memory // differently that the way they are stored on disk; we store on disk // differently so we can only load up // NOTE: The smallest mip levels are stored first!! AllocateImageData( iImageSize ); for (int iMip = m_nMipCount; --iMip >= 0; ) { // NOTE: This is for older versions... if (header.numMipLevels - nSkipMipLevels <= iMip) continue; int iMipSize = ComputeMipSize( iMip ); for (int iFrame = 0; iFrame < m_nFrameCount; ++iFrame) { for (int iFace = 0; iFace < nFacesToRead; ++iFace) { unsigned char *pMipBits = ImageData( iFrame, iFace, iMip ); buf.Get( pMipBits, iMipSize ); } } } return buf.IsValid(); }
bool GetStringHelper( CUtlBuffer & cmd, char *outBuf, int bufSize ) { outBuf[0] = 0; cmd.GetString(outBuf, bufSize); if ( !cmd.IsValid() ) { cmd.Purge(); return false; } return true; }
//----------------------------------------------------------------------------- // Serialization methods for basic types //----------------------------------------------------------------------------- bool Serialize( CUtlBuffer &buf, const bool &src ) { if ( buf.IsText() ) { buf.Printf( "%d", src ); } else { buf.PutChar( src ); } return buf.IsValid(); }
bool Serialize( CUtlBuffer &buf, const float &src ) { if ( buf.IsText() ) { SerializeFloat( buf, src ); } else { buf.PutFloat( src ); } return buf.IsValid(); }
//----------------------------------------------------------------------------- // Parses a token from the excel .csv file //----------------------------------------------------------------------------- CSFMGenApp::TokenRetVal_t CSFMGenApp::ParseToken( CUtlBuffer &buf, char *pToken, int nMaxTokenLen ) { *pToken = 0; if ( !buf.IsValid() ) return TOKEN_EOF; int nLen = 0; char c = buf.GetChar(); bool bIsQuoted = false; while ( true ) { if ( c == '"' ) { bIsQuoted = !bIsQuoted; } else if ( ( c == ',' || c == '\n' ) && !bIsQuoted ) { pToken[nLen] = 0; return ( c == '\n' ) ? TOKEN_RETURN : TOKEN_COMMA; } if ( nLen < nMaxTokenLen - 1 ) { if ( c != '"' ) { pToken[nLen++] = c; } } if ( !buf.IsValid() ) { pToken[nLen] = 0; return TOKEN_EOF; } c = buf.GetChar(); } // Should never get here return TOKEN_EOF; }
//----------------------------------------------------------------------------- // Attribute types related to vector math //----------------------------------------------------------------------------- bool Serialize( CUtlBuffer &buf, const Vector2D &src ) { if ( buf.IsText() ) { SerializeFloats( buf, 2, src.Base() ); } else { buf.PutFloat( src.x ); buf.PutFloat( src.y ); } return buf.IsValid(); }
bool Serialize( CUtlBuffer &buf, const Quaternion &src ) { if ( buf.IsText() ) { SerializeFloats( buf, 4, &src.x ); } else { buf.PutFloat( src.x ); buf.PutFloat( src.y ); buf.PutFloat( src.z ); buf.PutFloat( src.w ); } return buf.IsValid(); }
//----------------------------------------------------------------------------- // Color attribute //----------------------------------------------------------------------------- bool Serialize( CUtlBuffer &buf, const Color &src ) { if ( buf.IsText() ) { buf.Printf( "%d %d %d %d", src[0], src[1], src[2], src[3] ); } else { buf.PutUnsignedChar( src[0] ); buf.PutUnsignedChar( src[1] ); buf.PutUnsignedChar( src[2] ); buf.PutUnsignedChar( src[3] ); } return buf.IsValid(); }
//----------------------------------------------------------------------------- // Parses the excel file //----------------------------------------------------------------------------- void CSFMGenApp::ParseCSVFile( CUtlBuffer &buf, CUtlVector< SFMInfo_t > &infoList, int nSkipLines ) { char pToken[512]; for( int nLine = 0; buf.IsValid(); ++nLine ) { SFMInfo_t info; TokenRetVal_t nTokenRetVal = ParseToken( buf, pToken, sizeof(pToken) ); if ( nTokenRetVal == TOKEN_EOF ) return; if ( nTokenRetVal != TOKEN_COMMA ) { Warning( "sfmgen: Missing Column at line %d\n", nLine ); continue; } info.m_DMXFileName = pToken; if ( ParseToken( buf, pToken, sizeof(pToken) ) != TOKEN_COMMA ) { Warning( "sfmgen: Missing Column at line %d\n", nLine ); continue; } if ( ParseToken( buf, pToken, sizeof(pToken) ) != TOKEN_COMMA ) { Warning( "sfmgen: Missing Column at line %d\n", nLine ); continue; } info.m_GameSound = pToken; nTokenRetVal = ParseToken( buf, pToken, sizeof(pToken) ); info.m_Text = pToken; while ( nTokenRetVal == TOKEN_COMMA ) { nTokenRetVal = ParseToken( buf, pToken, sizeof(pToken) ); } if ( nSkipLines > nLine ) continue; infoList.AddToTail( info ); } }
bool Unserialize( CUtlBuffer &buf, VMatrix &dest ) { if ( !buf.IsValid() ) return false; if ( buf.IsText() ) { int nRetVal = buf.Scanf( "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", &dest[ 0 ][ 0 ], &dest[ 0 ][ 1 ], &dest[ 0 ][ 2 ], &dest[ 0 ][ 3 ], &dest[ 1 ][ 0 ], &dest[ 1 ][ 1 ], &dest[ 1 ][ 2 ], &dest[ 1 ][ 3 ], &dest[ 2 ][ 0 ], &dest[ 2 ][ 1 ], &dest[ 2 ][ 2 ], &dest[ 2 ][ 3 ], &dest[ 3 ][ 0 ], &dest[ 3 ][ 1 ], &dest[ 3 ][ 2 ], &dest[ 3 ][ 3 ] ); return (nRetVal == 16); } buf.Get( &dest, sizeof(VMatrix) ); return true; }
bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest ) { if ( !buf.IsText() ) { int nLen = buf.GetInt( ); dest.SetLength( nLen ); if ( dest.Length() != 0 ) { buf.Get( dest.Get(), dest.Length() ); } if ( nLen != dest.Length() ) { buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLen - dest.Length() ); return false; } return buf.IsValid(); } int nEndGet; int nByteCount = CountBinaryBytes( buf, &nEndGet ); if ( nByteCount < 0 ) return false; buf.EatWhiteSpace(); int nDest = 0; dest.SetLength( nByteCount ); while( buf.TellGet() < nEndGet ) { char c1 = buf.GetChar(); char c2 = buf.GetChar(); unsigned char b1 = HexCharToInt( c1 ); unsigned char b2 = HexCharToInt( c2 ); if ( b1 == 0xFF || b2 == 0xFF ) return false; dest[ nDest++ ] = b2 | ( b1 << 4 ); buf.EatWhiteSpace(); } return true; }
bool Serialize( CUtlBuffer &buf, const VMatrix &src ) { if ( buf.IsText() ) { buf.Printf( "\n" ); SerializeFloats( buf, 4, src[0] ); buf.Printf( "\n" ); SerializeFloats( buf, 4, src[1] ); buf.Printf( "\n" ); SerializeFloats( buf, 4, src[2] ); buf.Printf( "\n" ); SerializeFloats( buf, 4, src[3] ); buf.Printf( "\n" ); } else { buf.Put( &src, sizeof(VMatrix) ); } return buf.IsValid(); }
//----------------------------------------------------------------------------- // Serialization of image data //----------------------------------------------------------------------------- bool CVTFTexture::WriteImageData( CUtlBuffer &buf ) { // NOTE: We load the bits this way because we store the bits in memory // differently that the way they are stored on disk; we store on disk // differently so we can only load up // NOTE: The smallest mip levels are stored first!! for (int iMip = m_nMipCount; --iMip >= 0; ) { int iMipSize = ComputeMipSize( iMip ); for (int iFrame = 0; iFrame < m_nFrameCount; ++iFrame) { for (int iFace = 0; iFace < m_nFaceCount; ++iFace) { unsigned char *pMipBits = ImageData( iFrame, iFace, iMip ); buf.Put( pMipBits, iMipSize ); } } } return buf.IsValid(); }
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; }
bool KeyValues::WriteAsBinary(CUtlBuffer &buffer) { if (buffer.IsText()) return false; if (!buffer.IsValid()) return false; for (KeyValues *dat = this; dat != NULL; dat = dat->m_pPeer) { buffer.PutUnsignedChar(dat->m_iDataType); buffer.PutString(dat->GetName()); switch (dat->m_iDataType) { case TYPE_NONE: { dat->m_pSub->WriteAsBinary(buffer); break; } case TYPE_STRING: { if (dat->m_sValue && *(dat->m_sValue)) { buffer.PutString(dat->m_sValue); } else { buffer.PutString(""); } break; } case TYPE_WSTRING: { Assert(!"TYPE_WSTRING"); break; } case TYPE_INT: { buffer.PutInt(dat->m_iValue); break; } case TYPE_UINT64: { buffer.PutDouble(*((double *)dat->m_sValue)); break; } case TYPE_FLOAT: { buffer.PutFloat(dat->m_flValue); break; } case TYPE_COLOR: { buffer.PutUnsignedChar(dat->m_Color[0]); buffer.PutUnsignedChar(dat->m_Color[1]); buffer.PutUnsignedChar(dat->m_Color[2]); buffer.PutUnsignedChar(dat->m_Color[3]); break; } case TYPE_PTR: { buffer.PutUnsignedInt((int)dat->m_pValue); } default: { break; } } } buffer.PutUnsignedChar(TYPE_NUMTYPES); return buffer.IsValid(); }
bool KeyValues::ReadAsBinary(CUtlBuffer &buffer) { if (buffer.IsText()) return false; if (!buffer.IsValid()) return false; RemoveEverything(); Init(); char token[KEYVALUES_TOKEN_SIZE]; KeyValues *dat = this; types_t type = (types_t)buffer.GetUnsignedChar(); while (true) { if (type == TYPE_NUMTYPES) break; dat->m_iDataType = type; buffer.GetString(token, KEYVALUES_TOKEN_SIZE - 1); token[KEYVALUES_TOKEN_SIZE - 1] = 0; dat->SetName(token); switch (type) { case TYPE_NONE: { dat->m_pSub = new KeyValues(""); dat->m_pSub->ReadAsBinary(buffer); break; } case TYPE_STRING: { buffer.GetString(token, KEYVALUES_TOKEN_SIZE - 1); token[KEYVALUES_TOKEN_SIZE - 1] = 0; int len = Q_strlen(token); dat->m_sValue = new char[len + 1]; Q_memcpy(dat->m_sValue, token, len + 1); break; } case TYPE_WSTRING: { Assert(!"TYPE_WSTRING"); break; } case TYPE_INT: { dat->m_iValue = buffer.GetInt(); break; } case TYPE_UINT64: { dat->m_sValue = new char[sizeof(uint64)]; *((double *)dat->m_sValue) = buffer.GetDouble(); } case TYPE_FLOAT: { dat->m_flValue = buffer.GetFloat(); break; } case TYPE_COLOR: { dat->m_Color[0] = buffer.GetUnsignedChar(); dat->m_Color[1] = buffer.GetUnsignedChar(); dat->m_Color[2] = buffer.GetUnsignedChar(); dat->m_Color[3] = buffer.GetUnsignedChar(); break; } case TYPE_PTR: { dat->m_pValue = (void *)buffer.GetUnsignedInt(); } default: { break; } } if (!buffer.IsValid()) return false; type = (types_t)buffer.GetUnsignedChar(); if (type == TYPE_NUMTYPES) break; dat->m_pPeer = new KeyValues(""); dat = dat->m_pPeer; } return buffer.IsValid(); }
//----------------------------------------------------------------------------- // String attribute //----------------------------------------------------------------------------- bool Serialize( CUtlBuffer &buf, const CUtlString &src ) { buf.PutDelimitedString( s_pConv, src.Get() ); return buf.IsValid(); }
//----------------------------------------------------------------------------- // Unserialization //----------------------------------------------------------------------------- bool CVTFTexture::Unserialize( CUtlBuffer &buf, bool bBufferHeaderOnly, int nSkipMipLevels ) { // When unserializing, we can skip a certain number of mip levels, // and we also can just load everything but the image data VTFFileHeader_t header; memset( &header, 0, sizeof(VTFFileHeader_t) ); buf.Get( &header, sizeof(VTFFileHeader_t) ); if (!buf.IsValid()) { Warning("*** Error unserializing VTF file... is the file empty?\n"); return false; } // Validity check if ( Q_strncmp( header.fileTypeString, "VTF", 4 ) ) { Warning("*** Tried to load a non-VTF file as a VTF file!\n"); return false; } if( header.version[0] != VTF_MAJOR_VERSION ) { Warning("*** Encountered VTF file with an invalid version!\n"); return false; } if( (header.flags & TEXTUREFLAGS_ENVMAP) && (header.width != header.height) ) { Warning("*** Encountered VTF non-square cubemap!\n"); return false; } if( header.width <= 0 || header.height <= 0 ) { Warning( "*** Encountered VTF invalid texture size!\n" ); return false; } m_nWidth = header.width; m_nHeight = header.height; m_Format = header.imageFormat; m_nFlags = header.flags; m_nFrameCount = header.numFrames; // NOTE: We're going to store space for all mip levels, even if we don't // have data on disk for them. This is for backward compatibility m_nMipCount = ComputeMipCount(); m_nFaceCount = (m_nFlags & TEXTUREFLAGS_ENVMAP) ? CUBEMAP_FACE_COUNT : 1; m_vecReflectivity = header.reflectivity; m_flBumpScale = header.bumpScale; // FIXME: Why is this needed? m_iStartFrame = header.startFrame; // FIXME: Remove // This is to make sure old-format .vtf files are read properly m_pVersion[0] = header.version[0]; m_pVersion[1] = header.version[1]; if( header.lowResImageWidth == 0 || header.lowResImageHeight == 0 ) { m_nLowResImageWidth = 0; m_nLowResImageHeight = 0; } else { m_nLowResImageWidth = header.lowResImageWidth; m_nLowResImageHeight = header.lowResImageHeight; } m_LowResImageFormat = header.lowResImageFormat; // Helpful for us to be able to get VTF info without reading in a ton if (bBufferHeaderOnly) return true; if (!LoadLowResData( buf )) return false; if (!LoadImageData( buf, header, nSkipMipLevels )) return false; return true; }
static bool GetKeyValueFromBuffer( CUtlBuffer &buf, char **key, char **val ) { char stringBuf[2048]; while( buf.IsValid() ) { buf.GetLine( stringBuf, sizeof(stringBuf) ); char *scan = stringBuf; // search for the first quote for the key. while( 1 ) { if( *scan == '\"' ) { *key = ++scan; break; } if( *scan == '#' ) { goto next_line; // comment } if( *scan == '\0' ) { goto next_line; // end of line. } scan++; } // read the key until another quote. while( 1 ) { if( *scan == '\"' ) { *scan = '\0'; scan++; break; } if( *scan == '\0' ) { goto next_line; } scan++; } // search for the first quote for the value. while( 1 ) { if( *scan == '\"' ) { *val = ++scan; break; } if( *scan == '#' ) { goto next_line; // comment } if( *scan == '\0' ) { goto next_line; // end of line. } scan++; } // read the value until another quote. while( 1 ) { if( *scan == '\"' ) { *scan = '\0'; scan++; // got a key and a value, so get the hell out of here. return true; } if( *scan == '\0' ) { goto next_line; } scan++; } next_line: ; } return false; }