Simple data buffer splitter and re-assembler.
SplitterAssembler.cpp
- Committer:
- ansond
- Date:
- 2015-02-18
- Revision:
- 6:094ed29a8bf7
- Parent:
- 4:221c8a56a80e
- Child:
- 7:6baecc15cb26
File content as of revision 6:094ed29a8bf7:
/** * @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"); }