tfussell / xlnt

:bar_chart: Cross-platform user-friendly xlsx library for C++11+
Other
1.49k stars 418 forks source link

problem to fill a cell #453

Closed sukoi26 closed 3 years ago

sukoi26 commented 4 years ago

I had no problem with this attached example, but now I have a segfault

the test : the program compares a chain and fills the cell in the adjacent if equal column.

#include <xlnt/xlnt.hpp>
#include <numeric>
#include <iostream>
#include <string>
#include <fstream>
#include <random>
#include <chrono>

// main entry
int main()
{

    // get file to random
    std::string filein;
    std::cout << "Please enter a file name to random without (.xlsx): ";
    getline( std::cin, filein );
    filein = filein+".xlsx";
    // test file exist
    std::ifstream fin(filein, std::ios::in);
    if (fin) fin.close();
    else
    {
        std::cerr << "!!! File cannot be opened !!!\n";
        return -1;
    }

    //new workbook
    xlnt::workbook wb;
    wb.load(filein);

     // new sheet
    auto ws1 = wb.active_sheet();
    ws1.title("SetColour");

    auto filly = xlnt::fill::solid(xlnt::color::yellow());
    auto fillg = xlnt::fill::solid(xlnt::color::green());
    auto fillr = xlnt::fill::solid(xlnt::color::red());
    auto fillb = xlnt::fill::solid(xlnt::color::blue());

     // filling
    std::cout << "test colour ...\n";

    // value to check  i column value
    int i = 2 ;
    std::string a = "AA" ;
    std::string b = "BB" ;
    std::string c = "CC" ;
    std::string d = "DD" ;

    for(int j=2; j<101; j++)
    {
        auto cellij = ws1.cell(xlnt::cell_reference(i,j));
        auto r = cellij.value<std::string>();

        if(r == a)
            ws1.cell(3,j).fill(fillg);
        //true;
        else if(r == b)
            ws1.cell(3,j).fill(fillr);
        //true;
        else if(r==c)
            ws1.cell(3,j).fill(fillb);

    }

    // rad a cell
    ws1.cell(3,101).value("NOCOLOR");

     //  save a copy file
    std::string fileout = "COPY_"+filein;
    std::cout << "write : "<< fileout << std::endl;
    wb.save(fileout);

    // exit
    return 0;
}

behavior observed: the first row is ok, at the second for fillr, a segfault on the function format_impl * find_or_create_with (format_impl * pattern, const fill & new_fill, optional <bool> applied)

some code to change

the file BATSV4.xlsx

GDB (linux)

(gdb) bt
#0  std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<double const, xlnt::color>, false> > >::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<double const, xlnt::color>, false> > > (
    this=0x555555835888, __a=...)
    at /usr/include/c++/9/bits/hashtable_policy.h:2042
#1  0x0000555555585816 in std::_Hashtable<double, std::pair<double const, xlnt::color>, std::allocator<std::pair<double const, xlnt::color> >, std::__detail::_Select1st, std::equal_to<double>, std::hash<double>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::_Hashtable (
    this=0x555555835888, __ht=...) at /usr/include/c++/9/bits/hashtable.h:1239
#2  0x0000555555585521 in std::unordered_map<double, xlnt::color, std::hash<double>, std::equal_to<double>, std::allocator<std::pair<double const, xlnt::color> > >::unordered_map (this=0x555555835888)
    at /usr/include/c++/9/bits/unordered_map.h:181
#3  0x000055555558560b in xlnt::gradient_fill::gradient_fill (
    this=0x555555835858)
    at /dvp/xlnt/source/../include/xlnt/styles/fill.hpp:142
#4  0x000055555558b483 in xlnt::fill::fill (this=0x555555835850)
    at /dvp/xlnt/source/../include/xlnt/styles/fill.hpp:298
#5  0x00005555555963f9 in __gnu_cxx::new_allocator<xlnt::fi--Type <RET> for more, q to quit, c to continue without paging--ll>::construct<xlnt::fill, xlnt::fill const&> (this=0x55555582ba40, __p=0x555555835850)
    at /usr/include/c++/9/ext/new_allocator.h:147
#6  0x0000555555593369 in std::allocator_traits<std::allocator<xlnt::fill> >::construct<xlnt::fill, xlnt::fill const&> (__a=..., __p=0x555555835850)
    at /usr/include/c++/9/bits/alloc_traits.h:484
