/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifdef __BCPLUSPLUS__ #include // string.h needed for memcpy(). RLN 111215 // This may be applicable to other compilers as well. #endif #include "../xlslib/record.h" #include "../xlslib/unit.h" #include "../xlslib/globalrec.h" #include "../xlslib/rectypes.h" #include "../xlslib/datast.h" using namespace xlslib_core; using namespace xlslib_strings; /* ********************************************************************************* * CUnit class implementation ********************************************************************************* */ // Default constructor CUnit::CUnit(CDataStorage &datastore) : m_Store(datastore), m_Index(INVALID_STORE_INDEX), m_Backpatching_Level(0), m_AlreadyContinued(false) { datastore.Push(this); } CUnit::CUnit(const CUnit& orig) : m_Store(orig.m_Store), m_Index(INVALID_STORE_INDEX), m_Backpatching_Level(0) { XL_ASSERT(m_Index == INVALID_STORE_INDEX); if (orig.m_Index != INVALID_STORE_INDEX) { m_Index = m_Store.RequestIndex(orig.GetDataSize()); if (m_Index != INVALID_STORE_INDEX) { XL_ASSERT(m_Index >= 0); XL_ASSERT(m_Store[m_Index].GetSize() >= orig.GetDataSize()); memcpy(m_Store[m_Index].GetBuffer(), orig.GetBuffer(), orig.GetDataSize()); } else { // TODO: mark error. Should we throw an exception from this constructor? } } } CUnit& CUnit::operator=(const CUnit& right) { if(this == &right) { return *this; } size_t len = right.GetDataSize(); if (m_Index == INVALID_STORE_INDEX && right.m_Index != INVALID_STORE_INDEX) { m_Index = m_Store.RequestIndex(len); if (m_Index == INVALID_STORE_INDEX) { // TODO: mark error. } } else if (right.m_Index != INVALID_STORE_INDEX) { signed8_t ret = m_Store[m_Index].Resize(len); if (ret != NO_ERRORS) { // TODO mark error } XL_ASSERT(ret == NO_ERRORS); } XL_ASSERT(right.m_Index != INVALID_STORE_INDEX && m_Index != INVALID_STORE_INDEX); if (right.m_Index != INVALID_STORE_INDEX && m_Index != INVALID_STORE_INDEX) { XL_ASSERT(m_Store[m_Index].GetSize() >= len); memcpy(m_Store[m_Index].GetBuffer(), right.GetBuffer(), len); m_Store[m_Index].SetDataSize(len); } return *this; } // Default destructor CUnit::~CUnit() { ResetDataStorage(); } void CUnit::ResetDataStorage(void) { if (m_Index != INVALID_STORE_INDEX) { XL_ASSERT(m_Index >= 0 ? !m_Store[m_Index].IsSticky() : 1); XL_ASSERT(m_Index < 0 ? m_Store[m_Index].IsSticky() : 1); if (m_Index >= 0) { m_Store[m_Index].Reset(); } } m_Index = INVALID_STORE_INDEX; } const size_t CUnit::DefaultInflateSize = 10; signed8_t CUnit::SetValueAt8(unsigned8_t newval, unsigned32_t index) { signed8_t errcode = NO_ERRORS; XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); if(data != NULL) { XL_ASSERT(m_Store[m_Index].GetSize() >= datasize); if (index < datasize) { data[index] = newval; } else { errcode = ERR_INVALID_INDEX; } } else { errcode = ERR_DATASTORAGE_EMPTY; } return errcode; } signed8_t CUnit::AddValue16(unsigned16_t newval) { signed8_t errcode = NO_ERRORS; if(AddValue8(BYTE_0(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_1(newval))) { errcode = GENERAL_ERROR; } return errcode; } signed8_t CUnit::AddValue32(unsigned32_t newval) { signed8_t errcode = NO_ERRORS; if(AddValue8(BYTE_0(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_1(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_2(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_3(newval))) { errcode = GENERAL_ERROR; } return errcode; } signed8_t CUnit::AddValue64(unsigned64_t newval) { signed8_t errcode = NO_ERRORS; if(AddValue8(BYTE_0(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_1(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_2(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_3(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_4(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_5(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_6(newval))) { errcode = GENERAL_ERROR; } if(AddValue8(BYTE_7(newval))) { errcode = GENERAL_ERROR; } return errcode; } unsigned64_t CUnit::EncodeFP2I64(double newval) { //#include "common/xls_pshpack1.h" union { double f; unsigned64_t i; unsigned8_t b[8]; } v; //#include "common/xls_poppack.h" XL_ASSERT(sizeof(v.f) == sizeof(v.i)); XL_ASSERT(sizeof(v.f) == sizeof(v.b)); XL_ASSERT(sizeof(v) == sizeof(v.f)); v.f = newval; return v.i; } signed8_t CUnit::AddValue64FP(double newval) { unsigned64_t i = EncodeFP2I64(newval); return AddValue64(i); } signed8_t CUnit::SetValueAt16(unsigned16_t newval, unsigned32_t index) { signed8_t errcode = NO_ERRORS; if(SetValueAt8(BYTE_0(newval), index )) {errcode = GENERAL_ERROR; } if(SetValueAt8(BYTE_1(newval), index+1)) { errcode = GENERAL_ERROR; } return errcode; } signed8_t CUnit::SetValueAt32(unsigned32_t newval, unsigned32_t index) { signed8_t errcode = NO_ERRORS; if(SetValueAt8(BYTE_0(newval), index )) {errcode = GENERAL_ERROR; } if(SetValueAt8(BYTE_1(newval), index+1)) { errcode = GENERAL_ERROR; } if(SetValueAt8(BYTE_2(newval), index+2)) { errcode = GENERAL_ERROR; } if(SetValueAt8(BYTE_3(newval), index+3)) { errcode = GENERAL_ERROR; } return errcode; } signed8_t CUnit::GetValue16From(unsigned16_t* val, unsigned32_t index) const { signed8_t errcode = NO_ERRORS; *val = (unsigned16_t)(operator[](index) + operator[](index+1)*0x0100U); return errcode; } signed8_t CUnit::GetValue32From(unsigned32_t* val, unsigned32_t index) const { signed8_t errcode = NO_ERRORS; // Yikes! this was signed16_t - DFH *val = (unsigned32_t)(operator[](index)*0x00000001U + operator[](index+1)*0x00000100U + operator[](index+2)*0x00010000U + operator[](index+3)*0x01000000U); // Yikes again, it was return errcode; } signed8_t CUnit::GetValue8From(unsigned8_t* dst, unsigned32_t index) const { signed8_t errcode = NO_ERRORS; XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); if(dst != NULL) { XL_ASSERT(m_Store[m_Index].GetSize() >= datasize); if (index < datasize) { *dst = data[index]; } else { errcode = ERR_INVALID_INDEX; } } else { errcode = ERR_DATASTORAGE_EMPTY; } return errcode; } signed8_t CUnit::AddDataArray(const unsigned8_t* newdata, size_t size) { signed8_t errcode = NO_ERRORS; if (m_Index == INVALID_STORE_INDEX) { m_Index = m_Store.RequestIndex(size); if (m_Index == INVALID_STORE_INDEX) { return GENERAL_ERROR; } } XL_ASSERT(GetSize() >= GetDataSize()); size_t spaceleft = GetSize() - GetDataSize(); if(spaceleft < size) { // allocate more space if new to-be-added array won't fit errcode = Inflate(size + GetDataSize()); if (errcode != NO_ERRORS) { return errcode; } } XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); if(newdata != NULL) { // TODO: memmove() (not memcpy() as can be called from Append() <-- this += *this; fringe case where memcpy() would possibly fail! for(size_t i=0; i datasize); data[datasize++] = newdata[i]; } m_Store[m_Index].SetDataSize(datasize); } else { //No data to add. Do nothing if (size != 0) { return GENERAL_ERROR; // [i_a] at least report this very suspicious situation } } return errcode; } signed8_t CUnit::AddFixedDataArray(const unsigned8_t value, size_t size) { signed8_t errcode = NO_ERRORS; if (m_Index == INVALID_STORE_INDEX) { m_Index = m_Store.RequestIndex(size); if (m_Index == INVALID_STORE_INDEX) { return GENERAL_ERROR; } } XL_ASSERT(GetSize() >= GetDataSize()); size_t spaceleft = GetSize() - GetDataSize(); if(spaceleft < size) { // allocate more space if new to-be-added array won't fit errcode = Inflate(size + GetDataSize()); if (errcode != NO_ERRORS) { return errcode; } } XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); // The following can be a memset for(size_t i=0; i datasize); data[datasize++] = value; } m_Store[m_Index].SetDataSize(datasize); return errcode; } // signed8_t AddDataArray (const unsigned16_t* newdata, size_t size); // signed8_t AddFixedDataArray (const unsigned16_t value, size_t size); signed8_t CUnit::SetArrayAt(const unsigned8_t* newdata, size_t size, unsigned32_t index) { signed8_t errcode = NO_ERRORS; size_t space = GetSize(); if(space < size + index) { // allocate more space if new to-be-added array won't fit errcode = Inflate(size + index); if (errcode != NO_ERRORS) { return errcode; } } XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); //size_t datasize = m_Store[m_Index].GetDataSize(); if (newdata != NULL) { for (size_t i=0; i index); data[index++] = newdata[i]; } } return errcode; } signed8_t CUnit::AddValue8(unsigned8_t newdata) { XL_ASSERT(GetSize() >= GetDataSize()); if(GetDataSize() >= GetSize()) { signed8_t errcode = Inflate(GetDataSize() + 1); if (errcode != NO_ERRORS) { return errcode; } } XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); data[datasize++] = newdata; m_Store[m_Index].SetDataSize(datasize); return NO_ERRORS; } signed8_t CUnit::AddUnicodeString(CGlobalRecords& gRecords, const std::string& str, XlsUnicodeStringFormat_t fmt) { std::string::const_iterator cBegin, cEnd; signed8_t errcode = NO_ERRORS; size_t strSize = 0; size_t strLen; size_t spaceleft; bool isASCII = CGlobalRecords::IsASCII(str); if (!isASCII) { u16string s16; XL_ASSERTS("Should never happen!"); gRecords.char2str16(str, s16); return AddUnicodeString(s16, fmt); } strLen = str.length(); switch (fmt) { case LEN2_FLAGS_UNICODE: // RECTYPE_FORMAT, RECTYPE_LABEL -- 'regular' strSize = 2; strSize += 1; // flags byte break; case LEN1_FLAGS_UNICODE: // RECTYPE_BOUNDSHEET strSize = 1; strSize += 1; // flags byte break; case NOLEN_FLAGS_UNICODE: // RECTYPE_NAME strSize = 0; strSize += 1; // flags byte break; default: XL_ASSERTS("should never go here!"); break; } strSize += strLen; XL_ASSERT(GetSize() >= GetDataSize()); spaceleft = GetSize() - GetDataSize(); if(spaceleft < strSize) { // allocate more space if new to-be-added array won't fit errcode = Inflate(strSize + GetDataSize()); if (errcode != NO_ERRORS) { return errcode; } } XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); XL_ASSERT(data); //XL_ASSERT(datasize > strSize); switch (fmt) { case LEN2_FLAGS_UNICODE: // RECTYPE_FORMAT, RECTYPE_LABEL -- 'regular' XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = strLen & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (strLen >> 8) & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = 0x00; // ASCII break; case LEN1_FLAGS_UNICODE: // RECTYPE_BOUNDSHEET XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = strLen & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = 0x00; // ASCII break; case NOLEN_FLAGS_UNICODE: // RECTYPE_NAME XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = 0x00; // ASCII break; default: XL_ASSERTS("should never go here!"); break; } cBegin = str.begin(); cEnd = str.end(); while(cBegin != cEnd) { XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (unsigned8_t)*cBegin++; } m_Store[m_Index].SetDataSize(datasize); return errcode; } signed8_t CUnit::AddUnicodeString(const u16string& str16, XlsUnicodeStringFormat_t fmt) { u16string::const_iterator cBegin, cEnd; signed8_t errcode = NO_ERRORS; size_t spaceleft; size_t strLen; bool isASCII; size_t strSize = UnicodeStringLength(str16, strLen, isASCII, fmt /* = LEN2_FLAGS_UNICODE */ ); XL_ASSERT(GetSize() >= GetDataSize()); spaceleft = GetSize() - GetDataSize(); if(spaceleft < strSize) { // allocate more space if new to-be-added array won't fit errcode = Inflate(strSize + GetDataSize()); if (errcode != NO_ERRORS) { return errcode; } } XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); size_t datasize = m_Store[m_Index].GetDataSize(); XL_ASSERT(data); //XL_ASSERT(datasize > strSize); switch (fmt) { case LEN2_FLAGS_UNICODE: // RECTYPE_FORMAT, RECTYPE_LABEL -- 'regular' XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = strLen & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (strLen >> 8) & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (isASCII ? 0x00 : 0x01); // ASCII or UTF-16 break; case LEN1_FLAGS_UNICODE: // RECTYPE_BOUNDSHEET XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = strLen & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (isASCII ? 0x00 : 0x01); // ASCII or UTF-16 break; case NOLEN_FLAGS_UNICODE: // RECTYPE_NAME XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (isASCII ? 0x00 : 0x01); // ASCII or UTF-16 break; default: XL_ASSERTS("should never go here!"); break; } cBegin = str16.begin(); cEnd = str16.end(); if (isASCII) { while(cBegin != cEnd) { unsigned16_t c = *cBegin++; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = static_cast(c); } } else { while(cBegin != cEnd) { unsigned16_t c = *cBegin++; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = c & 0xFF; XL_ASSERT(m_Store[m_Index].GetSize() > datasize); data[datasize++] = (c >> 8) & 0xFF; } } m_Store[m_Index].SetDataSize(datasize); return errcode; } size_t CUnit::UnicodeStringLength(const u16string& str16, size_t& strLen, bool& isASCII, XlsUnicodeStringFormat_t fmt /* = LEN2_FLAGS_UNICODE */ ) { strLen = str16.length(); isASCII = CGlobalRecords::IsASCII(str16); size_t strSize = strLen; switch (fmt) { case LEN2_FLAGS_UNICODE: // RECTYPE_FORMAT, RECTYPE_LABEL -- 'regular' strSize += 2; strSize += 1; // flags byte if (!isASCII) { strSize += strLen; // UTF16 takes 2 bytes per char } break; case LEN1_FLAGS_UNICODE: // RECTYPE_BOUNDSHEET strSize += 1; strSize += 1; // flags byte if (!isASCII) { strSize += strLen; // UTF16 takes 2 bytes per char } break; case NOLEN_FLAGS_UNICODE: // RECTYPE_NAME //strSize = 0; strSize += 1; // flags byte if (!isASCII) { strSize += strLen; // UTF16 takes 2 bytes per char } break; default: XL_ASSERTS("should never go here!"); break; } return strSize; } signed8_t CUnit::Inflate(size_t newsize) { signed8_t errcode = NO_ERRORS; if (m_Index == INVALID_STORE_INDEX) { XL_ASSERT(newsize > 0); m_Index = m_Store.RequestIndex(newsize); if (m_Index == INVALID_STORE_INDEX) { return GENERAL_ERROR; } } else { XL_ASSERT(newsize > 0); #if 0 { size_t oldlen = m_Store[m_Index].GetSize(); if (oldlen < 64) { increase = CUnit::DefaultInflateSize; } else { // bigger units grow faster: save on the number of realloc redimension operations... increase = oldlen / 2; } } #endif XL_ASSERT(m_Index != INVALID_STORE_INDEX); errcode = m_Store[m_Index].Resize(newsize); } return errcode; } unsigned8_t& CUnit::operator[](const size_t index) const { XL_ASSERT(m_Index != INVALID_STORE_INDEX); unsigned8_t *data = m_Store[m_Index].GetBuffer(); //size_t datasize = m_Store[m_Index].GetDataSize(); XL_ASSERT(index < GetSize()); // DFH: need to read ahead when setting bits in 32bit words XL_ASSERT(index < GetDataSize()); // [i_a] //if(index >= datasize) printf("ERROR: Short read!! \n"); return data[index]; } CUnit& CUnit::operator +=(const CUnit& from) { XL_VERIFY(NO_ERRORS == Append(from)); return *this; } CUnit& CUnit::operator +=(unsigned8_t from) { XL_VERIFY(NO_ERRORS == AddValue8(from)); return *this; } signed8_t CUnit::Init(const unsigned8_t* data, const size_t size, const unsigned32_t datasz) { XL_ASSERT(m_Index != INVALID_STORE_INDEX); signed8_t ret = m_Store[m_Index].Init(data, size, datasz); return ret; } signed8_t CUnit::Append(const CUnit& newunit) { XL_ASSERT(GetSize() >= GetDataSize()); size_t spaceleft = GetSize() - GetDataSize(); if(spaceleft < newunit.GetDataSize()) { // allocate more space if new to-be-added array won't fit signed8_t errcode = Inflate(GetDataSize() + newunit.GetDataSize()); if (errcode != NO_ERRORS) { return errcode; } } return AddDataArray(newunit.GetBuffer(), newunit.GetDataSize()); } signed8_t CUnit::InitFill(unsigned8_t data, size_t size) { XL_ASSERT(m_Index != INVALID_STORE_INDEX); return m_Store[m_Index].InitWithValue(data, size); } size_t CUnit::GetSize(void) const { XL_ASSERT(m_Index != INVALID_STORE_INDEX); return m_Store[m_Index].GetSize(); } size_t CUnit::GetDataSize(void) const { XL_ASSERT(m_Index != INVALID_STORE_INDEX); return m_Store[m_Index].GetDataSize(); } const unsigned8_t* CUnit::GetBuffer(void) const { XL_ASSERT(m_Index != INVALID_STORE_INDEX); return m_Store[m_Index].GetBuffer(); }