diff playtreeparser.c @ 32623:d90ee6158b89

Add playlist parser for .nsc files. Tested to properly decode .nsc files, but not properly tested since no publically available stream could be found.
author reimar
date Sun, 12 Dec 2010 19:25:43 +0000
parents b39155e98ac3
children bfe41b532fe9
line wrap: on
line diff
--- a/playtreeparser.c	Sun Dec 12 17:16:59 2010 +0000
+++ b/playtreeparser.c	Sun Dec 12 19:25:43 2010 +0000
@@ -680,6 +680,116 @@
   return entry;
 }
 
+/**
+ * \brief decode the base64 used in nsc files
+ * \param in input string, 0-terminated
+ * \param buf output buffer, must point to memory suitable for realloc,
+ *            will be NULL on failure.
+ * \return decoded length in bytes
+ */
+static int decode_nsc_base64(char *in, char **buf) {
+  int i, j, n;
+  if (in[0] != '0' || in[1] != '2')
+    goto err_out;
+  in += 2; // skip prefix
+  if (strlen(in) < 16) // error out if nothing to decode
+    goto err_out;
+  in += 12; // skip encoded string length
+  n = strlen(in) / 4;
+  *buf = realloc(*buf, n * 3);
+  for (i = 0; i < n; i++) {
+    uint8_t c[4];
+    for (j = 0; j < 4; j++) {
+      c[j] = in[4 * i + j];
+      if (c[j] >= '0' && c[j] <= '9') c[j] += 0 - '0';
+      else if (c[j] >= 'A' && c[j] <= 'Z') c[j] += 10 - 'A';
+      else if (c[j] >= 'a' && c[j] <= 'z') c[j] += 36 - 'a';
+      else if (c[j] == '{') c[j] = 62;
+      else if (c[j] == '}') c[j] = 63;
+      else {
+        mp_msg(MSGT_PLAYTREE, MSGL_ERR, "Invalid character %c (0x%02"PRIx8")\n", c[j], c[j]);
+        goto err_out;
+      }
+    }
+    (*buf)[3 * i] = (c[0] << 2) | (c[1] >> 4);
+    (*buf)[3 * i + 1] = (c[1] << 4) | (c[2] >> 2);
+    (*buf)[3 * i + 2] = (c[2] << 6) | c[3];
+  }
+  return 3 * n;
+err_out:
+  if (*buf) free(*buf);
+  *buf = NULL;
+  return 0;
+}
+
+/**
+ * \brief "converts" utf16 to ascii by just discarding every second byte
+ * \param buf buffer to convert
+ * \param len lenght of buffer, must be > 0
+ */
+static void utf16_to_ascii(char *buf, int len) {
+  int i;
+  if (len <= 0) return;
+  for (i = 0; i < len / 2; i++)
+    buf[i] = buf[i * 2];
+  buf[i] = 0; // just in case
+}
+
+static play_tree_t *parse_nsc(play_tree_parser_t* p) {
+  char *line, *addr = NULL, *url, *unicast_url = NULL;
+  int port = 0;
+  play_tree_t *entry = NULL;
+
+  mp_msg(MSGT_PLAYTREE,MSGL_V,"Trying nsc playlist...\n");
+  while((line = play_tree_parser_get_line(p)) != NULL) {
+    strstrip(line);
+    if(!line[0]) // Ignore empties
+      continue;
+    if (strncasecmp(line,"[Address]", 9) == 0)
+      break; // nsc header found
+    else
+      return NULL;
+  }
+  mp_msg(MSGT_PLAYTREE,MSGL_V,"Detected nsc playlist format\n");
+  play_tree_parser_stop_keeping(p);
+  while ((line = play_tree_parser_get_line(p)) != NULL) {
+    strstrip(line);
+    if (!line[0])
+      continue;
+    if (strncasecmp(line, "Unicast URL=", 12) == 0) {
+      int len = decode_nsc_base64(&line[12], &unicast_url);
+      if (len <= 0)
+        mp_msg(MSGT_PLAYTREE, MSGL_WARN, "[nsc] Unsupported Unicast URL encoding\n");
+      else
+        utf16_to_ascii(unicast_url, len);
+    } else if (strncasecmp(line, "IP Address=", 11) == 0) {
+      int len = decode_nsc_base64(&line[11], &addr);
+      if (len <= 0)
+        mp_msg(MSGT_PLAYTREE, MSGL_WARN, "[nsc] Unsupported IP Address encoding\n");
+      else
+        utf16_to_ascii(addr, len);
+    } else if (strncasecmp(line, "IP Port=", 8) == 0) {
+      port = strtol(&line[8], NULL, 0);
+    }
+  }
+
+  if (unicast_url)
+    url = strdup(unicast_url);
+  else if (addr && port) {
+    url = malloc(strlen(addr) + 7 + 20 + 1);
+    sprintf(url, "http://%s:%i", addr, port);
+  } else
+   goto out;
+
+  entry = play_tree_new();
+  play_tree_add_file(entry, url);
+  free(url);
+out:
+  if (addr) free(addr);
+  if (unicast_url) free(unicast_url);
+  return entry;
+}
+
 play_tree_t*
 parse_playtree(stream_t *stream, int forced) {
   play_tree_parser_t* p;
@@ -839,6 +949,10 @@
     if(tree) break;
     play_tree_parser_reset(p);
 
+    tree = parse_nsc(p);
+    if(tree) break;
+    play_tree_parser_reset(p);
+
     // Here come the others formats ( textplain must stay the last one )
     if (forced)
     {