Fix even more leaks
[pandora-libraries.git] / lib / pnd_tinyxml.cpp
index da4f13a..1aa8f9b 100644 (file)
@@ -26,79 +26,170 @@ unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app) {
   app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c);
   if (!app->titles) return (0); //errno = NOMEM
 
-  //Go through all title tags and load them.
-  for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem;
-       pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE))
-  {
+  // Go through all title tags and load them.
+  // - Check if newer style titles sub-block exists; if so, use that.
+  //   - if not, fall back to old style
+  //     - failing that, crash earth into sun
+  if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_TITLES).Element()) ) {
+    // newer <titles> block
 
-    if ( ! pElem->GetText() ) {
-      continue;
-    }
+    pElem = pElem -> FirstChildElement ( PND_PXML_ENAME_TITLE );
+
+    while ( pElem ) {
 
-    char *text = strdup(pElem->GetText());
-    if (!text) continue;
+      // handle <title lang="en_US">Program Title</title>
+      //
 
-    char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG);
-    if (!lang) continue;
+      // parse out the text and lang
+      char *text, *lang;
+
+      if ( ! ( text = strdup ( pElem -> GetText() ) ) ) {
+       continue;
+      }
 
-    app->titles_c++;
-    if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated
+      if ( ! ( lang = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_TITLELANG ) ) ) {
+       continue;
+      }
+
+      // increment counter; if we're running out of buffers, grow to handle the new strings
+      app -> titles_c++;
+
+      if ( app -> titles_c > app -> titles_alloc_c ) {
+       // we don't have enough strings allocated
+       app -> titles_alloc_c <<= 1;
+       app -> titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
+       if (!app->titles) return (0); //errno = ENOMEM
+      }
+
+      // populate the stringbuf
+      pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
+      title->language = lang;
+      title->string = text;
+
+      // next
+      pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_TITLE );
+
+    } // foreach
+
+  } else {
+    // older style <title> entry series
+
+    for ( pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem;
+         pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE))
     {
-      app->titles_alloc_c <<= 1;
-      app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
-      if (!app->titles) return (0); //errno = ENOMEM
-    }
 
-    pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
-    title->language = lang;
-    title->string = text;
+      if ( ! pElem->GetText() ) {
+       continue;
+      }
 
-    //pnd_log ( PND_LOG_DEFAULT, (char*)"    Title/Lang: %s/%s\n", text, lang );
+      char *text = strdup(pElem->GetText());
+      if (!text) continue;
 
-  }
+      char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG);
+      if (!lang) continue;
+
+      app->titles_c++;
+      if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated
+      {
+       app->titles_alloc_c <<= 1;
+       app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
+       if (!app->titles) return (0); //errno = ENOMEM
+      }
+
+      pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
+      title->language = lang;
+      title->string = text;
+
+      //pnd_log ( PND_LOG_DEFAULT, (char*)"    Title/Lang: %s/%s\n", text, lang );
+
+    } // for
+
+  } // new or old style <title(s)>
 
   return ( 1 );
 }
 
-unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *app)
-{
-       TiXmlElement *pElem;
-       app->descriptions_alloc_c = 4; //TODO: adjust this based on how many descriptions a PXML usually has. Power of 2.
+unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *app) {
+  TiXmlElement *pElem;
+  app->descriptions_alloc_c = 4; //TODO: adjust this based on how many descriptions a PXML usually has. Power of 2.
 
-       app->descriptions = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->descriptions_alloc_c);
-       if (!app->descriptions) 
-       {
-               app->descriptions_alloc_c = 0;
-               return (0); //errno = NOMEM
-       }
+  app->descriptions = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->descriptions_alloc_c);
+  if (!app->descriptions)
+  {
+    app->descriptions_alloc_c = 0;
+    return (0); //errno = NOMEM
+  }
 