#7  0x0000555555593734 in std::vector<xlnt::fill, std::allocator<xlnt::fill> >::_M_realloc_insert<xlnt::fill const&> (this=0x55555582ba40, 
    __position=non-dereferenceable iterator for std::vector)
    at /usr/include/c++/9/bits/vector.tcc:449
#8  0x00005555555d7263 in std::vector<xlnt::fill, std::allocator<xlnt::fill> >::push_back (this=0x55555582ba40, __x=...)
    at /usr/include/c++/9/bits/stl_vector.h:1195
#9  0x00005555555bfdc5 in xlnt::workbook::empty ()
    at /dvp/xlnt/source/workbook/workbook.cpp:463
#10 0x00005555555c08fd in xlnt::workbook::workbook (this=0x7fffffffda08)
    at /dvp/xlnt/source/workbook/workbook.cpp:499
#11 0x000055555555efae in main () at /dvp/xtest/xtest/main.cpp:29
sukoi26 commented 4 years ago

question about this code in consummer.cpp

expect_start_element(qn("spreadsheetml", "xf"), xml::content::complex);

                auto &record = *(!in_style_records
                        ? format_records.emplace(format_records.end())
                        : style_records.emplace(style_records.end()));

v.emplace(v.end()) does it copy of the last record ? value initialization?

sukoi26 commented 4 years ago

i come back on this issue ,segfault disappear if i change the flag "garbage_collection_enabled" to false. I change the test file like below image the result image the fill is applied on cell not requested AA = green BB= red CC=blue as you see. i check2 the origin file image result i have 5 fills OK image I check2 the origin xfs

<cellXfs count="5">
<xf numFmtId="164" fontId="0" fillId="0" borderId="0" xfId="0" applyFont="false" applyBorder="false" applyAlignment="false" applyProtection="false">
<alignment horizontal="general" vertical="bottom" textRotation="0" wrapText="false" indent="0" shrinkToFit="false"/>
<protection locked="true" hidden="false"/>
</xf>
<xf numFmtId="164" fontId="4" fillId="0" borderId="1" xfId="0" applyFont="true" applyBorder="true" applyAlignment="true" applyProtection="false">
<alignment horizontal="center" vertical="bottom" textRotation="0" wrapText="false" indent="0" shrinkToFit="false"/>
<protection locked="true" hidden="false"/>
</xf>
<xf numFmtId="164" fontId="0" fillId="0" borderId="0" xfId="0" applyFont="true" applyBorder="false" applyAlignment="false" applyProtection="false">
<alignment horizontal="general" vertical="bottom" textRotation="0" wrapText="false" indent="0" shrinkToFit="false"/>
<protection locked="true" hidden="false"/>
</xf>
<xf numFmtId="164" fontId="0" fillId="0" borderId="0" xfId="17" applyFont="true" applyBorder="true" applyAlignment="true" applyProtection="true">
<alignment horizontal="center" vertical="center" textRotation="0" wrapText="false" indent="0" shrinkToFit="false"/>
<protection locked="true" hidden="false"/>
</xf>
<xf numFmtId="164" fontId="4" fillId="0" borderId="0" xfId="0" applyFont="true" applyBorder="true" applyAlignment="true" applyProtection="false">
<alignment horizontal="left" vertical="center" textRotation="0" wrapText="false" indent="0" shrinkToFit="false"/>
<protection locked="true" hidden="false"/>
</xf>
</cellXfs>

and the result

<cellXfs count="6">
<xf numFmtId="164" fontId="0" fillId="0" borderId="0" xfId="0" applyFont="0" applyBorder="0" applyAlignment="0" applyProtection="0">
<alignment horizontal="general" vertical="bottom" textRotation="0" indent="0"/>
<protection locked="1" hidden="0"/>
</xf>
<xf numFmtId="164" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1" applyProtection="0">
<alignment horizontal="center" vertical="bottom" textRotation="0" indent="0"/>
<protection locked="1" hidden="0"/>
</xf>
<xf numFmtId="164" fontId="0" fillId="0" borderId="0" xfId="0" applyFont="1" applyBorder="0" applyAlignment="0" applyProtection="0">
<alignment horizontal="general" vertical="bottom" textRotation="0" indent="0"/>
<protection locked="1" hidden="0"/>
</xf>
<xf numFmtId="164" fontId="0" fillId="2" borderId="0" xfId="3" applyFill="1" applyFont="1" applyBorder="1" applyAlignment="1" applyProtection="1">
<alignment horizontal="center" vertical="center" textRotation="0" indent="0"/>
<protection locked="1" hidden="0"/>
</xf>
<xf fillId="3" applyFill="1"/>
<xf fillId="4" applyFill="1"/>
</cellXfs>

