dnxXml.c

Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002 
00003    Copyright (c) 2006-2007, Intellectual Reserve, Inc. All rights reserved.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License version 2 as
00007    published by the Free Software Foundation.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018   --------------------------------------------------------------------------*/
00019 
00028 #include "dnxXml.h"
00029 
00030 #include "dnxProtocol.h"
00031 #include "dnxError.h"
00032 #include "dnxDebug.h"
00033 #include "dnxLogging.h"
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <errno.h>
00039 #include <syslog.h>
00040 #include <assert.h>
00041 
00042 #define DNX_XML_MIN_HEADER 32
00043 
00046 /*--------------------------------------------------------------------------
00047                               IMPLEMENTATION
00048   --------------------------------------------------------------------------*/
00049 
00060 static int dnxXmlEscapeStr(char * outstr, char * instr, int maxbuf)
00061 {
00062    int i,op;
00063    int ret = DNX_OK;
00064 
00065    for (i = 0, op = 0; i < strlen(instr) && i < maxbuf && ret == DNX_OK; i++)
00066    {
00067       switch(instr[i])
00068       {
00069          case 38: // & -> &amp;
00070             if (op + 5 < maxbuf)
00071             {
00072                memcpy(outstr + op, "&amp;", 5);
00073                op += 5;
00074             }
00075             else
00076                ret = DNX_ERR_CAPACITY;
00077             break;
00078          case 60: // < -> &lt;
00079             if (op + 4 < maxbuf)
00080             {
00081                memcpy(outstr + op, "&lt;", 4);
00082                op += 4;
00083             }
00084             else
00085                ret = DNX_ERR_CAPACITY;
00086             break;
00087          case 62: // > -> &gt;
00088             if (op + 4 < maxbuf)
00089             {
00090                memcpy(outstr + op, "&gt;", 4);
00091                op += 4;
00092             }
00093             else ret = DNX_ERR_CAPACITY;
00094             break;
00095          case 34: // " -> &quot;
00096             if (op + 6 < maxbuf)
00097             {
00098                memcpy(outstr + op, "&qout;", 6);
00099                op += 6;
00100             }
00101             else
00102                ret = DNX_ERR_CAPACITY;
00103             break;
00104          case 39: // ' -> &apos;
00105             if (op + 6 < maxbuf)
00106             {
00107                memcpy(outstr + op, "&apos;", 6);
00108                op += 6;
00109             }
00110             else
00111                ret = DNX_ERR_CAPACITY;
00112             break;
00113          default:
00114             if (op + 1 < maxbuf)
00115             {
00116                outstr[op] = instr[i];
00117                op++;
00118             }
00119             else
00120                ret = DNX_ERR_CAPACITY;
00121             break;
00122       }
00123    }
00124    if (i >= maxbuf)
00125       ret = DNX_ERR_CAPACITY;
00126    if (ret != DNX_ERR_CAPACITY)
00127       outstr[op] = 0;
00128    return ret;
00129 }
00130 
00131 //----------------------------------------------------------------------------
00132 
00143 static int dnxXmlUnescapeStr(char * outstr, char * instr, int maxbuf)
00144 {
00145    int i, op;
00146    int ret = DNX_OK;
00147    char * temp;
00148    int tempnum;
00149 
00150    for (i = 0, op = 0; i < strlen(instr) && i < maxbuf && ret == DNX_OK; i++, op++)
00151    {
00152       if (instr[i] == 38)
00153       {  // &
00154          if (strncmp(instr + i, "&amp;", 5) == 0)
00155          {
00156             outstr[op] = '&';
00157             i += 4;
00158          }
00159          else if (strncmp(instr + i, "&lt;", 4) == 0)
00160          {
00161             outstr[op] = '<';
00162             i += 3;
00163          }
00164          else if (strncmp(instr + i, "&gt;", 4) == 0)
00165          {
00166             outstr[op] = '>';
00167             i+=3;
00168          }
00169          else if (strncmp(instr + i, "&qout;", 6) == 0)
00170          {
00171             outstr[op] = 34;
00172             i+=5;
00173          }
00174          else if (strncmp(instr + i, "&apos;", 6) == 0)
00175          {
00176             outstr[op] = 39;
00177             i+=5;
00178          }
00179          else if ((temp = memchr(instr + i, ';', maxbuf-i)) != 0)
00180          {
00181             if (instr[i+1] == '#')
00182             {  // Handle cases like &#39;
00183                errno = 0;
00184                tempnum = strtol(instr + i, 0, 0);
00185                if (errno == ERANGE || tempnum < 0 || tempnum > 255)
00186                {
00187                   ret = DNX_ERR_SYNTAX;
00188                   dnxDebug(2, "dnxXmlUnescapeStr: invalid unescape #, "
00189                               "instr=%s, i=%d, num=%d", instr, i, tempnum);
00190                }
00191                else
00192                   outstr[op]=(int)tempnum;
00193                i = temp-instr;
00194             }
00195             else
00196             {  // Unsupported XML escape sequence
00197                ret = DNX_ERR_SYNTAX;
00198                dnxDebug(2, "dnxXmlUnescapeStr: unsupported xml escape "
00199                            "sequence, instr=%s, i=%d", instr, i);
00200             }
00201          }
00202          else
00203          {  // This was not an escape sequence
00204             ret = DNX_ERR_SYNTAX;
00205             dnxDebug(2, "dnxXmlUnescapeStr: inappropriate escape "
00206                         "sequence, instr=%s, i=%d", instr, i);
00207          }
00208       }
00209       else
00210          outstr[op]=instr[i];
00211    }
00212    if (i >= maxbuf)
00213       ret = DNX_ERR_CAPACITY;
00214    if (ret != DNX_ERR_CAPACITY)
00215       outstr[op] = 0;
00216    return ret;
00217 }
00218 
00219 //----------------------------------------------------------------------------
00220 
00231 static int dnxXmlToString(DnxXmlType xType, void * xData, char * buf, int size)
00232 {
00233    int ret = DNX_OK;
00234 
00235    assert(xData && buf && size > 0);
00236 
00237    *buf = 0;
00238 
00239    switch (xType)
00240    {
00241       case DNX_XML_SHORT:
00242          snprintf(buf, size, "%hd", *((short *)xData));
00243          break;
00244 
00245       case DNX_XML_USHORT:
00246          snprintf(buf, size, "%hu", *((unsigned short *)xData));
00247          break;
00248 
00249       case DNX_XML_INT:
00250          snprintf(buf, size, "%d", *((int *)xData));
00251          break;
00252 
00253       case DNX_XML_UINT:
00254          snprintf(buf, size, "%u", *((unsigned int *)xData));
00255          break;
00256 
00257       case DNX_XML_LONG:
00258          snprintf(buf, size, "%ld", *((long *)xData));
00259          break;
00260 
00261       case DNX_XML_ULONG:
00262          snprintf(buf, size, "%lu", *((unsigned long *)xData));
00263          break;
00264 
00265       case DNX_XML_STR_UNESCAPED:
00266          assert(strlen((char *)xData) < size);
00267          strncpy(buf, (char *)xData, size);
00268          buf[size - 1] = 0;
00269          break;
00270 
00271       case DNX_XML_STR:
00272          assert(strlen((char *)xData) < size);
00273          ret = dnxXmlEscapeStr(buf, (char *)xData, size);
00274          buf[size - 1] = 0;
00275          break;
00276 
00277       case DNX_XML_XID:
00278          snprintf(buf, size, "%u-%lu-%lu", ((DnxXID *)xData)->objType,
00279                ((DnxXID *)xData)->objSerial, ((DnxXID *)xData)->objSlot);
00280          break;
00281 
00282       default:
00283          ret = DNX_ERR_INVALID;
00284    }
00285    return ret;
00286 }
00287 
00288 //----------------------------------------------------------------------------
00289 
00302 static int dnxXmlGetTagValue(DnxXmlBuf * xbuf, char * xTag, DnxXmlType xType,
00303       char * buf, int size)
00304 {
00305    char * cp, * ep, * value;
00306    int len, ret = DNX_OK;
00307 
00308    assert(xbuf && xTag && buf && size);
00309 
00310    // search for opening bracket
00311    cp = xbuf->buf;
00312    while ((cp = strchr(cp, '<')) != 0)
00313    {
00314       cp++;
00315 
00316       if (*cp == '/')
00317          continue;   // not a match
00318 
00319       // search for end-bracket
00320       if ((ep = strchr(cp, '>')) == 0)
00321       {
00322          ret = DNX_ERR_SYNTAX;
00323          break;   // error - unmatched XML brackets
00324       }
00325 
00326       // see if we've matched open-tag
00327       if (strncmp(cp, xTag, (ep-cp)))
00328       {
00329          cp = ep+1;  // reset beginning pointer for next search
00330          continue;   // not a match
00331       }
00332 
00333       value = cp = ep + 1; // beginning of tag-value
00334 
00335 end_tag:
00336 
00337       // find opening bracket of end-tag
00338       if ((ep = strchr(cp, '<')) == 0)
00339       {
00340          ret = DNX_ERR_SYNTAX;
00341          break;   // error - missing closing tag
00342       }
00343 
00344       len = ep - value; // length of tag-value
00345 
00346       // verify that this is a closing tag
00347       if (*(cp = ep + 1) != '/')
00348          goto end_tag;  // not a match
00349       cp++;
00350 
00351       // search for end-bracket
00352       if ((ep = strchr(cp, '>')) == 0)
00353       {
00354          ret = DNX_ERR_SYNTAX;
00355          break;   // error - nmatched XML brackets
00356       }
00357 
00358       // see if we've matched the end-tag
00359       if (strncmp(cp, xTag, ep - cp))
00360          goto end_tag;  // not a match
00361 
00362       // get min of tag-value-length or conversion buffer size.
00363       if (len >= size)
00364          len = size - 1;
00365 
00366       // copy tag value to local conversion buffer
00367       if (len > 0)
00368          memcpy(buf, value, len);
00369       buf[len] = 0;
00370 
00371       break;   // success
00372    }
00373    return ret;
00374 }
00375 
00376 /*--------------------------------------------------------------------------
00377                               INTERFACE
00378   --------------------------------------------------------------------------*/
00379 
00387 int dnxXmlOpen(DnxXmlBuf * xbuf, char * tag)
00388 {
00389    assert(xbuf && tag);
00390 
00391    // initialize buffer with message container opening tag and request attribute
00392    xbuf->size = sprintf(xbuf->buf, "<dnxMessage><Request>%s</Request>", tag);
00393 
00394    return DNX_OK;
00395 }
00396 
00397 //----------------------------------------------------------------------------
00398 
00409 int dnxXmlAdd(DnxXmlBuf * xbuf, char * xTag, DnxXmlType xType, void * xData)
00410 {
00411    char buf[DNX_MAX_MSG];
00412    int len, ret;
00413 
00414    assert(xbuf && xbuf->size >= DNX_XML_MIN_HEADER && xTag);
00415 
00416    // convert data element to string
00417    *buf = 0;
00418    if (xData && (ret = dnxXmlToString(xType, xData, buf, sizeof buf)) != DNX_OK)
00419       return ret;
00420 
00421    // perform capacity check on XML buffer - 5 = number of brackets plus '/'
00422    if ((len = xbuf->size + strlen(xTag) * 2 + strlen(buf) + 5) >= DNX_MAX_MSG)
00423       return DNX_ERR_CAPACITY;
00424 
00425    // add to XML buffer
00426    xbuf->size += sprintf(xbuf->buf + xbuf->size, "<%s>%s</%s>", xTag, buf, xTag);
00427 
00428    return DNX_OK;
00429 }
00430 
00431 //----------------------------------------------------------------------------
00432 
00447 int dnxXmlGet(DnxXmlBuf * xbuf, char * xTag, DnxXmlType xType, void * xData)
00448 {
00449    char buf[DNX_MAX_MSG];
00450    char * cp, * ep, * lastchar;
00451    unsigned long unum;
00452    long num;
00453    int ret = DNX_OK;
00454    char * temp = NULL;
00455 
00456    // extract the value of the specified tag from the XML buffer
00457    if ((ret = dnxXmlGetTagValue(xbuf, xTag, xType, buf, sizeof buf)) != DNX_OK)
00458       return ret;
00459 
00460    // convert tag value into target binary type
00461    switch (xType)
00462    {
00463       case DNX_XML_SHORT:
00464          errno = 0;
00465          num = strtol(buf, &lastchar, 0);
00466          if (errno == ERANGE || *lastchar)
00467             ret = DNX_ERR_SYNTAX;
00468          else
00469             *(short *)xData = (short)num;
00470          break;
00471 
00472       case DNX_XML_USHORT:
00473          errno = 0;
00474          unum = strtoul(buf, &lastchar, 0);
00475          if (errno == ERANGE || *lastchar)
00476             ret = DNX_ERR_SYNTAX;
00477          else
00478             *(unsigned short *)xData = (unsigned short)unum;
00479          break;
00480 
00481       case DNX_XML_INT:
00482          errno = 0;
00483          num = strtol(buf, &lastchar, 0);
00484          if (errno == ERANGE || *lastchar)
00485             ret = DNX_ERR_SYNTAX;
00486          else
00487             *(int *)xData = (int)num;
00488          break;
00489 
00490       case DNX_XML_UINT:
00491          errno = 0;
00492          unum = strtoul(buf, &lastchar, 0);
00493          if (errno == ERANGE || *lastchar)
00494             ret = DNX_ERR_SYNTAX;
00495          else
00496             *(unsigned int *)xData = (unsigned int)unum;
00497          break;
00498 
00499       case DNX_XML_LONG:
00500          errno = 0;
00501          num = strtol(buf, &lastchar, 0);
00502          if (errno == ERANGE || *lastchar)
00503             ret = DNX_ERR_SYNTAX;
00504          else
00505             *(long *)xData = (long)num;
00506          break;
00507 
00508       case DNX_XML_ULONG:
00509          errno = 0;
00510          unum = strtoul(buf, &lastchar, 0);
00511          if (errno == ERANGE || *lastchar)
00512             ret = DNX_ERR_SYNTAX;
00513          else
00514             *(unsigned long *)xData = (unsigned long)unum;
00515          break;
00516 
00517       case DNX_XML_STR_UNESCAPED:
00518          if ((*((char **)xData) = xstrdup(buf)) == 0)
00519             ret = DNX_ERR_MEMORY;
00520          break;
00521 
00522       case DNX_XML_STR:
00523          if ((temp = xstrdup(buf)) == 0)
00524          {
00525             ret = DNX_ERR_MEMORY;
00526          }else{
00527             ret = dnxXmlUnescapeStr(temp, buf, sizeof buf);
00528             *(char **)xData = temp;
00529          }
00530          break;
00531 
00532       case DNX_XML_XID:
00533          // the format of a XID is: "objType-objSerial-objSlot",
00534          // where objType, objSerial and objSlot are unsigned integers
00535          if ((cp = strchr(buf, '-')) == 0)
00536          {
00537             ret = DNX_ERR_SYNTAX;   // missing XID separator
00538             break;
00539          }
00540          *cp++ = 0;  // now buf points to objType and cp points to objSerial
00541 
00542          if ((ep = strchr(cp, '-')) == 0)
00543          {
00544             ret = DNX_ERR_SYNTAX;   // missing XID separator
00545             break;
00546          }
00547          *ep++ = 0;  // now ep points to objSlot
00548 
00549          // decode objType
00550          errno = 0;
00551          unum = strtoul(buf, &lastchar, 0);
00552          if (errno == ERANGE || *lastchar)
00553          {
00554             ret = DNX_ERR_SYNTAX;
00555             break;
00556          }
00557          ((DnxXID *)xData)->objType = (DnxObjType)unum;
00558 
00559          // decode objSerial
00560          errno = 0;
00561          unum = strtoul(cp, &lastchar, 0);
00562          if (errno == ERANGE || *lastchar)
00563          {
00564             ret = DNX_ERR_SYNTAX;
00565             break;
00566          }
00567          ((DnxXID *)xData)->objSerial = (unsigned long)unum;
00568 
00569          // decode objSlot
00570          errno = 0;
00571          unum = strtoul(ep, &lastchar, 0);
00572          if (errno == ERANGE || *lastchar)
00573          {
00574             ret = DNX_ERR_SYNTAX;
00575             break;
00576          }
00577          ((DnxXID *)xData)->objSlot = (unsigned long)unum;
00578          break;
00579 
00580       default:
00581          ret = DNX_ERR_INVALID;
00582    }
00583    return ret;
00584 }
00585 
00586 //----------------------------------------------------------------------------
00587 
00596 int dnxXmlCmpStr(DnxXmlBuf * xbuf, char * xTag, char * cmpstr)
00597 {
00598    char buf[DNX_MAX_MSG];
00599    int ret;
00600 
00601    if ((ret = dnxXmlGetTagValue(xbuf,
00602          xTag, DNX_XML_STR, buf, sizeof buf)) != DNX_OK)
00603       return ret;
00604 
00605    return strcmp(cmpstr, buf) == 0 ? DNX_OK : DNX_ERR_SYNTAX;
00606 }
00607 
00608 //----------------------------------------------------------------------------
00609 
00616 int dnxXmlClose(DnxXmlBuf * xbuf)
00617 {
00618    assert(xbuf && xbuf->size >= 0);
00619 
00620    if (xbuf->size > DNX_MAX_MSG)
00621       return DNX_ERR_CAPACITY;
00622 
00623    // append final message container tag
00624    strcat(xbuf->buf, "</dnxMessage>");
00625    xbuf->size = strlen(xbuf->buf);
00626 
00627    return DNX_OK;
00628 }
00629 
00630 /*--------------------------------------------------------------------------
00631                                  TEST MAIN
00632 
00633    From within dnx/common, compile with GNU tools using this command line:
00634 
00635       gcc -DDEBUG -DDNX_XML_TEST -g -O0 -o dnxXmlTest \
00636          dnxXml.c dnxError.c
00637 
00638    Alternatively, a heap check may be done with the following command line:
00639 
00640       gcc -DDEBUG -DDEBUG_HEAP -DDNX_XML_TEST -g -O0 -o dnxXmlTest \
00641          dnxXml.c dnxError.c dnxHeap.c
00642 
00643   --------------------------------------------------------------------------*/
00644 
00645 #ifdef DNX_XML_TEST
00646 
00647 #include "utesthelp.h"
00648 
00649 static verbose;
00650 
00651 IMPLEMENT_DNX_SYSLOG(verbose);
00652 IMPLEMENT_DNX_DEBUG(verbose);
00653 
00654 int main(int argc, char ** argv)
00655 {
00656    static int lens[] = {35, 54, 74, 90, 107, 126, 146, 174, 204, 217};
00657    static char * testbuf =
00658          "<dnxMessage>"
00659          "<Request>Test</Request>"
00660          "<Short>-100</Short>"
00661          "<UShort>100</UShort>"
00662          "<Int>-1000</Int>"
00663          "<UInt>1000</UInt>"
00664          "<Long>-10000</Long>"
00665          "<ULong>10000</ULong>"
00666          "<String>test string</String>"
00667          "<XID>6-12345678-87654321</XID>"
00668          "</dnxMessage>";
00669 
00670    DnxXmlBuf xbuf;
00671 
00672    short xshort = -100;
00673    unsigned short xushort = 100;
00674    int xint = -1000;
00675    unsigned int xuint = 1000;
00676    long xlong = -10000;
00677    unsigned long xulong = 10000;
00678    char * xstring = "test string";
00679    DnxXID xid;
00680 
00681    xid.objType = DNX_OBJ_MANAGER;
00682    xid.objSerial = 12345678;
00683    xid.objSlot = 87654321;
00684 
00685    verbose = argc > 1 ? 1 : 0;
00686 
00687    CHECK_ZERO(dnxXmlOpen(&xbuf, "Test"));
00688    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[0]) == 0);
00689 
00690    CHECK_ZERO(dnxXmlAdd(&xbuf, "Short", DNX_XML_SHORT, &xshort));
00691    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[1]) == 0);
00692 
00693    CHECK_ZERO(dnxXmlAdd(&xbuf, "UShort", DNX_XML_USHORT, &xushort));
00694    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[2]) == 0);
00695 
00696    CHECK_ZERO(dnxXmlAdd(&xbuf, "Int", DNX_XML_INT, &xint));
00697    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[3]) == 0);
00698 
00699    CHECK_ZERO(dnxXmlAdd(&xbuf, "UInt", DNX_XML_UINT, &xuint));
00700    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[4]) == 0);
00701 
00702    CHECK_ZERO(dnxXmlAdd(&xbuf, "Long", DNX_XML_LONG, &xlong));
00703    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[5]) == 0);
00704 
00705    CHECK_ZERO(dnxXmlAdd(&xbuf, "ULong", DNX_XML_ULONG, &xulong));
00706    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[6]) == 0);
00707 
00708    CHECK_ZERO(dnxXmlAdd(&xbuf, "String", DNX_XML_STR, xstring));
00709    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[7]) == 0);
00710 
00711    CHECK_ZERO(dnxXmlAdd(&xbuf, "XID", DNX_XML_XID, &xid));
00712    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[8]) == 0);
00713 
00714    CHECK_ZERO(dnxXmlClose(&xbuf));
00715    CHECK_TRUE(memcmp(xbuf.buf, testbuf, lens[9]) == 0);
00716 
00717    CHECK_ZERO(dnxXmlGet(&xbuf, "Short",  DNX_XML_SHORT,  &xshort));
00718    CHECK_TRUE(xshort == -100);
00719 
00720    CHECK_ZERO(dnxXmlGet(&xbuf, "UShort", DNX_XML_USHORT, &xushort));
00721    CHECK_TRUE(xushort == 100);
00722 
00723    CHECK_ZERO(dnxXmlGet(&xbuf, "Int",    DNX_XML_INT,    &xint));
00724    CHECK_TRUE(xint == -1000);
00725 
00726    CHECK_ZERO(dnxXmlGet(&xbuf, "UInt",   DNX_XML_UINT,   &xuint));
00727    CHECK_TRUE(xuint == 1000);
00728 
00729    CHECK_ZERO(dnxXmlGet(&xbuf, "Long",   DNX_XML_LONG,   &xlong));
00730    CHECK_TRUE(xlong == -10000);
00731 
00732    CHECK_ZERO(dnxXmlGet(&xbuf, "ULong",  DNX_XML_ULONG,  &xulong));
00733    CHECK_TRUE(xulong == 10000);
00734 
00735    CHECK_ZERO(dnxXmlGet(&xbuf, "String", DNX_XML_STR, &xstring));
00736    CHECK_TRUE(strcmp(xstring, "test string") == 0);
00737 
00738    // we have to free all strings returned by dnxXmlGet - this is so broken
00739    xfree(xstring);
00740 
00741    CHECK_ZERO(dnxXmlGet(&xbuf, "XID",    DNX_XML_XID,    &xid));
00742    CHECK_TRUE(xid.objType == DNX_OBJ_MANAGER);
00743    CHECK_TRUE(xid.objSerial == 12345678);
00744    CHECK_TRUE(xid.objSlot == 87654321);
00745 
00746 #ifdef DEBUG_HEAP
00747    CHECK_ZERO(dnxCheckHeap());
00748 #endif
00749 
00750    return 0;
00751 }
00752 
00753 #endif   /* DNX_XML_TEST */
00754 
00755 /*--------------------------------------------------------------------------*/
00756 

Generated on Tue Apr 13 15:48:07 2010 for DNX by  doxygen 1.5.6