[stream] Add quad-word support and stream_resize

2006-01-10 Paul Jakma <paul.jakma@sun.com>

	* stream.c: (stream_new) Allocate stream data as seperate object.
	  (stream_free) free the data.
	  (stream_resize) new function, resize stream to new size.
	  (stream_{get,put}q*) new functions to get/put quad word size
	  types.
	* stream.h: (struct stream) make data seperate from the stream.
	  Export new stream_resize and quad-word get/put functions.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index b02cc51..da0bc4a 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,13 @@
+2006-01-10 Paul Jakma <paul.jakma@sun.com>
+
+	* stream.c: (stream_new) Allocate stream data as seperate object.
+	  (stream_free) free the data.
+	  (stream_resize) new function, resize stream to new size.
+	  (stream_{get,put}q*) new functions to get/put quad word size
+	  types.
+	* stream.h: (struct stream) make data seperate from the stream.
+	  Export new stream_resize and quad-word get/put functions.
+	  
 2005-12-29  Greg Troxel  <gdt@fnord.ir.bbn.com>
 
 	* vty.c (vty_hello): add cast to quiet lint (from David Young)
diff --git a/lib/stream.c b/lib/stream.c
index d8c1088..4c5c44a 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -99,11 +99,17 @@
       return NULL;
     }
   
-  s = XCALLOC (MTYPE_STREAM, offsetof(struct stream, data[size]));
+  s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
 
   if (s == NULL)
     return s;
   
+  if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL)
+    {
+      XFREE (MTYPE_STREAM, s);
+      return NULL;
+    }
+  
   s->size = size;
   return s;
 }
@@ -112,6 +118,10 @@
 void
 stream_free (struct stream *s)
 {
+  if (!s)
+    return;
+  
+  XFREE (MTYPE_STREAM_DATA, s->data);
   XFREE (MTYPE_STREAM, s);
 }
 
@@ -143,6 +153,30 @@
 
   return (stream_copy (new, s));
 }
+
+size_t
+stream_resize (struct stream *s, size_t newsize)
+{
+  u_char *newdata;
+  STREAM_VERIFY_SANE (s);
+  
+  newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize);
+  
+  if (newdata == NULL)
+    return s->size;
+  
+  s->data = newdata;
+  s->size = newsize;
+  
+  if (s->endp > s->size)
+    s->endp = s->size;
+  if (s->getp > s->endp)
+    s->getp = s->endp;
+  
+  STREAM_VERIFY_SANE (s);
+  
+  return s->size;
+}
 
 size_t
 stream_get_getp (struct stream *s)
@@ -344,6 +378,58 @@
   
   return l;
 }
+
+/* Get next quad word from the stream. */
+uint64_t
+stream_getq_from (struct stream *s, size_t from)
+{
+  u_int64_t q;
+
+  STREAM_VERIFY_SANE(s);
+  
+  if (!GETP_VALID (s, from + sizeof (uint64_t)))
+    {
+      STREAM_BOUND_WARN (s, "get quad");
+      return 0;
+    }
+  
+  q  = ((uint64_t) s->data[from++]) << 56;
+  q |= ((uint64_t) s->data[from++]) << 48;
+  q |= ((uint64_t) s->data[from++]) << 40;
+  q |= ((uint64_t) s->data[from++]) << 32;  
+  q |= ((uint64_t) s->data[from++]) << 24;
+  q |= ((uint64_t) s->data[from++]) << 16;
+  q |= ((uint64_t) s->data[from++]) << 8;
+  q |= ((uint64_t) s->data[from++]);
+  
+  return q;
+}
+
+uint64_t
+stream_getq (struct stream *s)
+{
+  uint64_t q;
+
+  STREAM_VERIFY_SANE(s);
+  
+  if (STREAM_READABLE (s) < sizeof (uint64_t))
+    {
+      STREAM_BOUND_WARN (s, "get quad");
+      return 0;
+    }
+  
+  q  = ((uint64_t) s->data[s->getp++]) << 56;
+  q |= ((uint64_t) s->data[s->getp++]) << 48;
+  q |= ((uint64_t) s->data[s->getp++]) << 40;
+  q |= ((uint64_t) s->data[s->getp++]) << 32;  
+  q |= ((uint64_t) s->data[s->getp++]) << 24;
+  q |= ((uint64_t) s->data[s->getp++]) << 16;
+  q |= ((uint64_t) s->data[s->getp++]) << 8;
+  q |= ((uint64_t) s->data[s->getp++]);
+  
+  return q;
+}
+
 /* Get next long word from the stream. */
 u_int32_t
 stream_get_ipv4 (struct stream *s)
