Bug 1306477 - Updates to latest upstream version of nestegg. r=kinetik draft
authorJay Harris <jharris@mozilla.com>
Wed, 08 Feb 2017 15:17:24 +1300
changeset 483298 7c5e6588dfd857433bff801ad8aece0971641c7a
parent 483291 195049fabb7ac5709e5f75614ba630ba3d1b5a9b
child 483299 fa5c430fa0b2ca7249591e612be8b3ed125c5ae3
push id45277
push userbmo:jharris@mozilla.com
push dateTue, 14 Feb 2017 02:59:42 +0000
reviewerskinetik
bugs1306477
milestone54.0a1
Bug 1306477 - Updates to latest upstream version of nestegg. r=kinetik MozReview-Commit-ID: D2vrjB3wOjh
media/libnestegg/README_MOZILLA
media/libnestegg/include/nestegg.h
media/libnestegg/src/nestegg.c
--- a/media/libnestegg/README_MOZILLA
+++ b/media/libnestegg/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the nestegg
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
 
-The git commit ID used was 1eeeccee205f7aee0386898508c1a68427e0dcc2.
+The git commit ID used was 5e2fb721d5808785475d68f63fc97d45b8a4ef03.
--- a/media/libnestegg/include/nestegg.h
+++ b/media/libnestegg/include/nestegg.h
@@ -87,19 +87,20 @@ extern "C" {
 #define NESTEGG_LOG_INFO     10    /**< Informational level log message. */
 #define NESTEGG_LOG_WARNING  100   /**< Warning level log message. */
 #define NESTEGG_LOG_ERROR    1000  /**< Error level log message. */
 #define NESTEGG_LOG_CRITICAL 10000 /**< Critical level log message. */
 
 #define NESTEGG_ENCODING_COMPRESSION 0 /**< Content encoding type is compression. */
 #define NESTEGG_ENCODING_ENCRYPTION  1 /**< Content encoding type is encryption. */
 
-#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE       0 /**< Packet does not have signal byte */
-#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED 1 /**< Packet has signal byte and is unencrypted */
-#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED   2 /**< Packet has signal byte and is encrypted */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE         0 /**< Packet does not have signal byte */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED   1 /**< Packet has signal byte and is unencrypted */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED     2 /**< Packet has signal byte and is encrypted */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED   4 /**< Packet has signal byte and is partitioned */
 
 #define NESTEGG_PACKET_HAS_KEYFRAME_FALSE   0 /**< Packet contains only keyframes. */
 #define NESTEGG_PACKET_HAS_KEYFRAME_TRUE    1 /**< Packet does not contain any keyframes */
 #define NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN 2 /**< Packet may or may not contain keyframes */
 
 typedef struct nestegg nestegg;               /**< Opaque handle referencing the stream state. */
 typedef struct nestegg_packet nestegg_packet; /**< Opaque handle referencing a packet of data. */
 
@@ -419,31 +420,45 @@ int nestegg_packet_discard_padding(neste
 /** Query if a packet is encrypted.
     @param packet Packet initialized by #nestegg_read_packet.
     @retval  #NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE No signal byte, encryption
              information not read from packet.
     @retval  #NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED Encrypted bit not
              set, encryption information not read from packet.
     @retval  #NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED Encrypted bit set,
              encryption infomation read from packet.
+    @retval  #NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED Partitioned bit set,
+             encryption and parition information read from packet.
     @retval -1 Error.*/
 int nestegg_packet_encryption(nestegg_packet * packet);
 
 /** Query the IV for an encrypted packet. Expects a packet from an encrypted
     track, and will return error if given a packet that has no signal btye.
     @param packet Packet initialized by #nestegg_read_packet.
     @param iv     Storage for queried iv.
     @param length Length of returned iv, may be 0.
                   The data is owned by the #nestegg_packet packet.
     @retval  0 Success.
     @retval -1 Error.
   */
 int nestegg_packet_iv(nestegg_packet * packet, unsigned char const ** iv,
                       size_t * length);
 
+/** Query the packet for offsets.
+@param packet            Packet initialized by #nestegg_read_packet.
+@param partition_offsets Storage for queried offsets.
+@param num_offsets       Length of returned offsets, may be 0.
+The data is owned by the #nestegg_packet packet.
+@retval  0 Success.
+@retval -1 Error.
+*/
+int nestegg_packet_offsets(nestegg_packet * packet,
+                           uint32_t const ** partition_offsets,
+                           uint8_t * num_offsets);
+
 /** Returns reference_block given packet
     @param packet          Packet initialized by #nestegg_read_packet.
     @param reference_block pointer to store reference block in.
     @retval  0 Success.
     @retval -1 Error. */
 int nestegg_packet_reference_block(nestegg_packet * packet,
                                    int64_t * reference_block);
 
--- a/media/libnestegg/src/nestegg.c
+++ b/media/libnestegg/src/nestegg.c
@@ -159,21 +159,26 @@ enum ebml_type_enum {
 
 /* Track Encryption */
 #define CONTENT_ENC_ALGO_AES        5
 #define AES_SETTINGS_CIPHER_CTR     1
 
 /* Packet Encryption */
 #define SIGNAL_BYTE_SIZE            1
 #define IV_SIZE                     8
+#define NUM_PACKETS_SIZE            1
+#define PACKET_OFFSET_SIZE          4
 
 /* Signal Byte */
 #define PACKET_ENCRYPTED            1
 #define ENCRYPTED_BIT_MASK          (1 << 0)
 
+#define PACKET_PARTITIONED          2
+#define PARTITIONED_BIT_MASK        (1 << 1)
+
 enum vint_mask {
   MASK_NONE,
   MASK_FIRST_BIT
 };
 
 struct ebml_binary {
   unsigned char * data;
   size_t length;
@@ -333,16 +338,18 @@ struct saved_state {
   uint64_t last_size;
   int last_valid;
 };
 
 struct frame_encryption {
   unsigned char * iv;
   size_t length;
   uint8_t signal_byte;
+  uint8_t num_partitions;
+  uint32_t * partition_offsets;
 };
 
 struct frame {
   unsigned char * data;
   size_t length;
   struct frame_encryption * frame_encryption;
   struct frame * next;
 };
@@ -1065,17 +1072,16 @@ ne_read_simple(nestegg * ctx, struct ebm
     r = ne_read_string(ctx, &storage->v.s, length);
     break;
   case TYPE_BINARY:
     r = ne_read_binary(ctx, &storage->v.b, length);
     break;
   case TYPE_MASTER:
   case TYPE_UNKNOWN:
   default:
-    r = 0;
     assert(0);
     break;
   }
 
   if (r == 1)
     storage->read = 1;
 
   return r;
@@ -1354,29 +1360,75 @@ ne_find_track_entry(nestegg * ctx, unsig
       return node->data;
     tracks += 1;
     node = node->next;
   }
 
   return NULL;
 }
 
+static struct frame *
+ne_alloc_frame(void)
+{
+  struct frame * f = ne_alloc(sizeof(*f));
+
+  if (!f)
+    return NULL;
+
+  f->data = NULL;
+  f->length = 0;
+  f->frame_encryption = NULL;
+  f->next = NULL;
+
+  return f;
+}
+
+static struct frame_encryption *
+ne_alloc_frame_encryption(void)
+{
+  struct frame_encryption * f = ne_alloc(sizeof(*f));
+
+  if (!f)
+    return NULL;
+
+  f->iv = NULL;
+  f->length = 0;
+  f->signal_byte = 0;
+  f->num_partitions = 0;
+  f->partition_offsets = NULL;
+
+  return f;
+}
+
+static void
+ne_free_frame(struct frame * f)
+{
+  if (f->frame_encryption) {
+    free(f->frame_encryption->iv);
+    free(f->frame_encryption->partition_offsets);
+  }
+
+  free(f->frame_encryption);
+  free(f->data);
+  free(f);
+}
+
 static int
 ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_packet ** data)
 {
   int r;
   int64_t timecode, abs_timecode;
   nestegg_packet * pkt;
   struct frame * f, * last;
   struct track_entry * entry;
   double track_scale;
   uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total,
            encoding_type, encryption_algo, encryption_mode;
   unsigned int i, lacing, track;
-  uint8_t signal_byte, keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN;
+  uint8_t signal_byte, keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN, j = 0;
   size_t consumed = 0, data_size, encryption_size;
 
   *data = NULL;
 
   if (block_size > LIMIT_BLOCK)
     return -1;
 
   r = ne_read_vint(ctx->io, &track_number, &length);
@@ -1419,16 +1471,20 @@ ne_read_block(nestegg * ctx, uint64_t bl
   case LACING_XIPH:
   case LACING_FIXED:
   case LACING_EBML:
     r = ne_read_uint(ctx->io, &frames, 1);
     if (r != 1)
       return r;
     consumed += 1;
     frames += 1;
+    break;
+  default:
+    assert(0);
+    return -1;
   }
 
   if (frames > 256)
     return -1;
 
   switch (lacing) {
   case LACING_NONE:
     frame_sizes[0] = block_size - consumed;
@@ -1448,16 +1504,19 @@ ne_read_block(nestegg * ctx, uint64_t bl
     break;
   case LACING_EBML:
     if (frames == 1)
       return -1;
     r = ne_read_ebml_lacing(ctx->io, block_size, &consumed, frames, frame_sizes);
     if (r != 1)
       return r;
     break;
+  default:
+    assert(0);
+    return -1;
   }
 
   /* Sanity check unlaced frame sizes against total block size. */
   total = consumed;
   for (i = 0; i < frames; ++i)
     total += frame_sizes[i];
   if (total > block_size)
     return -1;
@@ -1504,82 +1563,98 @@ ne_read_block(nestegg * ctx, uint64_t bl
            block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9, flags, frames);
 
   last = NULL;
   for (i = 0; i < frames; ++i) {
     if (frame_sizes[i] > LIMIT_FRAME) {
       nestegg_free_packet(pkt);
       return -1;
     }
-    f = ne_alloc(sizeof(*f));
+    f = ne_alloc_frame();
     if (!f) {
       nestegg_free_packet(pkt);
       return -1;
     }
     /* Parse encryption */
     if (encoding_type == NESTEGG_ENCODING_ENCRYPTION) {
       r = ne_io_read(ctx->io, &signal_byte, SIGNAL_BYTE_SIZE);
       if (r != 1) {
-        free(f);
+        ne_free_frame(f);
         nestegg_free_packet(pkt);
         return r;
       }
-      f->frame_encryption = ne_alloc(sizeof(*f->frame_encryption));
+      f->frame_encryption = ne_alloc_frame_encryption();
       if (!f->frame_encryption) {
-        free(f);
+        ne_free_frame(f);
         nestegg_free_packet(pkt);
         return -1;
       }
       f->frame_encryption->signal_byte = signal_byte;
       if ((signal_byte & ENCRYPTED_BIT_MASK) == PACKET_ENCRYPTED) {
         f->frame_encryption->iv = ne_alloc(IV_SIZE);
         if (!f->frame_encryption->iv) {
-          free(f->frame_encryption);
-          free(f);
+          ne_free_frame(f);
           nestegg_free_packet(pkt);
           return -1;
         }
         r = ne_io_read(ctx->io, f->frame_encryption->iv, IV_SIZE);
         if (r != 1) {
-          free(f->frame_encryption->iv);
-          free(f->frame_encryption);
-          free(f);
+          ne_free_frame(f);
           nestegg_free_packet(pkt);
           return r;
         }
         f->frame_encryption->length = IV_SIZE;
         encryption_size = SIGNAL_BYTE_SIZE + IV_SIZE;
+
+        if ((signal_byte & PARTITIONED_BIT_MASK) == PACKET_PARTITIONED) {
+          r = ne_io_read(ctx->io, &f->frame_encryption->num_partitions, NUM_PACKETS_SIZE);
+          if (r != 1) {
+            ne_free_frame(f);
+            nestegg_free_packet(pkt);
+            return r;
+          }
+
+          encryption_size += NUM_PACKETS_SIZE + f->frame_encryption->num_partitions * PACKET_OFFSET_SIZE;
+          f->frame_encryption->partition_offsets = ne_alloc(f->frame_encryption->num_partitions * PACKET_OFFSET_SIZE);
+
+          for (j = 0; j < f->frame_encryption->num_partitions; ++j) {
+            uint64_t value = 0;
+            r = ne_read_uint(ctx->io, &value, PACKET_OFFSET_SIZE);
+            if (r != 1) {
+              break;
+            }
+
+            f->frame_encryption->partition_offsets[j] = (uint32_t) value;
+          }
+
+          /* If any of the partition offsets did not return 1, then fail. */
+          if (j != f->frame_encryption->num_partitions) {
+            ne_free_frame(f);
+            nestegg_free_packet(pkt);
+            return r;
+          }
+        }
       } else {
-        f->frame_encryption->iv = NULL;
-        f->frame_encryption->length = 0;
         encryption_size = SIGNAL_BYTE_SIZE;
       }
     } else {
-      f->frame_encryption = NULL;
       encryption_size = 0;
     }
     data_size = frame_sizes[i] - encryption_size;
     /* Encryption parsed */
     f->data = ne_alloc(data_size);
     if (!f->data) {
-      if (f->frame_encryption)
-        free(f->frame_encryption->iv);
-      free(f->frame_encryption);
-      free(f);
+      ne_free_frame(f);
       nestegg_free_packet(pkt);
       return -1;
     }
     f->length = data_size;
     r = ne_io_read(ctx->io, f->data, data_size);
     if (r != 1) {
-      if (f->frame_encryption)
-        free(f->frame_encryption->iv);
-      free(f->frame_encryption);
-      free(f->data);
-      free(f);
+      ne_free_frame(f);
       nestegg_free_packet(pkt);
       return r;
     }
 
     if (!last)
       pkt->frame = f;
     else
       last->next = f;
@@ -1859,70 +1934,70 @@ ne_init_cue_points(nestegg * ctx, int64_
     if (!node)
       return -1;
   }
 
   return 0;
 }
 
 /* Three functions that implement the nestegg_io interface, operating on a
- * sniff_buffer. */
-struct sniff_buffer {
+   io_buffer. */
+struct io_buffer {
   unsigned char const * buffer;
   size_t length;
   int64_t offset;
 };
 
 static int
 ne_buffer_read(void * buffer, size_t length, void * userdata)
 {
-  struct sniff_buffer * sb = userdata;
+  struct io_buffer * iob = userdata;
 
   int rv = 1;
-  size_t available = sb->length - sb->offset;
+  size_t available = iob->length - iob->offset;
 
   if (available < length)
     return 0;
 
-  memcpy(buffer, sb->buffer + sb->offset, length);
-  sb->offset += length;
+  memcpy(buffer, iob->buffer + iob->offset, length);
+  iob->offset += length;
 
   return rv;
 }
 
 static int
 ne_buffer_seek(int64_t offset, int whence, void * userdata)
 {
-  struct sniff_buffer * sb = userdata;
-  int64_t o = sb->offset;
+  struct io_buffer * iob = userdata;
+  int64_t o = iob->offset;
 
   switch(whence) {
   case NESTEGG_SEEK_SET:
     o = offset;
     break;
   case NESTEGG_SEEK_CUR:
     o += offset;
     break;
   case NESTEGG_SEEK_END:
-    o = sb->length + offset;
+    o = iob->length + offset;
     break;
   }
 
-  if (o < 0 || o > (int64_t) sb->length)
+  if (o < 0 || o > (int64_t) iob->length)
     return -1;
 
-  sb->offset = o;
+  iob->offset = o;
   return 0;
 }
 
 static int64_t
 ne_buffer_tell(void * userdata)
 {
-  struct sniff_buffer * sb = userdata;
-  return sb->offset;
+  struct io_buffer * iob = userdata;
+  return iob->offset;
 }
 
 static int
 ne_context_new(nestegg ** context, nestegg_io io, nestegg_log callback)
 {
   nestegg * ctx;
 
   if (!(io.read && io.seek && io.tell))
@@ -2345,71 +2420,77 @@ nestegg_track_codec_data_count(nestegg *
 }
 
 int
 nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item,
                          unsigned char ** data, size_t * length)
 {
   struct track_entry * entry;
   struct ebml_binary codec_private;
-  uint64_t sizes[3], size, total, avail;
-  unsigned char * p;
-  unsigned int count, i;
 
   *data = NULL;
   *length = 0;
-  count = 1;
 
   entry = ne_find_track_entry(ctx, track);
   if (!entry)
     return -1;
 
-  if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
-      && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
+  if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS &&
+      nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
     return -1;
 
   if (ne_get_binary(entry->codec_private, &codec_private) != 0)
     return -1;
 
   if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
-    p = codec_private.data;
-    avail = codec_private.length;
-    if (avail < 1)
-      return -1;
-
-    count = *p++ + 1;
-    avail -= 1;
-
-    if (count > 3 || item >= count)
-      return -1;
+    uint64_t count;
+    uint64_t sizes[3];
+    size_t total;
+    unsigned char * p;
+    unsigned int i;
+    int r;
+
+    nestegg_io io;
+    struct io_buffer userdata;
+    userdata.buffer = codec_private.data;
+    userdata.length = codec_private.length;
+    userdata.offset = 0;
+
+    io.read = ne_buffer_read;
+    io.seek = ne_buffer_seek;
+    io.tell = ne_buffer_tell;
+    io.userdata = &userdata;
 
     total = 0;
-    for (i = 0; i < count - 1; ++i) {
-      size = 0;
-      do {
-        if (avail - total <= size) {
-          return -1;
-        }
-        size += *p;
-        avail -= 1;
-      } while (*p++ == 255);
-      if (avail - total < size)
-        return -1;
-      sizes[i] = size;
-      total += size;
-    }
-    sizes[i] = avail - total;
-
+
+    r = ne_read_uint(&io, &count, 1);
+    if (r != 1)
+      return r;
+    total += 1;
+    count += 1;
+
+    if (count > 3)
+      return -1;
+    r = ne_read_xiph_lacing(&io, codec_private.length, &total, count, sizes);
+    if (r != 1)
+      return r;
+
+    if (item >= count)
+      return -1;
+
+    p = codec_private.data + total;
     for (i = 0; i < item; ++i) {
       p += sizes[i];
     }
+    assert((size_t) (p - codec_private.data) <= codec_private.length &&
+           codec_private.length - (p - codec_private.data) >= sizes[item]);
     *data = p;
     *length = sizes[item];
   } else {
-    if (item >= count)
+    if (item >= 1)
       return -1;
 
     *data = codec_private.data;
     *length = codec_private.length;
   }
 
   return 0;
 }
@@ -2843,22 +2924,18 @@ void
 nestegg_free_packet(nestegg_packet * pkt)
 {
   struct frame * frame;
   struct block_additional * block_additional;
 
   while (pkt->frame) {
     frame = pkt->frame;
     pkt->frame = frame->next;
-    if (frame->frame_encryption) {
-      free(frame->frame_encryption->iv);
-    }
-    free(frame->frame_encryption);
-    free(frame->data);
-    free(frame);
+
+    ne_free_frame(frame);
   }
 
   while (pkt->block_additional) {
     block_additional = pkt->block_additional;
     pkt->block_additional = block_additional->next;
     free(block_additional->data);
     free(block_additional);
   }
@@ -2972,28 +3049,33 @@ nestegg_packet_additional_data(nestegg_p
   return -1;
 }
 
 int
 nestegg_packet_encryption(nestegg_packet * pkt)
 {
   struct frame * f = pkt->frame;
   unsigned char encrypted_bit;
+  unsigned char partitioned_bit;
 
   if (!f->frame_encryption)
     return NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE;
 
   /* Should never have parsed blocks with both encryption and lacing */
   assert(f->next == NULL);
 
   encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK;
+  partitioned_bit = f->frame_encryption->signal_byte & PARTITIONED_BIT_MASK;
 
   if (encrypted_bit != PACKET_ENCRYPTED)
     return NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED;
 
+  if (partitioned_bit == PACKET_PARTITIONED)
+    return NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED;
+
   return NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED;
 }
 
 int
 nestegg_packet_iv(nestegg_packet * pkt, unsigned char const ** iv, size_t * length)
 {
   struct frame * f = pkt->frame;
   unsigned char encrypted_bit;
@@ -3012,27 +3094,56 @@ nestegg_packet_iv(nestegg_packet * pkt, 
     return 0;
 
   *iv = f->frame_encryption->iv;
   *length = f->frame_encryption->length;
   return 0;
 }
 
 int
+nestegg_packet_offsets(nestegg_packet * pkt,
+                       uint32_t const ** partition_offsets,
+                       uint8_t * num_partitions)
+{
+  struct frame * f = pkt->frame;
+  unsigned char encrypted_bit;
+  unsigned char partitioned_bit;
+
+  *partition_offsets = NULL;
+  *num_partitions = 0;
+
+  if (!f->frame_encryption)
+    return -1;
+
+  /* Should never have parsed blocks with both encryption and lacing */
+  assert(f->next == NULL);
+
+  encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK;
+  partitioned_bit = f->frame_encryption->signal_byte & PARTITIONED_BIT_MASK;
+
+  if (encrypted_bit != PACKET_ENCRYPTED || partitioned_bit != PACKET_PARTITIONED)
+    return -1;
+
+  *num_partitions = f->frame_encryption->num_partitions;
+  *partition_offsets = f->frame_encryption->partition_offsets;
+  return 0;
+}
+
+int
 nestegg_has_cues(nestegg * ctx)
 {
   return ctx->segment.cues.cue_point.head ||
     ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
 }
 
 int
 nestegg_sniff(unsigned char const * buffer, size_t length)
 {
   nestegg_io io;
-  struct sniff_buffer userdata;
+  struct io_buffer userdata;
 
   userdata.buffer = buffer;
   userdata.length = length;
   userdata.offset = 0;
 
   io.read = ne_buffer_read;
   io.seek = ne_buffer_seek;
   io.tell = ne_buffer_tell;