Simple data buffer splitter and re-assembler.

Revision:
1:9f05dbd1c2c7
Parent:
0:12a931a6161c
Child:
3:00f7a99862a3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SplitterAssembler.cpp	Thu Feb 12 20:06:15 2015 +0000
@@ -0,0 +1,217 @@
+/**
+ * @file    SplitterAssembler.cpp
+ * @brief   data buffer splitter and assembler implementation
+ * @author  Doug Anson
+ * @version 1.0
+ * @see     
+ *
+ * Copyright (c) 2014
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+ #include "SplitterAssembler.h"
+ 
+// we have to redefine DBG as its used differently here...
+#ifdef DBG
+    #undef DBG
+#endif
+#define DBG  printf
+ 
+ // constructor
+ SplitterAssembler::SplitterAssembler() 
+ { 
+    this->reset();  
+ }
+ 
+ // fragment a buffer 
+ int SplitterAssembler::split(uint8_t *data,int data_length) 
+ {
+     // reset
+     this->reset();
+     
+     // get our number of fragments
+     this->m_num_fragments = this->calculateNumFragments(data,data_length);
+     
+     // DEBUG
+     //DBG("fragment() num_fragments=%d data_length=%d\r\n",this->m_num_fragments,data_length);
+     
+     // make sure we have a positive number...
+     if (this->m_num_fragments > 0) {
+         // check for the simple case first
+         if (this->m_num_fragments == 1) {
+             // simple case... just 1 fragment
+             memcpy(this->m_fragments[0],data,data_length);
+             this->m_last_fragment_length = data_length;
+         }
+         else {
+             // must iterate over the buffer and fragment...
+             for(int i=0;i<this->m_num_fragments;++i) {
+                 int offset = i*DEF_FRAGMENT_LENGTH;
+                 if (i < (this->m_num_fragments-1)) {
+                     // interior... will always be fixed length
+                     memcpy(this->m_fragments[i],(data + offset),DEF_FRAGMENT_LENGTH);
+                 }
+                 else {
+                     // trailing... may be partial length...
+                     this->m_last_fragment_length = data_length - offset;
+                     memcpy(this->m_fragments[i],(data + offset),this->m_last_fragment_length);
+                 }
+             }
+         }
+     }
+     else {
+         // unable to fragment... invalid parameters
+         DBG("ERROR: invalid parameters in fragment()\r\n");
+     }
+     
+     // DEBUG
+     this->dump();
+     
+     // return our number of fragments
+     return this->m_num_fragments;
+ }
+ 
+ // calculate the number of fragments
+ int SplitterAssembler::calculateNumFragments(uint8_t *data,int data_length) 
+ {
+     int num_fragments = 0;
+     
+     // param checking
+     if (data != NULL && data_length > 0) {
+         // check for simple case... 
+         if (data_length <= DEF_FRAGMENT_LENGTH) {
+             num_fragments = 1;
+         }
+         else {
+             num_fragments = 1;
+             data_length -= DEF_FRAGMENT_LENGTH;
+             while(data_length > 0) {
+                ++num_fragments;
+                data_length -= DEF_FRAGMENT_LENGTH;
+             }
+         }   
+     }
+     else {
+         // invalid parameters
+         DBG("ERROR: invalid parameters in calculateNumFragments() data_length=%d\r\n",data_length);
+     }
+     
+     return num_fragments;
+ }
+ 
+ // get the ith fragment
+ uint8_t *SplitterAssembler::get(int index)
+ {
+     if (index >= 0 && index < this->m_num_fragments) 
+        return this->m_fragments[index];
+    return NULL;
+ }
+ 
+ // reset the Fragmenter/Assembler
+ void SplitterAssembler::reset(void) 
+ {
+     memset(this->m_fragments,0,sizeof(this->m_fragments));
+     this->m_num_fragments = 0;
+     this->m_last_fragment_length = 0;
+ }
+ 
+ // add a fragment to assemble later
+ int SplitterAssembler::add(uint8_t *fragment,int fragment_length)
+ {
+     if (this->m_num_fragments < (MAX_FRAGMENTS-1)) {
+         int length = fragment_length;
+         if (length > DEF_FRAGMENT_LENGTH) {
+             length = DEF_FRAGMENT_LENGTH;
+             //DBG("WARNING: Truncating input fragment in add() fragment_length=%d\r\n",fragment_length);
+         }
+         memcpy(this->m_fragments[this->m_num_fragments],fragment,length);
+         ++this->m_num_fragments;
+     }
+     else {
+         // not enough memory to hold all the fragments
+         DBG("ERROR: Maximum number of fragments permissible reached, Please increase MAX_FRAGMENTS...\r\n");
+     }
+     return this->m_num_fragments;
+ }
+ 
+ // assemble all input fragments
+ void SplitterAssembler::assemble(uint8_t *buffer,int buffer_length,bool reset_after_assemble)
+ {
+     // calculate the final assembly length
+     int length = this->calculateAssemblyLength(buffer_length);
+     if (length > 0) {   
+         // initialize the return buffer
+         memset(buffer,0,buffer_length);
+         
+         // check for the simple case.. 1 fragment
+         if (this->m_num_fragments == 1) {
+            // simple case detected... just copy over
+            memset(buffer,0,buffer_length);
+            memcpy(buffer,this->m_fragments[0],length);
+         }
+         else {
+             // we have to loop and copy/append
+             for(int i=0;i<this->m_num_fragments;++i) {
+                 int offset = (i*DEF_FRAGMENT_LENGTH);
+                 if (i < (this->m_num_fragments-1)) {
+                     // interior... will always be fixed length
+                     memcpy((buffer+offset),this->m_fragments[i],DEF_FRAGMENT_LENGTH);
+                 }
+                 else {
+                     // trailing... may be partial length...
+                     memcpy((buffer+offset),this->m_fragments[i],this->m_last_fragment_length);
+                 }
+             }
+         }
+         
+         // DEBUG
+         //DBG("assemble(): buffer=[%s] length=%d\r\n",buffer,buffer_length);
+     }
+     else {
+         // unable to assemble... 
+         DBG("ERROR: Unable to assemble. calculateAssemblyLength() failed (%d)\r\n",length);
+     }
+ }
+ 
+ // calculate the assembled packet length
+ int SplitterAssembler::calculateAssemblyLength(int buffer_length) {
+     int length = 0;
+     
+     for(int i=0;i<this->m_num_fragments;++i) {
+        if (i < (this->m_num_fragments-1)) length += DEF_FRAGMENT_LENGTH;
+        else length += this->m_last_fragment_length;
+     }
+     
+     // sanity check
+     if (length > buffer_length) {
+         // input buffer is too small...
+         DBG("ERROR: calculateAssemblyLength() input buffer too small: %d bytes. required length: %d bytes.\r\n",buffer_length,length);
+         length = -1;
+     }
+     
+     return length;
+ }
+ 
+ // dump the state of the Fragmenter/Assembler
+ void SplitterAssembler::dump(void)
+ {
+     DBG("\r\nDUMP: Number of fragments: %d last_length=%d\r\n",this->m_num_fragments,this->m_last_fragment_length);
+     for(int i=0;i<this->m_num_fragments;++i) {
+         DBG("DUMP:    Fragment[%d]=[%s] length=%d\r\n",i,this->get(i),strlen((const char *)this->get(i)));
+     }
+     DBG("\r\n");
+ }
+ 
+ 
+ 
\ No newline at end of file