/** * Set the value for @p key as @p newStringValue. * * The function will allocate and save a private copy of @p newStringValue, so * the parameter can be freed after the call. * * String values will be saved in backend storage, when kdbSetKey() will be * called, in UTF-8 universal encoding, regardless of the program's current * encoding, when iconv plugin is present. * * @note The type will be set to KEY_TYPE_STRING. * When the type of the key is already a string type it won't be changed. * * @param key the key to set the string value * @param newStringValue NULL-terminated text string to be set as @p key's * value * @return the number of bytes actually saved in private struct including final * NULL * @retval 1 if newStringValue is a NULL pointer, this will make the * string empty (string only containing null termination) * @retval -1 if key is a NULL pointer * @see keyGetString(), keyValue(), keyString() * @ingroup keyvalue */ ssize_t keySetString(Key *key, const char *newStringValue) { ssize_t ret=0; if (!key) return -1; keySetMeta (key, "binary", 0); if (!newStringValue || newStringValue[0] == '\0') ret=keySetRaw(key,0,0); else ret=keySetRaw(key,newStringValue,elektraStrLen(newStringValue)); return ret; }
/** Reads the value of the key and decodes all escaping * codes into the buffer. * @pre the buffer needs to be as large as value's size. * @param cur the key holding the value to decode * @param buf the buffer to write to */ void elektraHexcodeDecode (Key * cur, CHexData * hd) { size_t valsize = keyGetValueSize (cur); const char * val = keyValue (cur); if (!val) return; size_t out = 0; for (size_t in = 0; in < valsize - 1; ++in) { char c = val[in]; char * n = hd->buf + out; if (c == hd->escape) { in += 2; /* Advance twice (2 hex numbers) */ char first = val[in - 1]; char second = val[in]; int res; res = elektraHexcodeConvFromHex (second); res += elektraHexcodeConvFromHex (first) * 16; *n = res & 255; } else { *n = c; } ++out; /* Only one char is written */ } hd->buf[out] = 0; // null termination for keyString() keySetRaw (cur, hd->buf, out + 1); }
/** Reads the value of the key and encodes it in * c-style in the buffer. * * @param cur the key which value is to encode * @param buf the buffer * @pre the buffer needs to have thrice as much space as the value's size */ void elektraHexcodeEncode (Key * cur, CHexData * hd) { size_t valsize = keyGetValueSize (cur); const char * val = keyValue (cur); if (!val) return; size_t out = 0; for (size_t in = 0; in < valsize - 1; ++in) { unsigned char c = val[in]; // need to encode char? if (hd->hd[c & 255]) { hd->buf[out] = hd->escape; out++; hd->buf[out] = elektraHexcodeConvToHex (c / 16); out++; hd->buf[out] = elektraHexcodeConvToHex (c % 16); out++; } else { // just copy one character hd->buf[out] = val[in]; // advance out cursor out++; } } hd->buf[out] = 0; // null termination for keyString() keySetRaw (cur, hd->buf, out + 1); }
/** * Set the value of a key as a binary. * * A private copy of @p newBinary will allocated and saved inside @p key, * so the parameter can be deallocated after the call. * * Binary values might be encoded in another way then string values * depending on the plugin. Typically character encodings should not take * place on binary data. * Consider using a string key instead. * * When newBinary is a NULL pointer the binary will be freed and 0 will * be returned. * * @note The meta data "binary" will be set to mark that the key is * binary from now on. When the key is already binary the meta data * won't be changed. This will only happen in the successful case, * but not when -1 is returned. * * @param key the object on which to set the value * @param newBinary is a pointer to any binary data or NULL to free the previous set data * @param dataSize number of bytes to copy from @p newBinary * @return the number of bytes actually copied to internal struct storage * @retval 0 when the internal binary was freed and is now a null pointer * @retval -1 if key is a NULL pointer * @retval -1 when dataSize is 0 (but newBinary not NULL) or larger than SSIZE_MAX * @see keyGetBinary() * @see keyIsBinary() to check if the type is binary * @see keyGetString() and keySetString() as preferred alternative to binary * @ingroup keyvalue */ ssize_t keySetBinary(Key *key, const void *newBinary, size_t dataSize) { ssize_t ret=0; if (!key) return -1; if (!dataSize && newBinary) return -1; if (dataSize > SSIZE_MAX) return -1; if (key->flags & KEY_FLAG_RO_VALUE) return -1; keySetMeta (key, "binary", ""); ret = keySetRaw(key,newBinary,dataSize); return ret; }
/* * Processes the current <key> node from reader, converting from XML * to a Key object, and ksAppendKey() it to ks. * * See keyToStream() for an example of a <key> node. * * This function is completelly dependent on libxml. * * @param ks where to put the resulting reded key * @param context a prent key name, so a full name can be calculated * if the XML node for the current key only provides a basename * @param reader where to read from */ static int consumeKeyNode(KeySet *ks, const char *context, xmlTextReaderPtr reader) { xmlChar *nodeName=0; xmlChar *keyNodeName=0; xmlChar *buffer=0; xmlChar *privateContext=0; Key *newKey=0; int appended=0; /* printf("%s", KDB_SCHEMA_PATH); */ keyNodeName=xmlTextReaderName(reader); if (!strcmp((char *)keyNodeName,"key")) { mode_t isdir=0; int isbin=0; int end=0; newKey=keyNew(0); /* a <key> must have one of the following: - a "name" attribute, used as an absolute name overriding the context - a "basename" attribute, that will be appended to the current context - a "parent" plus "basename" attributes, both appended to current context - only a "parent", appended to current context */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"name"); if (buffer) { /* set absolute name */ keySetName(newKey,(char *)buffer); xmlFree(buffer); buffer=0; } else { /* logic for relative name calculation */ privateContext=xmlTextReaderGetAttribute(reader, (const xmlChar *)"parent"); buffer=xmlTextReaderGetAttribute(reader, (const xmlChar *)"basename"); if (context) keySetName(newKey,context); if (privateContext) keyAddName(newKey, (char *)privateContext); if (buffer) keyAddName(newKey,(char *)buffer); xmlFree(privateContext); privateContext=0; xmlFree(buffer); buffer=0; } /* test for a short value attribute, instead of <value> bellow */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"value"); if (buffer) { keySetRaw(newKey,buffer,elektraStrLen((char *)buffer)); xmlFree(buffer); buffer=0; } /* Parse UID */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"uid"); if (buffer) { int errsave = errno; char * endptr; long int uid = strtol ((const char *)buffer, &endptr, 10); errno = errsave; if (endptr != '\0' && *endptr == '\0') { keySetUID(newKey,uid); } xmlFree(buffer); buffer=0; } /* Parse GID */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"gid"); if (buffer) { int errsave = errno; char * endptr; long int gid = strtol ((const char *)buffer, &endptr, 10); errno = errsave; if (endptr != '\0' && *endptr == '\0') { keySetGID(newKey,gid); } xmlFree(buffer); buffer=0; } /* Parse mode permissions */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"mode"); int errsave = errno; if (buffer) keySetMode(newKey,strtol((char *)buffer,0,0)); errno = errsave; xmlFree(buffer); if (xmlTextReaderIsEmptyElement(reader)) { /* we have a <key ..../> element */ if (newKey && !appended) { ksAppendKey(ks,newKey); appended=1; end=1; } } buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"type"); if (buffer) { if (!strcmp((char *)buffer,"binary")) isbin = 1; else if (!strcmp((char *)buffer,"bin")) isbin = 1; } xmlFree(buffer); /* If "isdir" appears, everything different from "0", "false" or "no" marks it as a dir key */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"isdir"); if (!isdir && buffer) { if ( strcmp((char *)buffer,"0") && strcmp((char *)buffer,"false") && strcmp((char *)buffer,"no")) isdir = 1; else isdir = 0; } xmlFree(buffer); if (isdir) keySetDir(newKey); if (isbin) keySetMeta (newKey, "binary", ""); // TODO: should parse arbitrary attributes as metadata /* Parse everything else */ while (!end) { xmlTextReaderRead(reader); nodeName=xmlTextReaderName(reader); if (!strcmp((char *)nodeName,"value")) { if (xmlTextReaderIsEmptyElement(reader) || xmlTextReaderNodeType(reader)==15) { xmlFree (nodeName); continue; } xmlTextReaderRead(reader); buffer=xmlTextReaderValue(reader); if (buffer) { /* Key's value type was already set above */ if (keyIsBinary(newKey)) { /* TODO binary values char *unencoded=0; size_t unencodedSize; unencodedSize=elektraStrLen((char *)buffer)/2; unencoded=elektraMalloc(unencodedSize); unencodedSize=kdbbDecode((char *)buffer,unencoded); if (!unencodedSize) return -1; keySetRaw(newKey,unencoded,unencodedSize); elektraFree (unencoded); */ } else keySetRaw(newKey,buffer,elektraStrLen((char *)buffer)); } xmlFree(buffer); } else if (!strcmp((char *)nodeName,"comment")) { ssize_t commentSize=0; if (xmlTextReaderIsEmptyElement(reader) || xmlTextReaderNodeType(reader)==15) { xmlFree (nodeName); continue; } xmlTextReaderRead(reader); buffer=xmlTextReaderValue(reader); if ((commentSize=keyGetCommentSize(newKey)) > 1) { /*Multiple line comment*/ char *tmpComment=0; tmpComment=elektraMalloc(commentSize+ xmlStrlen(buffer)*sizeof(xmlChar)+1); if (tmpComment) { keyGetComment(newKey,tmpComment,commentSize); strcat(tmpComment,"\n"); strcat(tmpComment,(char *)buffer); keySetComment(newKey,tmpComment); elektraFree (tmpComment); tmpComment=0; } } else keySetComment(newKey,(char *)buffer); xmlFree(buffer); } else if (!strcmp((char *)nodeName,"key")) { /* Here we found </key> or a sub <key>. So include current key in the KeySet. */ if (newKey && !appended) { ksAppendKey(ks,newKey); appended=1; } if (xmlTextReaderNodeType(reader)==15) /* found a </key> */ end=1; else { /* found a sub <key> */ /* prepare the context (parent) */ consumeKeyNode(ks,newKey->key,reader); } } xmlFree (nodeName); } if (privateContext) xmlFree(privateContext); /* seems like we forgot the key, lets delete it */ if (newKey && !appended) { keyDel (newKey); appended=1; } } xmlFree(keyNodeName); return 0; }