change add 3 fills but the xfs count increase only +1 (5->6) ??? if cell row 3 , 5, 6

<row r="4" customFormat="false" ht="12.8" hidden="false" customHeight="false" outlineLevel="0" collapsed="false">
<c r="A4" s="4"/>
<c r="B4" s="2" t="s">
<v>8</v>
</c>
<c r="C4" s="3"/>
<c r="D4" s="2" t="s">
<v>7</v>
</c>
</row>
<row r="5" customFormat="false" ht="12.8" hidden="false" customHeight="false" outlineLevel="0" collapsed="false">
<c r="A5" s="4"/>
<c r="B5" s="2" t="s">
<v>9</v>
</c>
<c r="C5" s="3"/>
<c r="D5" s="2" t="s">
<v>7</v>
</c>
</row>
<row r="6" customFormat="false" ht="12.8" hidden="false" customHeight="false" outlineLevel="0" collapsed="false">
<c r="A6" s="4"/>
<c r="B6" s="2" t="s">
<v>10</v>
</c>
<c r="C6" s="3"/>
<c r="D6" s="2" t="s">
<v>7</v>
</c>
</row>

result

<row r="4" spans="1:4" customFormat="0" ht="12.8">
<c r="A4" s="4"/>
<c r="B4" s="2" t="s">
<v>8</v>
</c>
<c r="C4" s="5"/>
<c r="D4" s="2" t="s">
<v>7</v>
</c>
</row>
<row r="5" spans="1:4" customFormat="0" ht="12.8">
<c r="A5" s="4"/>
<c r="B5" s="2" t="s">
<v>9</v>
</c>
<c r="C5" s="4"/>
<c r="D5" s="2" t="s">
<v>7</v>
</c>
</row>
<row r="6" spans="1:4" customFormat="0" ht="12.8">
<c r="A6" s="4"/>
<c r="B6" s="2" t="s">
<v>10</v>
</c>
<c r="C6" s="5"/>
<c r="D6" s="2" t="s">
<v>7</v>
</c>
</row>

note the style row (3,4,5,6) between 2 files A / C A / C 3 2 / 3 2 / 3 4 4 / 3 4 / 5 5 4 / 3 4 / 4 6 4 / 3 4 / 5

3 = green 4 = blue 5 =red a)when i create format style , the cell change only if i change the fill, as the new cellxfs, but in case no change i use the modified cellXfs with different style? b) row 6 ,cell C why the style is changed no color applied (DD) c)row 7 cell A no fill as the origin file has no A7 applied style

files joined: COPY_noname.xlsx noname.xlsx

sukoi26 commented 4 years ago

i locate the issue : void xlsx_consumer::read_worksheet_sheetdata() ... // test //if (cell.style_index != -1) //{ // ws_cellimpl->format = target_.format(static_cast(cell.styleindex)).d; //}

to solve this case , but with an other test file still a problem (infinite loop) IMPORTANT: EXCEL give dimension with lot of "holes", XLNT is no optimized for that

<dimension ref="A1:AMJ1048576"/>
<c r="D1" s="8" t="s">
<v>3</v>
</c>
<c r="YD1" s="0"/>

now cellXfs is 8 ( 5 + 3) image

the target format is ok for this case but existing styles are not set

sukoi26 commented 4 years ago

previous comment is not exact as the existing format not set. So i locate other thing on the stylesheet commit 617f7a2525fe20133b77241162e5ea5ed48222af Capture d’écran de 2020-08-15 17-23-54 very different of now Capture d’écran de 2020-08-15 17-26-20

as this code is complex due garbage, i only comment the line 403 to solve the problem //iter->references -= iter->references > 0 ? 1 : 0; it seems the pattern id is not increase when i create the first fill

currently on test with other file , if someboby can try ... th+

sukoi26 commented 3 years ago

i close the issue as i cannot reproduce it on Linux with the latest commit of january https://github.com/tfussell/xlnt/commit/e66e417b0c8806121202adb2dc45de91809710cc .