@@ -448,6 +534,30 @@
   return 4;
 }
 
+/* Put quad word to the stream. */
+int
+stream_putq (struct stream *s, uint64_t q)
+{
+  STREAM_VERIFY_SANE (s);
+
+  if (STREAM_WRITEABLE (s) < sizeof (uint64_t))
+    {
+      STREAM_BOUND_WARN (s, "put quad");
+      return 0;
+    }
+  
+  s->data[s->endp++] = (u_char)(q >> 56);
+  s->data[s->endp++] = (u_char)(q >> 48);
+  s->data[s->endp++] = (u_char)(q >> 40);
+  s->data[s->endp++] = (u_char)(q >> 32);
+  s->data[s->endp++] = (u_char)(q >> 24);
+  s->data[s->endp++] = (u_char)(q >> 16);
+  s->data[s->endp++] = (u_char)(q >>  8);
+  s->data[s->endp++] = (u_char)q;
+
+  return 8;
+}
+
 int
 stream_putc_at (struct stream *s, size_t putp, u_char c)
 {
@@ -499,6 +609,28 @@
   return 4;
 }
 
+int
+stream_putq_at (struct stream *s, size_t putp, uint64_t q)
+{
+  STREAM_VERIFY_SANE(s);
+  
+  if (!PUT_AT_VALID (s, putp + sizeof (uint64_t)))
+    {
+      STREAM_BOUND_WARN (s, "put");
+      return 0;
+    }
+  s->data[putp] =     (u_char)(q >> 56);
+  s->data[putp + 1] = (u_char)(q >> 48);
+  s->data[putp + 2] = (u_char)(q >> 40);
+  s->data[putp + 3] = (u_char)(q >> 32);
+  s->data[putp + 4] = (u_char)(q >> 24);
+  s->data[putp + 5] = (u_char)(q >> 16);
+  s->data[putp + 6] = (u_char)(q >>  8);
+  s->data[putp + 7] = (u_char)q;
+  
+  return 8;
+}
+
 /* Put long word to the stream. */
 int
 stream_put_ipv4 (struct stream *s, u_int32_t l)
diff --git a/lib/stream.h b/lib/stream.h
index 564fa3c..d2d2e40 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -103,7 +103,7 @@
   size_t getp; 		/* next get position */
   size_t endp;		/* last valid data position */
   size_t size;		/* size of data segment */
-  unsigned char data[]; /* data pointer */
+  unsigned char *data; /* data pointer */
 };
 
 /* First in first out queue structure. */
@@ -127,12 +127,19 @@
 #define STREAM_DATA(S)  ((S)->data)
 #define STREAM_REMAIN(S) STREAM_WRITEABLE((S))
 
-/* Stream prototypes. */
+/* Stream prototypes. 
+ * For stream_{put,get}S, the S suffix mean:
+ *
+ * c: character (unsigned byte)
+ * w: word (two bytes)
+ * l: long (two words)
+ * q: quad (four words)
+ */
 extern struct stream *stream_new (size_t);
 extern void stream_free (struct stream *);
 extern struct stream * stream_copy (struct stream *new, struct stream *src);
 extern struct stream *stream_dup (struct stream *);
-
+extern size_t stream_resize (struct stream *, size_t);
 extern size_t stream_get_getp (struct stream *);
 extern size_t stream_get_endp (struct stream *);
 extern size_t stream_get_size (struct stream *);
@@ -150,6 +157,8 @@
 extern int stream_putw_at (struct stream *, size_t, u_int16_t);
 extern int stream_putl (struct stream *, u_int32_t);
 extern int stream_putl_at (struct stream *, size_t, u_int32_t);
+extern int stream_putq (struct stream *, uint64_t);
+extern int stream_putq_at (struct stream *, size_t, uint64_t);
 extern int stream_put_ipv4 (struct stream *, u_int32_t);
 extern int stream_put_in_addr (struct stream *, struct in_addr *);
 extern int stream_put_prefix (struct stream *, struct prefix *);
@@ -161,6 +170,8 @@
 extern u_int16_t stream_getw_from (struct stream *, size_t);
 extern u_int32_t stream_getl (struct stream *);
 extern u_int32_t stream_getl_from (struct stream *, size_t);
+extern uint64_t stream_getq (struct stream *);
+extern uint64_t stream_getq_from (struct stream *, size_t);
 extern u_int32_t stream_get_ipv4 (struct stream *);
 
 #undef stream_read