-       for (pElem = hRoot.FirstChild(PND_PXML_ENAME_DESCRIPTION).Element(); pElem; 
-               pElem = pElem->NextSiblingElement(PND_PXML_ENAME_DESCRIPTION))
-       {
+  // similar logic to how <titles> or <title> is parsed
+  // - if <titles> block is found, use that; otherwise fall back to <title> deprecated form
+  if ( (pElem = hRoot.FirstChild ( PND_PXML_NODENAME_DESCRIPTIONS).Element() ) ) {
+    // newer style <descriptions> block
 
-         if ( ! pElem->GetText() ) {
-           continue;
-         }
+    pElem = pElem -> FirstChildElement ( PND_PXML_ENAME_DESCRIPTION );
 
-               char *text = strdup(pElem->GetText());
-               if (!text) continue;
+    while ( pElem ) {
 
-               char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_DESCRLANG);
-               if (!lang) continue;
+      char *text, *lang;
 
-               app->descriptions_c++;
-               if (app->descriptions_c > app->descriptions_alloc_c) //we don't have enough strings allocated
-               {
-                       app->descriptions_alloc_c <<= 1;
-                       app->descriptions = (pnd_localized_string_t*)realloc((void*)app->descriptions, app->descriptions_alloc_c);
-                       if (!app->descriptions) return (0); //errno = ENOMEM
-               }
+      if ( ! ( text = strdup ( pElem -> GetText() ) ) ) {
+       continue;
+      }
 
-               pnd_localized_string_t *description = &app->descriptions[app->descriptions_c - 1];
-               description->language = lang;
-               description->string = text;
-       }
-       return (1);
+      if ( ! ( lang = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_DESCRLANG ) ) ) {
+       if(text) free(text); text = NULL;
+       continue;
+      }
+
+      app->descriptions_c++;
+      if (app->descriptions_c > app->descriptions_alloc_c) //we don't have enough strings allocated
+      {
+       app->descriptions_alloc_c <<= 1;
+       app->descriptions = (pnd_localized_string_t*)realloc((void*)app->descriptions, app->descriptions_alloc_c * sizeof(pnd_localized_string_t) );
+       if (!app->descriptions) { if(text) free(text); if(lang) free(lang); return (0); } //errno = ENOMEM
+      }
+
+      pnd_localized_string_t *description = &app->descriptions[app->descriptions_c - 1];
+      description->language = lang;
+      description->string = text;
+
+      // next
+      pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_DESCRIPTION );
+
+    } // foreach
+
+  } else {
+    // fallback to older approach
+
+    for (pElem = hRoot.FirstChild(PND_PXML_ENAME_DESCRIPTION).Element(); pElem;
+        pElem = pElem->NextSiblingElement(PND_PXML_ENAME_DESCRIPTION))
+    {
+
+      if ( ! pElem->GetText() ) {
+       continue;
+      }
+
+      char *text = strdup(pElem->GetText());
+      if (!text) continue;
+
+      char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_DESCRLANG);
+      if (!lang) { if(text) free(text); text = NULL;  continue; }
+
+      app->descriptions_c++;
+      if (app->descriptions_c > app->descriptions_alloc_c) //we don't have enough strings allocated
+      {
+       app->descriptions_alloc_c <<= 1;
+       app->descriptions = (pnd_localized_string_t*)realloc((void*)app->descriptions, app->descriptions_alloc_c * sizeof(pnd_localized_string_t) );
+       if (!app->descriptions) { if(text) free(text); if(lang) free(lang); return (0); } //errno = ENOMEM
+      }
+
+      pnd_localized_string_t *description = &app->descriptions[app->descriptions_c - 1];
+      description->language = lang;
+      description->string = text;
+    } // for
+
+  } // new form or old form?
+
+  return ( 1 );
 }
 
 unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t **apps ) {
@@ -131,6 +222,27 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
   // is present in PXML line or not; if not, assume application mode?
   hRoot = TiXmlHandle(pElem);
 
+  // workaround for package ID's used by some package managers
+  // get the package ID and store it for each application
+  char* package_id = NULL;
+  char* package_version_major = NULL;
+  char* package_version_minor = NULL;
+  char* package_version_release = NULL;
+  char* package_version_build = NULL;
+  pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element();
+  if ( pElem ) {
+       package_id = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_ID );
+   TiXmlHandle pRoot = TiXmlHandle( pElem );
+   if ( (pElem = pRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) )
+   {
+      package_version_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR);
+      package_version_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR);
+      package_version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL);
+      package_version_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD);
+   }
+  }
+
+  // move to applications element then
   if ( hRoot.FirstChild(PND_PXML_APP).Element() != NULL ) {
     appwrappermode = 1;
     appElem = hRoot.FirstChild(PND_PXML_APP).Element();
@@ -154,10 +266,23 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
       app -> subapp_number = 0;
     }
 
