Simple data buffer splitter and re-assembler.

SplitterAssembler.cpp

Committer:
ansond
Date:
2015-07-25
Revision:
8:bfa5b7b9b886
Parent:
7:6baecc15cb26

File content as of revision 8:bfa5b7b9b886:

/**
 * @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) 
 {
     for(int i=0;i<MAX_FRAGMENTS;++i) memset(this->m_fragments[i],0,DEF_FRAGMENT_LENGTH+1);
     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) {
         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
 int SplitterAssembler::assemble(uint8_t *buffer,int buffer_length,bool reset_after_assemble)
 {
     // DEBUG
     //this->dump();
     
     // 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);
         
         // if desired, we re-set after we assemble
         if (reset_after_assemble) this->reset();
     }
     else {
         // unable to assemble... 
         length = -1;
         DBG("ERROR: Unable to assemble. calculateAssemblyLength() failed (length=%d)\r\n",length);
     }
     
     // return our length
     return 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 this->m_last_fragment_length += strlen((char *)this->m_fragments[i]);
     }
     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;
 }
 
 // see if any of the collected fragments contains a special character
 bool SplitterAssembler::hasCollectedCharacter(char special_char)
 {
     int found = false;
     
     for(int i=0;i<this->m_num_fragments && !found;++i) {
         char *fragment = (char *)this->m_fragments[i];
         int fragment_length = strlen(fragment);
         for(int j=0;j<fragment_length && !found;++j) {
             if (fragment[j] == special_char) 
                found = true;
         }
     }
     
     return found;
 }
 
 // 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");
 }