1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <dataprovider.hxx>
11 #include <datatransformation.hxx>
12 #include <datamapper.hxx>
13 #include <stringutil.hxx>
14 
15 #include <tools/stream.hxx>
16 #include <vcl/svapp.hxx>
17 #include <docsh.hxx>
18 #include <orcus/csv_parser.hpp>
19 #include <utility>
20 
21 namespace {
22 
23 class CSVHandler
24 {
25     ScDocument* mpDoc;
26     SCCOL mnCol;
27     SCROW mnRow;
28 
29 public:
CSVHandler(ScDocument * pDoc)30     CSVHandler(ScDocument* pDoc) :
31         mpDoc(pDoc), mnCol(0), mnRow(0)
32     {
33     }
34 
begin_parse()35     static void begin_parse() {}
end_parse()36     static void end_parse() {}
begin_row()37     static void begin_row() {}
end_row()38     void end_row()
39     {
40         ++mnRow;
41         mnCol = 0;
42     }
43 
cell(const char * p,size_t n,bool)44     void cell(const char* p, size_t n, bool /*transient*/)
45     {
46         if (mnCol > mpDoc->MaxCol())
47             return;
48 
49         double mfValue = 0.0;
50         if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', mfValue))
51         {
52             mpDoc->SetValue(mnCol, mnRow, 0, mfValue);
53         }
54         else
55         {
56             OString aStr(p, n);
57             mpDoc->SetString(mnCol, mnRow, 0, OStringToOUString(aStr, RTL_TEXTENCODING_UTF8));
58         }
59 
60         ++mnCol;
61     }
62 };
63 
64 }
65 
66 namespace sc {
CSVFetchThread(ScDocument & rDoc,const OUString & mrURL,std::function<void ()> aImportFinishedHdl,const std::vector<std::shared_ptr<sc::DataTransformation>> & rDataTransformations)67 CSVFetchThread::CSVFetchThread(
68     ScDocument& rDoc, const OUString& mrURL, std::function<void()> aImportFinishedHdl,
69     const std::vector<std::shared_ptr<sc::DataTransformation>>& rDataTransformations)
70     : Thread("CSV Fetch Thread")
71     , mrDocument(rDoc)
72     , maURL(mrURL)
73     , mbTerminate(false)
74     , maDataTransformations(rDataTransformations)
75     , maImportFinishedHdl(std::move(aImportFinishedHdl))
76 {
77     maConfig.delimiters.push_back(',');
78     maConfig.text_qualifier = '"';
79 }
80 
~CSVFetchThread()81 CSVFetchThread::~CSVFetchThread()
82 {
83 }
84 
IsRequestedTerminate()85 bool CSVFetchThread::IsRequestedTerminate()
86 {
87     osl::MutexGuard aGuard(maMtxTerminate);
88     return mbTerminate;
89 }
90 
RequestTerminate()91 void CSVFetchThread::RequestTerminate()
92 {
93     osl::MutexGuard aGuard(maMtxTerminate);
94     mbTerminate = true;
95 }
96 
EndThread()97 void CSVFetchThread::EndThread()
98 {
99     RequestTerminate();
100 }
101 
execute()102 void CSVFetchThread::execute()
103 {
104     OStringBuffer aBuffer(64000);
105     std::unique_ptr<SvStream> pStream = DataProvider::FetchStreamFromURL(maURL, aBuffer);
106     if (mbTerminate)
107         return;
108 
109     CSVHandler aHdl(&mrDocument);
110     orcus::csv_parser<CSVHandler> parser(aBuffer.getStr(), aBuffer.getLength(), aHdl, maConfig);
111     parser.parse();
112 
113     for (const auto& itr : maDataTransformations)
114     {
115         itr->Transform(mrDocument);
116     }
117 
118     SolarMutexGuard aGuard;
119     maImportFinishedHdl();
120 }
121 
CSVDataProvider(ScDocument * pDoc,sc::ExternalDataSource & rDataSource)122 CSVDataProvider::CSVDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource):
123     DataProvider(rDataSource),
124     mpDocument(pDoc)
125 {
126 }
127 
~CSVDataProvider()128 CSVDataProvider::~CSVDataProvider()
129 {
130     if (mxCSVFetchThread.is())
131     {
132         SolarMutexReleaser aReleaser;
133         mxCSVFetchThread->join();
134     }
135 }
136 
Import()137 void CSVDataProvider::Import()
138 {
139     // already importing data
140     if (mpDoc)
141         return;
142 
143     mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
144     mpDoc->ResetClip(mpDocument, SCTAB(0));
145     mxCSVFetchThread = new CSVFetchThread(*mpDoc, mrDataSource.getURL(), std::bind(&CSVDataProvider::ImportFinished, this), mrDataSource.getDataTransformation());
146     mxCSVFetchThread->launch();
147 
148     if (mbDeterministic)
149     {
150         SolarMutexReleaser aReleaser;
151         mxCSVFetchThread->join();
152     }
153 }
154 
ImportFinished()155 void CSVDataProvider::ImportFinished()
156 {
157     mrDataSource.getDBManager()->WriteToDoc(*mpDoc);
158     mpDoc.reset();
159     Refresh();
160 }
161 
Refresh()162 void CSVDataProvider::Refresh()
163 {
164     ScDocShell* pDocShell = static_cast<ScDocShell*>(mpDocument->GetDocumentShell());
165     if (pDocShell)
166         pDocShell->SetDocumentModified();
167 }
168 
GetURL() const169 const OUString& CSVDataProvider::GetURL() const
170 {
171     return mrDataSource.getURL();
172 }
173 
174 }
175 
176 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
177