+    // give application the package id, if there is one
+    if( package_id )
+      app -> package_id               = strdup(package_id);
+    if( package_version_major )
+      app -> package_version_major    = strdup(package_version_major);
+    if( package_version_minor )
+      app -> package_version_minor    = strdup(package_version_minor);
+    if( package_version_release )
+      app -> package_version_release  = strdup(package_version_release);
+    if( package_version_build )
+      app -> package_version_build    = strdup(package_version_build);
+
     //Get unique ID first.
     if ( appwrappermode ) {
       app->unique_id = pnd_pxml_get_attribute(appElem, PND_PXML_ATTRNAME_UID);
       //pnd_log ( PND_LOG_DEFAULT, (char*)"  Subapp #%u has unique_id %s\n", appcount, app -> unique_id );
+      app->appdata_dirname = pnd_pxml_get_attribute(appElem, PND_PXML_ATTRNAME_APPDATANAME);
     } else {
       app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID);
       //pnd_log ( PND_LOG_DEFAULT, (char*)"  Only-app #%u has unique_id %s\n", appcount, app -> unique_id );
@@ -185,6 +310,14 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
       app->icon       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC);
     }
 
+    // <info>
+    if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_INFO).Element()) )
+     {
+       app-> info_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_INFONAME );
+       app-> info_filename = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_INFOSRC );
+       app-> info_type = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_INFOTYPE );
+     }
+
     //The preview pics:
     if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) )
     {
@@ -197,7 +330,7 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
        {
          app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
        }
-      }        
+      }
     } //previewpic
 
     //The author info:
@@ -234,7 +367,7 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
       i = 0;
 
       //Goes through all the top-level categories and their sub-categories. i helps limit these to 2.
-      for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2; 
+      for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2;
           pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++)
       {
        //TODO: Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed.
@@ -283,14 +416,20 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
     {
       i = 0;
       //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number.
-      for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3; 
+      for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3;
           pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++)
       {
        char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME);
        char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE);
        char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS);
 
-       if (!(name && filetype && paramter)) continue;
+       if (!(name && filetype && paramter))
+       {
+         if(name)     free(name);
+         if(filetype) free(filetype);
+         if(paramter) free(paramter);
+         continue;
+       }
 
        switch(i) //TODO: same problem here: only 3 associations supported
        {
@@ -315,19 +454,22 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
          app->associationitem3_parameter = paramter;
        }
        }
+       if(name)     free(name);
+       if(filetype) free(filetype);
+       if(paramter) free(paramter);
       }
     }
 
     //Performance related things (aka: Clockspeed XD):
     pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element();
     if (pElem)
-    {  
+    {
       app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ);
     }
 
     // Package
     pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element();
-    if ( pElem ) {     
+    if ( pElem ) {
       app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME );
       app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE );
     }
@@ -342,10 +484,11 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
        if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
          // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent.
          app -> mkdir_sp = strdup ( t );
+         free(t); // free this attribute
        }
 
        while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) {
-             
+
          if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
            char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ );
 
@@ -355,6 +498,7 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
              app -> mkdir_sp = foo;
            } // assuming we got ram, lets cat it all together
 
+           free(t); // free this attribute
          } // got another elem?
 
        } // while
@@ -393,6 +537,17 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
 
   } // while finding apps
 
+  if( package_id )
+     free(package_id);
+  if( package_version_major )
+     free(package_version_major);
+  if( package_version_minor )
+     free(package_version_minor);
+  if( package_version_release )
+     free(package_version_release);
+  if( package_version_build )
+     free(package_version_build);
+
   return (1);
 }