diff options
Diffstat (limited to 'src/xplist.c')
| -rw-r--r-- | src/xplist.c | 194 | 
1 files changed, 122 insertions, 72 deletions
diff --git a/src/xplist.c b/src/xplist.c index a7d52e5..7e39ea4 100644 --- a/src/xplist.c +++ b/src/xplist.c @@ -41,7 +41,6 @@  #include <limits.h>  #include <node.h> -#include <node_list.h>  #include "plist.h"  #include "base64.h" @@ -71,7 +70,7 @@  #define MAC_EPOCH 978307200 -#define MAX_DATA_BYTES_PER_LINE(__i) (((76 - (__i << 3)) >> 2) * 3) +#define MAX_DATA_BYTES_PER_LINE(__i) (((76 - ((__i) << 3)) >> 2) * 3)  static const char XML_PLIST_PROLOG[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\  <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\ @@ -81,8 +80,10 @@ static const char XML_PLIST_EPILOG[] = "</plist>\n";  #ifdef DEBUG  static int plist_xml_debug = 0;  #define PLIST_XML_ERR(...) if (plist_xml_debug) { fprintf(stderr, "libplist[xmlparser] ERROR: " __VA_ARGS__); } +#define PLIST_XML_WRITE_ERR(...) if (plist_xml_debug) { fprintf(stderr, "libplist[xmlwriter] ERROR: " __VA_ARGS__); }  #else  #define PLIST_XML_ERR(...) +#define PLIST_XML_WRITE_ERR(...)  #endif  void plist_xml_init(void) @@ -101,6 +102,13 @@ void plist_xml_deinit(void)      /* deinit XML stuff */  } +void plist_xml_set_debug(int debug) +{ +#if DEBUG +    plist_xml_debug = debug; +#endif +} +  static size_t dtostr(char *buf, size_t bufsize, double realval)  {      size_t len = 0; @@ -113,7 +121,7 @@ static size_t dtostr(char *buf, size_t bufsize, double realval)      } else {          size_t i = 0;          len = snprintf(buf, bufsize, "%.*g", 17, realval); -        for (i = 0; i < len; i++) { +        for (i = 0; buf && i < len; i++) {              if (buf[i] == ',') {                  buf[i] = '.';                  break; @@ -125,7 +133,7 @@ static size_t dtostr(char *buf, size_t bufsize, double realval)      return len;  } -static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) +static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth)  {      plist_data_t node_data = NULL; @@ -139,8 +147,10 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth)      uint32_t i = 0; -    if (!node) -        return; +    if (!node) { +        PLIST_XML_WRITE_ERR("Encountered invalid empty node in property list\n"); +        return PLIST_ERR_INVALID_ARG; +    }      node_data = plist_get_data(node); @@ -158,14 +168,14 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth)      }      break; -    case PLIST_UINT: +    case PLIST_INT:          tag = XPLIST_INT;          tag_len = XPLIST_INT_LEN;          val = (char*)malloc(64);          if (node_data->length == 16) { -            val_len = snprintf(val, 64, "%"PRIu64, node_data->intval); +            val_len = snprintf(val, 64, "%" PRIu64, node_data->intval);          } else { -            val_len = snprintf(val, 64, "%"PRIi64, node_data->intval); +            val_len = snprintf(val, 64, "%" PRIi64, node_data->intval);          }          break; @@ -211,8 +221,7 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth)              struct TM _btime;              struct TM *btime = gmtime64_r(&timev, &_btime);              if (btime) { -                val = (char*)malloc(24); -                memset(val, 0, 24); +                val = (char*)calloc(1, 24);                  struct tm _tmcopy;                  copy_TM64_to_tm(btime, &_tmcopy);                  val_len = strftime(val, 24, "%Y-%m-%dT%H:%M:%SZ", &_tmcopy); @@ -228,13 +237,16 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth)          tag_len = XPLIST_DICT_LEN;          val = (char*)malloc(64);          if (node_data->length == 16) { -            val_len = snprintf(val, 64, "%"PRIu64, node_data->intval); +            val_len = snprintf(val, 64, "%" PRIu64, node_data->intval);          } else { -            val_len = snprintf(val, 64, "%"PRIi64, node_data->intval); +            val_len = snprintf(val, 64, "%" PRIi64, node_data->intval);          }          break; +    case PLIST_NULL: +        PLIST_XML_WRITE_ERR("PLIST_NULL type is not valid for XML format\n"); +        return PLIST_ERR_FORMAT;      default: -        break; +        return PLIST_ERR_UNKNOWN;      }      for (i = 0; i < depth; i++) { @@ -352,9 +364,10 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth)          if (node_data->type == PLIST_DICT && node->children) {              assert((node->children->count % 2) == 0);          } -        node_t *ch; +        node_t ch;          for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { -            node_to_xml(ch, outbuf, depth+1); +            plist_err_t res = node_to_xml(ch, outbuf, depth+1); +            if (res < 0) return res;          }          /* fix indent for structured types */ @@ -370,8 +383,7 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth)          str_buf_append(*outbuf, ">", 1);      }      str_buf_append(*outbuf, "\n", 1); - -    return; +    return PLIST_ERR_SUCCESS;  }  static void parse_date(const char *strval, struct TM *btime) @@ -403,7 +415,7 @@ static int num_digits_i(int64_t i)      int64_t po10;      n=1;      if (i < 0) { -        i = -i; +        i = (i == INT64_MIN) ? INT64_MAX : -i;          n++;      }      po10=10; @@ -432,15 +444,15 @@ static int num_digits_u(uint64_t i)      return n;  } -static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) +static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth)  {      plist_data_t data;      if (!node) { -        return; +        return PLIST_ERR_INVALID_ARG;      }      data = plist_get_data(node);      if (node->children) { -        node_t *ch; +        node_t ch;          for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {              node_estimate_size(ch, size, depth + 1);          } @@ -473,7 +485,7 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth)              *size += data->length;              *size += (XPLIST_KEY_LEN << 1) + 6;              break; -        case PLIST_UINT: +        case PLIST_INT:              if (data->length == 16) {                  *size += num_digits_u(data->intval);              } else { @@ -482,7 +494,7 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth)              *size += (XPLIST_INT_LEN << 1) + 6;              break;          case PLIST_REAL: -            *size += num_digits_i((int64_t)data->realval) + 7; +            *size += dtostr(NULL, 0, data->realval);              *size += (XPLIST_REAL_LEN << 1) + 6;              break;          case PLIST_DATE: @@ -505,37 +517,58 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth)              *size += 18; /* <key>CF$UID</key> */              *size += (XPLIST_INT_LEN << 1) + 6;              break; +        case PLIST_NULL: +            PLIST_XML_WRITE_ERR("PLIST_NULL type is not valid for XML format\n"); +            return PLIST_ERR_FORMAT;          default: -            break; +            PLIST_XML_WRITE_ERR("invalid node type encountered\n"); +            return PLIST_ERR_UNKNOWN;          }          *size += indent;      } +    return PLIST_ERR_SUCCESS;  } -PLIST_API void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) +plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length)  {      uint64_t size = 0; -    node_estimate_size(plist, &size, 0); +    plist_err_t res; + +    if (!plist || !plist_xml || !length) { +        return PLIST_ERR_INVALID_ARG; +    } + +    res = node_estimate_size((node_t)plist, &size, 0); +    if (res < 0) { +        return res; +    }      size += sizeof(XML_PLIST_PROLOG) + sizeof(XML_PLIST_EPILOG) - 1;      strbuf_t *outbuf = str_buf_new(size); +    if (!outbuf) { +        PLIST_XML_WRITE_ERR("Could not allocate output buffer\n"); +        return PLIST_ERR_NO_MEM; +    }      str_buf_append(outbuf, XML_PLIST_PROLOG, sizeof(XML_PLIST_PROLOG)-1); -    node_to_xml(plist, &outbuf, 0); +    res = node_to_xml((node_t)plist, &outbuf, 0); +    if (res < 0) { +        str_buf_free(outbuf); +        *plist_xml = NULL; +        *length = 0; +        return res; +    }      str_buf_append(outbuf, XML_PLIST_EPILOG, sizeof(XML_PLIST_EPILOG)); -    *plist_xml = outbuf->data; +    *plist_xml = (char*)outbuf->data;      *length = outbuf->len - 1;      outbuf->data = NULL;      str_buf_free(outbuf); -} -PLIST_API void plist_to_xml_free(char *plist_xml) -{ -    free(plist_xml); +    return PLIST_ERR_SUCCESS;  }  struct _parse_ctx { @@ -638,14 +671,14 @@ static void text_parts_free(text_part_t *tp)  {      while (tp) {          text_part_t *tmp = tp; -        tp = tp->next; +        tp = (text_part_t*)tp->next;          free(tmp);      }  }  static text_part_t* text_part_append(text_part_t* parts, const char *begin, size_t length, int is_cdata)  { -    text_part_t* newpart = malloc(sizeof(text_part_t)); +    text_part_t* newpart = (text_part_t*)malloc(sizeof(text_part_t));      assert(newpart);      parts->next = text_part_init(newpart, begin, length, is_cdata);      return newpart; @@ -751,7 +784,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le          }      } while (1);      ctx->pos++; -    if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len)) { +    if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) {          PLIST_XML_ERR("EOF or end tag mismatch\n");          ctx->err++;          return NULL; @@ -897,9 +930,9 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t      text_part_t *tmp = tp;      while (tp && tp->begin) {          total_length += tp->length; -        tp = tp->next; +        tp = (text_part_t*)tp->next;      } -    str = malloc(total_length + 1); +    str = (char*)malloc(total_length + 1);      assert(str);      p = str;      tp = tmp; @@ -914,7 +947,7 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t              }          }          p += len; -        tp = tp->next; +        tp = (text_part_t*)tp->next;      }      *p = '\0';      if (length) { @@ -926,7 +959,7 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t      return str;  } -static void node_from_xml(parse_ctx ctx, plist_t *plist) +static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)  {      char *tag = NULL;      char *keyname = NULL; @@ -967,7 +1000,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                  ctx->err++;                  goto err_out;              } -            if (strncmp(ctx->pos, "?>", 2)) { +            if (strncmp(ctx->pos, "?>", 2) != 0) {                  PLIST_XML_ERR("Couldn't find <? tag closing marker\n");                  ctx->err++;                  goto err_out; @@ -979,7 +1012,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)              if (((ctx->end - ctx->pos) > 3) && !strncmp(ctx->pos, "!--", 3)) {                  ctx->pos += 3;                  find_str(ctx,"-->", 3, 0); -                if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3)) { +                if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) {                      PLIST_XML_ERR("Couldn't find end of comment\n");                      ctx->err++;                      goto err_out; @@ -1008,7 +1041,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                  }                  if (embedded_dtd) {                      find_str(ctx, "]>", 2, 1); -                    if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2)) { +                    if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) {                          PLIST_XML_ERR("Couldn't find end of DOCTYPE\n");                          ctx->err++;                          goto err_out; @@ -1033,8 +1066,8 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                  ctx->err++;                  goto err_out;              } -            int taglen = ctx->pos - p; -            tag = malloc(taglen + 1); +            size_t taglen = ctx->pos - p; +            tag = (char*)malloc(taglen + 1);              strncpy(tag, p, taglen);              tag[taglen] = '\0';              if (*ctx->pos != '>') { @@ -1051,7 +1084,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                  goto err_out;              }              if (*(ctx->pos-1) == '/') { -                int idx = ctx->pos - p - 1; +                size_t idx = ctx->pos - p - 1;                  if (idx < taglen)                      tag[idx] = '\0';                  is_empty = 1; @@ -1072,7 +1105,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      goto err_out;                  } -                struct node_path_item *path_item = malloc(sizeof(struct node_path_item)); +                struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item));                  if (!path_item) {                      PLIST_XML_ERR("out of memory when allocating node path item\n");                      ctx->err++; @@ -1100,7 +1133,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      goto err_out;                  }                  struct node_path_item *path_item = node_path; -                node_path = node_path->prev; +                node_path = (struct node_path_item*)node_path->prev;                  free(path_item);                  free(tag); @@ -1123,7 +1156,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part);                      if (!tp) {                          PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); -                        text_parts_free(first_part.next); +                        text_parts_free((text_part_t*)first_part.next);                          ctx->err++;                          goto err_out;                      } @@ -1132,7 +1165,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                          char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free);                          if (!str_content) {                              PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); -                            text_parts_free(first_part.next); +                            text_parts_free((text_part_t*)first_part.next);                              ctx->err++;                              goto err_out;                          } @@ -1144,7 +1177,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                              }                              str++;                          } -                        data->intval = strtoull((char*)str, NULL, 0); +                        data->intval = strtoull(str, NULL, 0);                          if (is_negative || (data->intval <= INT64_MAX)) {                              uint64_t v = data->intval;                              if (is_negative) { @@ -1161,20 +1194,20 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      } else {                          is_empty = 1;                      } -                    text_parts_free(tp->next); +                    text_parts_free((text_part_t*)tp->next);                  }                  if (is_empty) {                      data->intval = 0;                      data->length = 8;                  } -                data->type = PLIST_UINT; +                data->type = PLIST_INT;              } else if (!strcmp(tag, XPLIST_REAL)) {                  if (!is_empty) {                      text_part_t first_part = { NULL, 0, 0, NULL };                      text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part);                      if (!tp) {                          PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); -                        text_parts_free(first_part.next); +                        text_parts_free((text_part_t*)first_part.next);                          ctx->err++;                          goto err_out;                      } @@ -1183,7 +1216,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                          char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free);                          if (!str_content) {                              PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); -                            text_parts_free(first_part.next); +                            text_parts_free((text_part_t*)first_part.next);                              ctx->err++;                              goto err_out;                          } @@ -1192,7 +1225,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                              free(str_content);                          }                      } -                    text_parts_free(tp->next); +                    text_parts_free((text_part_t*)tp->next);                  }                  data->type = PLIST_REAL;                  data->length = 8; @@ -1218,12 +1251,12 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      size_t length = 0;                      if (!tp) {                          PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); -                        text_parts_free(first_part.next); +                        text_parts_free((text_part_t*)first_part.next);                          ctx->err++;                          goto err_out;                      }                      str = text_parts_get_content(tp, 1, &length, NULL); -                    text_parts_free(first_part.next); +                    text_parts_free((text_part_t*)first_part.next);                      if (!str) {                          PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);                          ctx->err++; @@ -1251,7 +1284,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part);                      if (!tp) {                          PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); -                        text_parts_free(first_part.next); +                        text_parts_free((text_part_t*)first_part.next);                          ctx->err++;                          goto err_out;                      } @@ -1260,7 +1293,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                          char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free);                          if (!str_content) {                              PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); -                            text_parts_free(first_part.next); +                            text_parts_free((text_part_t*)first_part.next);                              ctx->err++;                              goto err_out;                          } @@ -1274,7 +1307,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                              free(str_content);                          }                      } -                    text_parts_free(tp->next); +                    text_parts_free((text_part_t*)tp->next);                  }                  data->type = PLIST_DATA;              } else if (!strcmp(tag, XPLIST_DATE)) { @@ -1283,7 +1316,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part);                      if (!tp) {                          PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); -                        text_parts_free(first_part.next); +                        text_parts_free((text_part_t*)first_part.next);                          ctx->err++;                          goto err_out;                      } @@ -1294,7 +1327,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                          char *str_content = text_parts_get_content(tp, 0, &length, &requires_free);                          if (!str_content) {                              PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); -                            text_parts_free(first_part.next); +                            text_parts_free((text_part_t*)first_part.next);                              ctx->err++;                              goto err_out;                          } @@ -1314,7 +1347,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                              free(str_content);                          }                      } -                    text_parts_free(tp->next); +                    text_parts_free((text_part_t*)tp->next);                      data->realval = (double)(timev - MAC_EPOCH);                  }                  data->length = sizeof(double); @@ -1358,7 +1391,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      }                  }                  if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) { -                    struct node_path_item *path_item = malloc(sizeof(struct node_path_item)); +                    struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item));                      if (!path_item) {                          PLIST_XML_ERR("out of memory when allocating node path item\n");                          ctx->err++; @@ -1383,10 +1416,10 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist)                      goto err_out;                  }                  struct node_path_item *path_item = node_path; -                node_path = node_path->prev; +                node_path = (struct node_path_item*)node_path->prev;                  free(path_item); -                parent = ((node_t*)parent)->parent; +                parent = ((node_t)parent)->parent;                  if (!parent) {                      goto err_out;                  } @@ -1414,24 +1447,41 @@ err_out:      /* clean up node_path if required */      while (node_path) {          struct node_path_item *path_item = node_path; -        node_path = path_item->prev; +        node_path = (struct node_path_item*)path_item->prev;          free(path_item);      }      if (ctx->err) {          plist_free(*plist);          *plist = NULL; +        return PLIST_ERR_PARSE;      } + +    /* check if we have a UID "dict" so we can replace it with a proper UID node */ +    if (PLIST_IS_DICT(*plist) && plist_dict_get_size(*plist) == 1) { +        plist_t value = plist_dict_get_item(*plist, "CF$UID"); +        if (PLIST_IS_UINT(value)) { +            uint64_t u64val = 0; +            plist_get_uint_val(value, &u64val); +            plist_free(*plist); +            *plist = plist_new_uid(u64val); +        } +    } + +    return PLIST_ERR_SUCCESS;  } -PLIST_API void plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist) +plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist)  { +    if (!plist) { +        return PLIST_ERR_INVALID_ARG; +    } +    *plist = NULL;      if (!plist_xml || (length == 0)) { -        *plist = NULL; -        return; +        return PLIST_ERR_INVALID_ARG;      }      struct _parse_ctx ctx = { plist_xml, plist_xml + length, 0 }; -    node_from_xml(&ctx, plist); +    return node_from_xml(&ctx, plist);  }  | 
