/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
*
|
* This file is part of xlslib -- A multiplatform, C/C++ library
|
* for dynamic generation of Excel(TM) files.
|
*
|
* Copyright 2004 Yeico S. A. de C. V. All Rights Reserved.
|
* Copyright 2008-2013 David Hoerl All Rights Reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without modification, are
|
* permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
* conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
* provided with the distribution.
|
*
|
* THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
#include "../xlslib/record.h"
|
#include "../xlslib/datast.h" // XTRACE2() [i_a]
|
#include "../xlslib/rectypes.h"
|
|
// for factory:
|
#include "../xlslib/font.h"
|
#include "../xlslib/format.h"
|
#include "../xlslib/number.h"
|
#include "../xlslib/boolean.h"
|
#include "../xlslib/err.h"
|
#include "../xlslib/note.h"
|
#include "../xlslib/formula_cell.h"
|
#include "../xlslib/merged.h"
|
#include "../xlslib/label.h"
|
#include "../xlslib/index.h"
|
#include "../xlslib/extformat.h"
|
#include "../xlslib/continue.h"
|
#include "../xlslib/colinfo.h"
|
#include "../xlslib/blank.h"
|
#include "../xlslib/recdef.h"
|
#include "../xlslib/HPSF.h"
|
|
#ifdef __BCPLUSPLUS__
|
#include <malloc.h>
|
// malloc.h needed for calloc. RLN 111208
|
// They may be needed for other compilers as well
|
#include <memory.h>
|
// memory.h needed for memset. RLN 111215
|
// These may be needed for other compilers as well.
|
#endif
|
|
using namespace xlslib_strings;
|
|
namespace xlslib_core
|
{
|
/*
|
***********************************
|
* CDataStorage class Implementation
|
***********************************
|
*/
|
|
CDataStorage::CDataStorage() :
|
store(),
|
m_DataSize(0),
|
m_FlushStack(),
|
m_FlushLastEndLevel(0)
|
{
|
store.reserve(300);
|
m_FlushLastEndPos = 0; // .begin();
|
}
|
|
CDataStorage::CDataStorage(size_t blobs) :
|
store(),
|
m_DataSize(0),
|
m_FlushStack(),
|
m_FlushLastEndLevel(0)
|
{
|
store.reserve(blobs);
|
m_FlushLastEndPos = 0; // m_FlushStack.begin();
|
}
|
|
CDataStorage::~CDataStorage()
|
{
|
// Delete all the data. (Only if it exists)
|
// flush all lingering units BEFORE we discard the associated UnitStore entities or we'll get a nasty assertion failure.
|
FlushEm(BACKPATCH_LEVEL_EVERYONE);
|
|
if (!store.empty()) {
|
StoreList_Itor_t x0, x1;
|
size_t cnt = 0;
|
|
x0 = store.begin();
|
x1 = store.end();
|
for(StoreList_Itor_t di = x0; di != x1; ++di) {
|
di->Reset();
|
cnt++;
|
}
|
XTRACE2("ACTUAL: total storage unit count: ", cnt);
|
#if OLE_DEBUG
|
std::cerr << "ACTUAL: total unit count: " << cnt << std::endl;
|
#endif
|
store.resize(0);
|
}
|
}
|
|
void CDataStorage::operator+=(CUnit* from)
|
{
|
/*
|
* constructor already positioned the CUnit; make sure our assumption sticks:
|
*
|
* we assume a usage style like this, i.e. += add in order AND BEFORE the next
|
* unit is requested/constructed:
|
*
|
* p1 = new CUnit(store, ...);
|
* ...
|
* store += p1;
|
* p2 = new CUnit(store, ...);
|
* ...
|
* store += p2;
|
*
|
* and we currently FAIL for any other 'mixed' usage pattern, e.g. this will b0rk:
|
*
|
* p1 = new CUnit(store, ...);
|
* p2 = new CUnit(store, ...);
|
* ...
|
* store += p1;
|
* store += p2;
|
*/
|
XL_ASSERT(from->m_Index == (int)store.size() - 1);
|
|
m_DataSize += from->GetDataSize();
|
|
// and 'persist' the data associated with the CUnit from here-on after...
|
// (that way, we can safely 'delete CUnit' and still have the data generated by the CUnit intact)
|
store[(size_t)from->m_Index].MakeSticky();
|
// and signal that we've made our data 'sticky':
|
XL_ASSERT(from->m_Index >= 0);
|
from->m_Index = -1 ^ from->m_Index;
|
XL_ASSERT(from->m_Index < 0);
|
}
|
|
size_t CDataStorage::GetDataSize() const
|
{
|
return m_DataSize;
|
}
|
|
StoreList_Itor_t CDataStorage::begin()
|
{
|
return store.begin();
|
}
|
|
StoreList_Itor_t CDataStorage::end()
|
{
|
return store.end();
|
}
|
|
signed32_t CDataStorage::RequestIndex(size_t minimum_size)
|
{
|
signed32_t idx = static_cast<signed32_t>(store.size());
|
CUnitStore &unit = *store.insert(store.end(), CUnitStore());
|
|
if (unit.Prepare(minimum_size) != NO_ERRORS) {
|
return INVALID_STORE_INDEX;
|
}
|
|
return idx;
|
}
|
|
CUnitStore& CDataStorage::operator[](signed32_t index)
|
{
|
XL_ASSERT(index != INVALID_STORE_INDEX);
|
XL_ASSERT(index >= 0 ? index < (int)store.size() : 1);
|
XL_ASSERT(index < 0 ? (~index) < (int)store.size() : 1);
|
|
return index >= 0 ? store[(size_t)index] : store[~(size_t)index];
|
}
|
|
// Queue a new unit
|
void CDataStorage::Push(CUnit* unit)
|
{
|
m_FlushStack.push_back(unit);
|
}
|
|
/*
|
* Clip to Max Data Size, as the rest of the record will be placed in continue records.
|
* This means that we will duplicate data. Its possible to create a new UnitStorage that takes just a pointer;
|
* however, these records are quite rare, so why go to the effort.
|
*/
|
size_t CDataStorage::Clip(CUnit* unit)
|
{
|
XL_ASSERT(unit == m_FlushStack.back());
|
CRecord *record = (CRecord *)unit;
|
|
// Use this record, but only record the first big chunk
|
record->SetRecordLength(MAX_RECORD_SIZE);
|
|
// No way to directly change the size of a Unit's storage space, so we fake it by telling the UnitStore that its now smaller
|
CUnitStore& unitStore = (*this)[record->GetIndex()];
|
size_t realSize = unitStore.GetDataSize() - RECORD_HEADER_SIZE;
|
unitStore.SetDataSize( MAX_RECORD_SIZE + RECORD_HEADER_SIZE );
|
|
return realSize;
|
}
|
|
void CDataStorage::FlushEm(unsigned16_t backpatch_level)
|
{
|
/*
|
* delete units which don't need to live any longer.
|
*
|
* In the same loop, we shrink the 'stack' for
|
* future speed and to keep storage requirements in check.
|
*/
|
//printf("FLUSH-EM %d\n", backpatch_level);
|
UnitList_Itor_t start = m_FlushStack.begin();
|
if (m_FlushLastEndLevel == backpatch_level
|
&& backpatch_level != BACKPATCH_LEVEL_EVERYONE // do not use cached position when 'flushing all'
|
//&& m_FlushLastEndPos != m_FlushStack.begin()
|
&& m_FlushLastEndPos != m_FlushStack.size()) { //.end())
|
XL_ASSERT(start != m_FlushStack.end());
|
start = m_FlushStack.begin() + (signed32_t)m_FlushLastEndPos;
|
XL_ASSERT(m_FlushLastEndPos <= m_FlushStack.size());
|
XL_ASSERT(start != m_FlushStack.end());
|
start++;
|
}
|
|
UnitList_Itor_t j = start;
|
size_t cnt = 0;
|
size_t cntleft = 0;
|
for (UnitList_Itor_t i = j; i != m_FlushStack.end(); i++) {
|
CUnit *up = *i;
|
if (up->m_Backpatching_Level <= backpatch_level) {
|
XL_ASSERT(up != NULL);
|
delete up;
|
(*i) = NULL;
|
cnt++;
|
continue;
|
}
|
|
XL_ASSERT(up->m_Backpatching_Level <= 4);
|
|
// do we need to move-copy the unit reference down as part of a shrink operation?
|
if (i != j) {
|
(*j) = up;
|
}
|
j++;
|
cntleft++;
|
}
|
|
size_t count = (size_t)(j - m_FlushStack.begin());
|
|
#if OLE_DEBUG
|
std::cerr << "number of records deleted: " << cnt << ", left: " << cntleft << ", new.size: " << count << std::endl;
|
#endif
|
|
m_FlushStack.resize(count);
|
XL_ASSERT(m_FlushStack.size() == count);
|
|
// remember for the next time around
|
m_FlushLastEndLevel = backpatch_level;
|
j = m_FlushStack.end();
|
if (m_FlushStack.size() > 0) {
|
j--;
|
} else {
|
#if OLE_DEBUG
|
std::cerr << "empty!" << std::endl;
|
#endif
|
}
|
m_FlushLastEndPos = (size_t)(j - m_FlushStack.begin());
|
}
|
|
void CDataStorage::FlushLowerLevelUnits(const CUnit *unit)
|
{
|
if (unit && unit->m_Backpatching_Level > 0) {
|
FlushEm(unit->m_Backpatching_Level - 1);
|
}
|
}
|
|
CUnit* CDataStorage::MakeCUnit()
|
{
|
return new CUnit(*this);
|
}
|
|
CRecord* CDataStorage::MakeCRecord()
|
{
|
return new CRecord(*this);
|
}
|
|
CRow* CDataStorage::MakeCRow(unsigned32_t rownum,
|
unsigned32_t firstcol,
|
unsigned32_t lastcol,
|
unsigned16_t rowheight,
|
const xf_t* xformat)
|
{
|
return new CRow(*this, rownum, firstcol, lastcol, rowheight, xformat);
|
}
|
|
CBof* CDataStorage::MakeCBof(unsigned16_t boftype)
|
{
|
return new CBof(*this, boftype);
|
}
|
|
CEof* CDataStorage::MakeCEof()
|
{
|
return new CEof(*this);
|
}
|
|
CDimension* CDataStorage::MakeCDimension(unsigned32_t minRow,
|
unsigned32_t maxRow,
|
unsigned32_t minCol,
|
unsigned32_t maxCol)
|
{
|
return new CDimension(*this, minRow, maxRow, minCol, maxCol);
|
}
|
|
CWindow1* CDataStorage::MakeCWindow1(const window1& wind1)
|
{
|
return new CWindow1(*this, wind1);
|
}
|
|
CWindow2* CDataStorage::MakeCWindow2(bool isActive)
|
{
|
return new CWindow2(*this, isActive);
|
}
|
|
CDateMode* CDataStorage::MakeCDateMode()
|
{
|
return new CDateMode(*this);
|
}
|
|
CStyle* CDataStorage::MakeCStyle(const style_t* styledef)
|
{
|
return new CStyle(*this, styledef);
|
}
|
|
CBSheet* CDataStorage::MakeCBSheet(const boundsheet_t* bsheetdef)
|
{
|
return new CBSheet(*this, bsheetdef);
|
}
|
|
CFormat* CDataStorage::MakeCFormat(const format_t* formatdef)
|
{
|
return new CFormat(*this, formatdef);
|
}
|
|
CFont* CDataStorage::MakeCFont(const font_t* fontdef)
|
{
|
return new CFont(*this, fontdef);
|
}
|
|
CNumber* CDataStorage::MakeCNumber(const number_t& numdef)
|
{
|
return new CNumber(*this, numdef);
|
}
|
|
CBoolean* CDataStorage::MakeCBoolean(const boolean_t& booldef)
|
{
|
return new CBoolean(*this, booldef);
|
}
|
|
CErr* CDataStorage::MakeCErr(const err_t& errdef)
|
{
|
return new CErr(*this, errdef);
|
}
|
|
CNote* CDataStorage::MakeCNote(const note_t& notedef)
|
{
|
return new CNote(*this, notedef);
|
}
|
|
CFormula* CDataStorage::MakeCFormula(const formula_cell_t& fdef)
|
{
|
return new CFormula(*this, fdef);
|
}
|
|
CMergedCells* CDataStorage::MakeCMergedCells()
|
{
|
return new CMergedCells(*this);
|
}
|
|
CLabel* CDataStorage::MakeCLabel(const label_t& labeldef)
|
{
|
return new CLabel(*this, labeldef);
|
}
|
|
CIndex* CDataStorage::MakeCIndex(unsigned32_t firstrow, unsigned32_t lastrow)
|
{
|
return new CIndex(*this, firstrow, lastrow);
|
}
|
|
CExtFormat* CDataStorage::MakeCExtFormat(const xf_t* xfdef)
|
{
|
return new CExtFormat(*this, xfdef);
|
}
|
|
CContinue* CDataStorage::MakeCContinue(CUnit* unit, const unsigned8_t* data, size_t size)
|
{
|
return new CContinue(unit, data, size);
|
}
|
|
CPalette* CDataStorage::MakeCPalette(const color_entry_t *colors)
|
{
|
return new CPalette(*this, colors);
|
}
|
|
CColInfo* CDataStorage::MakeCColInfo(const colinfo_t* newci)
|
{
|
return new CColInfo(*this, newci);
|
}
|
|
CBlank* CDataStorage::MakeCBlank(const blank_t& blankdef)
|
{
|
return new CBlank(*this, blankdef);
|
}
|
|
CCodePage* CDataStorage::MakeCCodePage(unsigned16_t boftype)
|
{
|
return new CCodePage(*this, boftype);
|
}
|
|
CDBCell* CDataStorage::MakeCDBCell(size_t startblock)
|
{
|
return new CDBCell(*this, startblock);
|
}
|
|
CHPSFdoc* CDataStorage::MakeCHPSFdoc(const hpsf_doc_t &docdef)
|
{
|
return new CHPSFdoc(*this, docdef);
|
}
|
|
CUnit* CDataStorage::MakeCExternBook(unsigned16_t sheet_count) {
|
CRecord *supbook= new CRecord(*this);
|
supbook->Inflate(8);
|
supbook->SetRecordType(RECTYPE_SUPBOOK);
|
supbook->SetRecordLength(4);
|
supbook->AddValue16(sheet_count);
|
supbook->AddValue8(0x01);
|
supbook->AddValue8(0x04);
|
|
return supbook;
|
}
|
|
CUnit* CDataStorage::MakeDrawingGroup(const Boundsheet_Vect_t& bsheets)
|
{
|
CRecord* data = NULL;
|
|
Boundsheet_Vect_CItor_t bsheet_end = bsheets.end();
|
|
unsigned32_t total_notes = 0;
|
unsigned32_t sheets_with_notes = 0;
|
for(Boundsheet_Vect_CItor_t bsheet = bsheets.begin(); bsheet != bsheet_end; ++bsheet) {
|
unsigned32_t count = (*bsheet)->GetNoteCount();
|
if(count) {
|
++sheets_with_notes;
|
total_notes += count;
|
}
|
}
|
|
if(total_notes) {
|
sheet_notes *notes = new sheet_notes[sheets_with_notes];
|
|
unsigned16_t notes_idx = 0;
|
unsigned16_t idx = 0;
|
for(Boundsheet_Vect_CItor_t bsheet = bsheets.begin(); bsheet != bsheet_end; ++bsheet) {
|
unsigned16_t count = (*bsheet)->GetNoteCount();
|
if(count) {
|
sheet_notes tmp = { idx, count };
|
notes[notes_idx] = tmp;
|
++notes_idx;
|
}
|
++idx;
|
}
|
data = new CRecord(*this);
|
CNote::MakeDrawingGroup(data, sheets_with_notes, notes);
|
|
delete[] notes;
|
}
|
|
return data;
|
}
|
|
CUnit* CDataStorage::MakeCExternSheet(const Boundsheet_Vect_t& sheets) {
|
CRecord *externsheet= new CRecord(*this);
|
externsheet->Inflate(4+2+sheets.size()*6);
|
externsheet->SetRecordType(RECTYPE_EXTERNSHEET);
|
externsheet->SetRecordLength(2+sheets.size()*6);
|
externsheet->AddValue16(static_cast<unsigned16_t>(sheets.size()));
|
for (size_t i=0; i<sheets.size(); i++) {
|
externsheet->AddValue16(0);
|
externsheet->AddValue16(static_cast<unsigned16_t>(i));
|
externsheet->AddValue16(static_cast<unsigned16_t>(i));
|
}
|
return externsheet;
|
}
|
|
// Old makeSST, commented out, still in svn before 1/1/2014 (not sure why it was kept around)
|
CUnit* CDataStorage::MakeSST(const Label_Vect_t& labels)
|
{
|
CRecord *record = new CRecord(*this);
|
size_t count = labels.size();
|
record->SetAlreadyContinued(true);
|
|
size_t offset = 0; // offset of last written data
|
|
record->SetRecordTypeIndexed(RECTYPE_SST, 0);
|
record->AddValue32(static_cast<unsigned32_t>(count)); // usages
|
record->AddValue32(static_cast<unsigned32_t>(count)); // number of strings to follow
|
|
size_t currSize = record->GetDataSize();
|
|
cLabel_Vect_Itor_t label_end = labels.end();
|
for(cLabel_Vect_Itor_t label = labels.begin(); label != label_end; ++label) {
|
const label_t *currLabel = *label;
|
u16string str16 = currLabel->GetStrLabel();
|
|
size_t strLen;
|
bool isAscii;
|
size_t strSize = record->UnicodeStringLength(str16, strLen, isAscii, CUnit::LEN2_FLAGS_UNICODE /* = LEN2_FLAGS_UNICODE */ );
|
if(strSize > MAX_RECORD_SIZE) {
|
static const unsigned16_t tooLong[] = { 'L', 'e', 'n', 'g', 't', 'h', ' ', 't', 'o', 'o', ' ', 'l', 'o', 'n', 'g', '!' , 0};
|
str16 = (xchar16_t *)(tooLong); // cannot static_cast or const_cast this expression
|
strSize = record->UnicodeStringLength(str16, strLen, isAscii, CUnit::LEN2_FLAGS_UNICODE /* = LEN2_FLAGS_UNICODE */ );
|
}
|
|
//printf("TEST: (currSize=%ld + strSize=%ld ) offset=%ld\n", currSize, strSize, offset);
|
|
// Payload is always 4 less than currSize, so account for that here
|
if((currSize + strSize) > (MAX_RECORD_SIZE+4)) {
|
record->SetRecordLengthIndexed(currSize-RECORD_HEADER_SIZE, offset);
|
|
offset = record->GetDataSize(); // new offset is where we are now
|
//printf("CHUNK: size=%ld END=%ld\n", currSize, offset);
|
record->AddFixedDataArray(0, 4); // space for header
|
record->SetRecordTypeIndexed(RECTYPE_CONTINUE, offset);
|
}
|
record->AddUnicodeString(str16, CUnit::LEN2_FLAGS_UNICODE);
|
currSize = record->GetDataSize() - offset; // at end so its valid when we break out of the loop
|
//printf("WROTE %ld bytes: total=%ld currBlock=%ld offset=%ld\n", strSize, record->GetDataSize(), currSize, offset);
|
}
|
//totalSize = record->GetDataSize(); // total size of this record
|
//printf("FINAL: cursize=%ld offset=%ld\n", currSize, offset);
|
record->SetRecordLengthIndexed(currSize-RECORD_HEADER_SIZE, offset);
|
|
//printf("TOTAL STRING SIZE: %ld\n", record->GetDataSize());
|
return record;
|
}
|
|
CUnitStore::CUnitStore() :
|
m_varying_width(false),
|
m_is_in_use(false),
|
m_is_sticky(false),
|
m_nDataSize(0)
|
{
|
memset(&s, 0, sizeof(s));
|
XL_ASSERT(s.vary.m_pData == NULL);
|
}
|
|
CUnitStore::~CUnitStore()
|
{
|
Reset();
|
XL_ASSERT(s.vary.m_pData == NULL);
|
}
|
|
/*
|
* This copy constructor is required as otherwise you'd get nuked by CDataStore
|
* when it has to redimension its vector store when more units than
|
* anticipated are requested: internally, STL detroys each unit during this
|
* vector resize operation, so we'll need to copy the data to new space, especially
|
* when we're m_varying_width !!!
|
*/
|
CUnitStore::CUnitStore(const CUnitStore &src)
|
{
|
if (&src == this) {
|
return;
|
}
|
|
m_varying_width = src.m_varying_width;
|
m_is_in_use = src.m_is_in_use;
|
m_is_sticky = src.m_is_sticky;
|
m_nDataSize = src.m_nDataSize;
|
if (!m_varying_width) {
|
XL_ASSERT(m_nDataSize <= FIXEDWIDTH_STORAGEUNIT_SIZE);
|
memcpy(&s, &src.s, sizeof(s));
|
} else {
|
XL_ASSERT(m_is_in_use);
|
XL_ASSERT(src.s.vary.m_nSize > 0);
|
s.vary.m_pData = (unsigned8_t *)malloc(src.s.vary.m_nSize);
|
if (!s.vary.m_pData) {
|
// ret = ERR_UNABLE_TOALLOCATE_MEMORY;
|
m_nDataSize = s.vary.m_nSize = 0;
|
} else {
|
memcpy(s.vary.m_pData, src.s.vary.m_pData, m_nDataSize);
|
s.vary.m_nSize = src.s.vary.m_nSize;
|
}
|
}
|
}
|
|
signed8_t CUnitStore::Prepare(size_t minimum_size)
|
{
|
signed8_t ret = NO_ERRORS;
|
|
// allocate space in the 'variable sized store' if we cannot fit in a fixed-width unit:
|
if (minimum_size <= FIXEDWIDTH_STORAGEUNIT_SIZE) {
|
m_varying_width = false;
|
m_is_in_use = true;
|
m_is_sticky = false;
|
m_nDataSize = 0;
|
memset(&s, 0, sizeof(s));
|
|
// range: 0 ... +oo
|
} else {
|
m_varying_width = true;
|
m_is_in_use = true;
|
m_is_sticky = false;
|
m_nDataSize = 0;
|
memset(&s, 0, sizeof(s));
|
XL_ASSERT(s.vary.m_pData == NULL);
|
if (minimum_size > 0) {
|
s.vary.m_pData = (unsigned8_t *)malloc(minimum_size);
|
if (!s.vary.m_pData) {
|
ret = ERR_UNABLE_TOALLOCATE_MEMORY;
|
minimum_size = 0;
|
}
|
s.vary.m_nSize = minimum_size;
|
}
|
}
|
|
return ret;
|
}
|
|
void CUnitStore::Reset()
|
{
|
if (m_varying_width && s.vary.m_pData) {
|
XL_ASSERT(m_is_in_use);
|
free((void *)s.vary.m_pData);
|
}
|
m_varying_width = false;
|
m_is_in_use = false;
|
m_is_sticky = false;
|
m_nDataSize = 0;
|
memset(&s, 0, sizeof(s));
|
XL_ASSERT(s.vary.m_pData == NULL);
|
}
|
|
signed8_t CUnitStore::Resize(size_t newlen)
|
{
|
signed8_t ret = NO_ERRORS;
|
|
XL_ASSERT(m_is_in_use);
|
XL_ASSERT(newlen > 0);
|
XL_ASSERT(newlen >= m_nDataSize);
|
|
if (!m_varying_width) {
|
if (newlen > FIXEDWIDTH_STORAGEUNIT_SIZE) {
|
// turn this node into a varying-width unit store:
|
unsigned8_t *p = (unsigned8_t *)malloc(newlen);
|
if (!p) {
|
ret = ERR_UNABLE_TOALLOCATE_MEMORY;
|
newlen = 0;
|
} else {
|
memcpy(p, s.fixed.m_pData, m_nDataSize);
|
}
|
s.vary.m_pData = p;
|
s.vary.m_nSize = newlen;
|
m_varying_width = true;
|
}
|
} else {
|
if (newlen != s.vary.m_nSize) {
|
if (!s.vary.m_pData) {
|
XL_ASSERT(m_nDataSize == 0);
|
s.vary.m_pData = (unsigned8_t *)malloc(newlen);
|
} else {
|
s.vary.m_pData = (unsigned8_t *)realloc((void *)s.vary.m_pData, newlen);
|
}
|
if (!s.vary.m_pData) {
|
ret = ERR_UNABLE_TOALLOCATE_MEMORY;
|
newlen = 0;
|
}
|
s.vary.m_nSize = newlen;
|
}
|
}
|
|
return ret;
|
}
|
|
signed8_t CUnitStore::Init(const unsigned8_t *data, size_t size, size_t datasize)
|
{
|
signed8_t ret;
|
|
XL_ASSERT(m_is_in_use);
|
XL_ASSERT(size > 0);
|
XL_ASSERT(datasize <= size);
|
ret = Resize(size);
|
if (ret == NO_ERRORS) {
|
memcpy(GetBuffer(), data, datasize);
|
SetDataSize(datasize);
|
}
|
return ret;
|
}
|
|
signed8_t CUnitStore::InitWithValue(unsigned8_t value, size_t size)
|
{
|
signed8_t ret;
|
|
XL_ASSERT(m_is_in_use);
|
XL_ASSERT(size > 0);
|
ret = Resize(size);
|
if (ret == NO_ERRORS) {
|
memset(GetBuffer(), value, size);
|
SetDataSize(size);
|
}
|
return ret;
|
}
|
}
|