FreeCAD

Форк
0
/
ProjectFile.cpp 
713 строк · 24.5 Кб
1
// SPDX-License-Identifier: LGPL-2.1-or-later
2

3
/***************************************************************************
4
 *   Copyright (c) 2024 Werner Mayer <wmayer[at]users.sourceforge.net>     *
5
 *                                                                         *
6
 *   This file is part of FreeCAD.                                         *
7
 *                                                                         *
8
 *   FreeCAD is free software: you can redistribute it and/or modify it    *
9
 *   under the terms of the GNU Lesser General Public License as           *
10
 *   published by the Free Software Foundation, either version 2.1 of the  *
11
 *   License, or (at your option) any later version.                       *
12
 *                                                                         *
13
 *   FreeCAD is distributed in the hope that it will be useful, but        *
14
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
15
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
16
 *   Lesser General Public License for more details.                       *
17
 *                                                                         *
18
 *   You should have received a copy of the GNU Lesser General Public      *
19
 *   License along with FreeCAD. If not, see                               *
20
 *   <https://www.gnu.org/licenses/>.                                      *
21
 *                                                                         *
22
 **************************************************************************/
23

24

25
#include "PreCompiled.h"
26

27
#include <cassert>
28
#include <xercesc/util/PlatformUtils.hpp>
29
#include <xercesc/util/XercesVersion.hpp>
30
#include <xercesc/dom/DOM.hpp>
31
#include <xercesc/dom/DOMImplementation.hpp>
32
#include <xercesc/dom/DOMImplementationLS.hpp>
33
#include <xercesc/framework/StdOutFormatTarget.hpp>
34
#include <xercesc/framework/LocalFileFormatTarget.hpp>
35
#include <xercesc/framework/LocalFileInputSource.hpp>
36
#include <xercesc/parsers/XercesDOMParser.hpp>
37
#include <xercesc/util/XMLUni.hpp>
38
#include <xercesc/util/XMLUniDefs.hpp>
39
#include <xercesc/util/XMLString.hpp>
40
#include <xercesc/sax/ErrorHandler.hpp>
41
#include <xercesc/sax/SAXParseException.hpp>
42
#include <sstream>
43

44
#include <zipios++/zipios-config.h>
45
#include <zipios++/zipfile.h>
46
#include <zipios++/zipinputstream.h>
47
#include <zipios++/zipoutputstream.h>
48
#include <zipios++/meta-iostreams.h>
49

50
#include "ProjectFile.h"
51
#include "DocumentObject.h"
52
#include <Base/FileInfo.h>
53
#include <Base/InputSource.h>
54
#include <Base/Reader.h>
55
#include <Base/Writer.h>
56
#include <Base/Stream.h>
57
#include <Base/XMLTools.h>
58

59
#ifndef XERCES_CPP_NAMESPACE_BEGIN
60
#define XERCES_CPP_NAMESPACE_QUALIFIER
61
using namespace XERCES_CPP_NAMESPACE;
62
#else
63
XERCES_CPP_NAMESPACE_USE
64
#endif
65
using namespace App;
66

67
namespace {
68
class DocumentMetadata
69
{
70
public:
71
    explicit DocumentMetadata(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* xmlDocument)
72
        : xmlDocument{xmlDocument}
73
    {}
74

75
    ProjectFile::Metadata getMetadata() const
76
    {
77
        return metadata;
78
    }
79

80
    void readXML()
81
    {
82
        readProgramVersion();
83

84
        std::map<std::string, std::string> propMap = initMap();
85

86
        DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("Properties").unicodeForm());
87
        for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
88
            DOMNode* node = nodes->item(i);
89
            if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
90
                auto elem = static_cast<DOMElement*>(node);  // NOLINT
91
                DOMNodeList* propList = elem->getElementsByTagName(XStr("Property").unicodeForm());
92
                for (XMLSize_t j = 0; j < propList->getLength(); j++) {
93
                    DOMNode* propNode = propList->item(j);
94
                    readProperty(propNode, propMap);
95
                }
96
            }
97
            break;
98
        }
99

100
        setMetadata(propMap);
101
    }
102

103
private:
104
    void readProgramVersion()
105
    {
106
        if (DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("Document").unicodeForm())) {
107
            for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
108
                DOMNode* node = nodes->item(i);
109
                if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
110
                    DOMNode* nameAttr = node->getAttributes()->getNamedItem(XStr("ProgramVersion").unicodeForm());
111
                    if (nameAttr) {
112
                        std::string value = StrX(nameAttr->getNodeValue()).c_str();
113
                        metadata.programVersion = value;
114
                        break;
115
                    }
116
                }
117
            }
118
        }
119
    }
120
    static std::map<std::string, std::string> initMap()
121
    {
122
        // clang-format off
123
        std::map<std::string, std::string> propMap = {{"Comment", ""},
124
                                                      {"Company", ""},
125
                                                      {"CreatedBy", ""},
126
                                                      {"CreationDate", ""},
127
                                                      {"Label", ""},
128
                                                      {"LastModifiedBy", ""},
129
                                                      {"LastModifiedDate", ""},
130
                                                      {"License", ""},
131
                                                      {"LicenseURL", ""},
132
                                                      {"Uid", ""}};
133
        return propMap;
134
        // clang-format on
135
    }
136

137
    void setMetadata(const std::map<std::string, std::string>& propMap)
138
    {
139
        metadata.comment = propMap.at("Comment");
140
        metadata.company = propMap.at("Company");
141
        metadata.createdBy = propMap.at("CreatedBy");
142
        metadata.creationDate = propMap.at("CreationDate");
143
        metadata.label = propMap.at("Label");
144
        metadata.lastModifiedBy = propMap.at("LastModifiedBy");
145
        metadata.lastModifiedDate = propMap.at("LastModifiedDate");
146
        metadata.license = propMap.at("License");
147
        metadata.licenseURL = propMap.at("LicenseURL");
148
        metadata.uuid = propMap.at("Uid");
149
    }
150

151
    static void readProperty(DOMNode* propNode, std::map<std::string, std::string>& propMap)
152
    {
153
        DOMNode* nameAttr = propNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
154
        if (nameAttr) {
155
            std::string name = StrX(nameAttr->getNodeValue()).c_str();
156
            auto it = propMap.find(name);
157
            if (it != propMap.end()) {
158
                it->second = readValue(propNode);
159
            }
160
        }
161
    }
162

163
    static std::string readValue(DOMNode* node)
164
    {
165
        if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
166
             if (DOMElement* child = static_cast<DOMElement*>(node)->getFirstElementChild()) {  // NOLINT
167
                 if (DOMNode* nameAttr = child->getAttributes()->getNamedItem(XStr("value").unicodeForm())) {
168
                     std::string value = StrX(nameAttr->getNodeValue()).c_str();
169
                     return value;
170
                 }
171
             }
172
        }
173

174
        return {};
175
    }
176

177
private:
178
    XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* xmlDocument;
179
    ProjectFile::Metadata metadata;
180
};
181
}
182

183
ProjectFile::ProjectFile()
184
    : xmlDocument(nullptr)
185
{}
186

187
ProjectFile::ProjectFile(std::string zipArchive)
188
    : stdFile(std::move(zipArchive))
189
    , xmlDocument(nullptr)
190
{}
191

192
ProjectFile::~ProjectFile()
193
{
194
    delete xmlDocument;
195
}
196

197
void ProjectFile::setProjectFile(const std::string& zipArchive)
198
{
199
    stdFile = zipArchive;
200
    delete xmlDocument;
201
    xmlDocument = nullptr;
202
}
203

204
bool ProjectFile::loadDocument()
205
{
206
    if (xmlDocument) {
207
        return true;  // already loaded
208
    }
209

210
    zipios::ZipFile project(stdFile);
211
    if (!project.isValid()) {
212
        return false;
213
    }
214
    std::unique_ptr<std::istream> str(project.getInputStream("Document.xml"));
215
    if (str) {
216
        std::unique_ptr<XercesDOMParser> parser(new XercesDOMParser);
217
        parser->setValidationScheme(XercesDOMParser::Val_Auto);
218
        parser->setDoNamespaces(false);
219
        parser->setDoSchema(false);
220
        parser->setValidationSchemaFullChecking(false);
221
        parser->setCreateEntityReferenceNodes(false);
222

223
        try {
224
            Base::StdInputSource inputSource(*str, stdFile.c_str());
225
            parser->parse(inputSource);
226
            xmlDocument = parser->adoptDocument();
227
            return true;
228
        }
229
        catch (const XMLException&) {
230
            return false;
231
        }
232
        catch (const DOMException&) {
233
            return false;
234
        }
235
    }
236

237
    return false;
238
}
239

240
ProjectFile::Metadata ProjectFile::getMetadata() const
241
{
242
    if (!xmlDocument) {
243
        return {};
244
    }
245

246
    DocumentMetadata reader(xmlDocument);
247
    reader.readXML();
248
    return reader.getMetadata();
249
}
250

251
std::list<ProjectFile::Object> ProjectFile::getObjects() const
252
{
253
    std::list<Object> names;
254
    if (!xmlDocument) {
255
        return names;
256
    }
257

258
    DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("Objects").unicodeForm());
259
    for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
260
        DOMNode* node = nodes->item(i);
261
        if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
262
            DOMNodeList* objectList =
263
                static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm());  // NOLINT
264
            for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
265
                DOMNode* objectNode = objectList->item(j);
266
                DOMNode* typeAttr =
267
                    objectNode->getAttributes()->getNamedItem(XStr("type").unicodeForm());
268
                DOMNode* nameAttr =
269
                    objectNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
270
                if (typeAttr && nameAttr) {
271
                    Object obj;
272
                    obj.name = StrX(nameAttr->getNodeValue()).c_str();
273
                    obj.type = Base::Type::fromName(StrX(typeAttr->getNodeValue()).c_str());
274
                    names.push_back(obj);
275
                }
276
            }
277
        }
278
    }
279

280
    return names;
281
}
282

283
std::list<std::string> ProjectFile::getObjectsOfType(const Base::Type& typeId) const
284
{
285
    std::list<std::string> names;
286
    if (!xmlDocument) {
287
        return names;
288
    }
289

290
    DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("Objects").unicodeForm());
291
    for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
292
        DOMNode* node = nodes->item(i);
293
        if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
294
            DOMNodeList* objectList =
295
                static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm());  // NOLINT
296
            for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
297
                DOMNode* objectNode = objectList->item(j);
298
                DOMNode* typeAttr =
299
                    objectNode->getAttributes()->getNamedItem(XStr("type").unicodeForm());
300
                DOMNode* nameAttr =
301
                    objectNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
302
                if (typeAttr && nameAttr) {
303
                    if (Base::Type::fromName(StrX(typeAttr->getNodeValue()).c_str()) == typeId) {
304
                        names.emplace_back(StrX(nameAttr->getNodeValue()).c_str());
305
                    }
306
                }
307
            }
308
        }
309
    }
310

311
    return names;
312
}
313

314
bool ProjectFile::restoreObject(const std::string& name,
315
                                App::PropertyContainer* obj,
316
                                bool verbose)
317
{
318
    Base::FileInfo fi(stdFile);
319
    Base::ifstream file(fi, std::ios::in | std::ios::binary);
320

321
    zipios::ZipInputStream zipstream(file);
322
    Base::XMLReader reader(stdFile.c_str(), zipstream);
323
    reader.setVerbose(verbose);
324

325
    if (!reader.isValid()) {
326
        return false;
327
    }
328

329
    // skip document properties
330
    reader.readElement("Properties");
331
    reader.readEndElement("Properties");
332

333
    // skip objects
334
    reader.readElement("Objects");
335
    reader.readEndElement("Objects");
336

337
    reader.readElement("ObjectData");
338
    long Cnt = reader.getAttributeAsInteger("Count");
339
    for (long i = 0; i < Cnt; i++) {
340
        reader.readElement("Object");
341
        std::string nameAttr = reader.getAttribute("name");
342

343
        if (nameAttr == name) {
344
            // obj->StatusBits.set(4);
345
            obj->Restore(reader);
346
            // obj->StatusBits.reset(4);
347
        }
348
        reader.readEndElement("Object");
349
    }
350
    reader.readEndElement("ObjectData");
351

352
    reader.readFiles(zipstream);
353

354
    return true;
355
}
356

357
Base::Type ProjectFile::getTypeId(const std::string& name) const
358
{
359
    // <Objects Count="1">
360
    //   <Object type="Mesh::MeshFeature" name="Mesh" />
361
    // <Objects/>
362
    if (!xmlDocument) {
363
        return Base::Type::badType();
364
    }
365

366
    DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("Objects").unicodeForm());
367
    for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
368
        DOMNode* node = nodes->item(i);
369
        if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
370
            DOMNodeList* objectList =
371
                static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm());  // NOLINT
372
            for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
373
                DOMNode* objectNode = objectList->item(j);
374
                DOMNode* typeAttr =
375
                    objectNode->getAttributes()->getNamedItem(XStr("type").unicodeForm());
376
                DOMNode* nameAttr =
377
                    objectNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
378
                if (typeAttr && nameAttr) {
379
                    if (strcmp(name.c_str(), StrX(nameAttr->getNodeValue()).c_str()) == 0) {
380
                        std::string typeId = StrX(typeAttr->getNodeValue()).c_str();
381
                        return Base::Type::fromName(typeId.c_str());
382
                    }
383
                }
384
            }
385
        }
386
    }
387

388
    return Base::Type::badType();
389
}
390

391
std::list<ProjectFile::PropertyFile>
392
ProjectFile::getPropertyFiles(const std::string& name) const
393
{
394
    // <ObjectData Count="1">
395
    //   <Object name="Mesh">
396
    //     <Properties Count="1">
397
    //       <Property name="Mesh" type="Mesh::PropertyMeshKernel">
398
    //         <Mesh file="MeshKernel.bms"/>
399
    //       <Property/>
400
    //     <Properties/>
401
    //   <Object/>
402
    // <ObjectData/>
403
    if (!xmlDocument) {
404
        return {};
405
    }
406

407
    std::list<PropertyFile> files;
408
    DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("ObjectData").unicodeForm());
409
    for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
410
        DOMNode* node = nodes->item(i);
411
        if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
412
            DOMNodeList* objectList =
413
                static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm());  // NOLINT
414
            for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
415
                DOMNode* objectNode = objectList->item(j);
416
                DOMNode* nameAttr =
417
                    objectNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
418
                if (nameAttr && strcmp(name.c_str(), StrX(nameAttr->getNodeValue()).c_str()) == 0) {
419
                    // now go recursively through the sub-tree (i.e. the properties) and collect
420
                    // every file attribute
421
                    findFiles(objectNode, files);
422
                    break;
423
                }
424
            }
425
        }
426
    }
427
    return files;
428
}
429

430
void ProjectFile::findFiles(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node,
431
                            std::list<ProjectFile::PropertyFile>& files) const
432
{
433
    if (node->hasAttributes()) {
434
        ProjectFile::PropertyFile prop;
435
        DOMNode* fileAttr = node->getAttributes()->getNamedItem(XStr("file").unicodeForm());
436
        if (fileAttr) {
437
            DOMNode* parentNode = node->getParentNode();
438
            if (parentNode) {
439
                DOMNode* nameAttr =
440
                    parentNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
441
                if (nameAttr) {
442
                    prop.name = StrX(nameAttr->getNodeValue()).c_str();
443
                }
444

445
                DOMNode* typeAttr =
446
                    parentNode->getAttributes()->getNamedItem(XStr("type").unicodeForm());
447
                if (typeAttr) {
448
                    prop.type = Base::Type::fromName(StrX(typeAttr->getNodeValue()).c_str());
449
                }
450
            }
451

452
            prop.file = StrX(fileAttr->getNodeValue()).c_str();
453
            files.push_back(prop);
454
        }
455
    }
456

457
    DOMNodeList* subNodes = node->getChildNodes();
458
    for (XMLSize_t i = 0; i < subNodes->getLength(); i++) {
459
        DOMNode* child = subNodes->item(i);
460
        findFiles(child, files);
461
    }
462
}
463

464
std::list<std::string> ProjectFile::getInputFiles(const std::string& name) const
465
{
466
    // <ObjectData Count="1">
467
    //   <Object name="Mesh">
468
    //     <Properties Count="1">
469
    //       <Property name="Mesh" type="Mesh::PropertyMeshKernel">
470
    //         <Mesh file="MeshKernel.bms"/>
471
    //       <Property/>
472
    //     <Properties/>
473
    //   <Object/>
474
    // <ObjectData/>
475
    if (!xmlDocument) {
476
        return {};
477
    }
478

479
    std::list<std::string> files;
480
    DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("ObjectData").unicodeForm());
481
    for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
482
        DOMNode* node = nodes->item(i);
483
        if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
484
            DOMNodeList* objectList =
485
                static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm());  // NOLINT
486
            for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
487
                DOMNode* objectNode = objectList->item(j);
488
                DOMNode* nameAttr =
489
                    objectNode->getAttributes()->getNamedItem(XStr("name").unicodeForm());
490
                if (nameAttr && strcmp(name.c_str(), StrX(nameAttr->getNodeValue()).c_str()) == 0) {
491
                    // now go recursively through the sub-tree (i.e. the properties) and collect
492
                    // every file attribute
493
                    findFiles(objectNode, files);
494
                    break;
495
                }
496
            }
497
        }
498
    }
499
    return files;
500
}
501

502
void ProjectFile::findFiles(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node,
503
                            std::list<std::string>& files) const
504
{
505
    if (node->hasAttributes()) {
506
        DOMNode* fileAttr = node->getAttributes()->getNamedItem(XStr("file").unicodeForm());
507
        if (fileAttr) {
508
            files.emplace_back(StrX(fileAttr->getNodeValue()).c_str());
509
        }
510
    }
511

512
    DOMNodeList* subNodes = node->getChildNodes();
513
    for (XMLSize_t i = 0; i < subNodes->getLength(); i++) {
514
        DOMNode* child = subNodes->item(i);
515
        findFiles(child, files);
516
    }
517
}
518

519
std::string ProjectFile::extractInputFile(const std::string& name)
520
{
521
    zipios::ZipFile project(stdFile);
522
    std::unique_ptr<std::istream> str(project.getInputStream(name));
523
    if (str) {
524
        // write it to a tmp. file as writing to the string stream
525
        // might take too long
526
        Base::FileInfo fi(Base::FileInfo::getTempFileName());
527
        Base::ofstream file(fi, std::ios::out | std::ios::binary);
528
        std::streambuf* buf = file.rdbuf();
529
        (*str) >> buf;
530
        file.flush();
531
        file.close();
532
        return fi.filePath();
533
    }
534

535
    return {};
536
}
537

538
void ProjectFile::readInputFile(const std::string& name, std::ostream& str)
539
{
540
    Base::FileInfo fi(extractInputFile(name));
541
    if (fi.exists()) {
542
        Base::ifstream file(fi, std::ios::in | std::ios::binary);
543
        file >> str.rdbuf();
544
        file.close();
545
        fi.deleteFile();
546
    }
547
}
548

549
// Read the given input file from the zip directly into the given stream (not using a temporary
550
// file)
551
void ProjectFile::readInputFileDirect(const std::string& name, std::ostream& str)
552
{
553
    zipios::ZipFile project(stdFile);
554
    std::unique_ptr<std::istream> istr(project.getInputStream(name));
555
    if (istr) {
556
        *istr >> str.rdbuf();
557
    }
558
}
559

560
std::string ProjectFile::replaceInputFile(const std::string& name, std::istream& inp)
561
{
562
    // create a new zip file with the name '<zipfile>.<uuid>'
563
    std::string uuid = Base::Uuid::createUuid();
564
    std::string fn = stdFile;
565
    fn += ".";
566
    fn += uuid;
567
    Base::FileInfo tmp(fn);
568
    Base::ofstream newZip(tmp, std::ios::out | std::ios::binary);
569

570
    // standard compression
571
    const int compressionLevel = 6;
572
    zipios::ZipOutputStream outZip(newZip);
573
    outZip.setComment("FreeCAD Document");
574
    outZip.setLevel(compressionLevel);
575

576
    // open the original zip file
577
    zipios::ZipFile project(stdFile);
578
    zipios::ConstEntries files = project.entries();
579
    for (const auto& it : files) {
580
        std::string file = it->getFileName();
581
        outZip.putNextEntry(file);
582
        if (file == name) {
583
            inp >> outZip.rdbuf();
584
        }
585
        else {
586
            std::unique_ptr<std::istream> str(project.getInputStream(file));
587
            if (str) {
588
                *str >> outZip.rdbuf();
589
            }
590
        }
591
    }
592

593
    project.close();
594
    outZip.close();
595
    newZip.close();
596

597
    return fn;
598
}
599

600
std::string ProjectFile::replaceInputFiles(const std::map<std::string, std::istream*>& inp)
601
{
602
    // create a new zip file with the name '<zipfile>.<uuid>'
603
    std::string uuid = Base::Uuid::createUuid();
604
    std::string fn = stdFile;
605
    fn += ".";
606
    fn += uuid;
607
    Base::FileInfo tmp(fn);
608
    Base::ofstream newZip(tmp, std::ios::out | std::ios::binary);
609

610
    // standard compression
611
    const int compressionLevel = 6;
612
    zipios::ZipOutputStream outZip(newZip);
613
    outZip.setComment("FreeCAD Document");
614
    outZip.setLevel(compressionLevel);
615

616
    // open the original zip file
617
    zipios::ZipFile project(stdFile);
618
    zipios::ConstEntries files = project.entries();
619
    for (const auto& it : files) {
620
        std::string file = it->getFileName();
621
        outZip.putNextEntry(file);
622

623
        auto jt = inp.find(file);
624
        if (jt != inp.end()) {
625
            *jt->second >> outZip.rdbuf();
626
        }
627
        else {
628
            std::unique_ptr<std::istream> str(project.getInputStream(file));
629
            if (str) {
630
                *str >> outZip.rdbuf();
631
            }
632
        }
633
    }
634

635
    project.close();
636
    outZip.close();
637
    newZip.close();
638

639
    return fn;
640
}
641

642
std::string
643
ProjectFile::replacePropertyFiles(const std::map<std::string, App::Property*>& props)
644
{
645
    // create a new zip file with the name '<zipfile>.<uuid>'
646
    std::string uuid = Base::Uuid::createUuid();
647
    std::string fn = stdFile;
648
    fn += ".";
649
    fn += uuid;
650
    Base::FileInfo tmp(fn);
651
    Base::ofstream newZip(tmp, std::ios::out | std::ios::binary);
652

653
    // open extra scope
654
    {
655
        // standard compression
656
        const int compressionLevel = 6;
657
        Base::ZipWriter writer(newZip);
658
        writer.setComment("FreeCAD Document");
659
        writer.setLevel(compressionLevel);
660

661
        // open the original zip file
662
        zipios::ZipFile project(stdFile);
663
        zipios::ConstEntries files = project.entries();
664
        for (const auto& it : files) {
665
            std::string file = it->getFileName();
666
            writer.putNextEntry(file.c_str());
667

668
            auto jt = props.find(file);
669
            if (jt != props.end()) {
670
                jt->second->SaveDocFile(writer);
671
            }
672
            else {
673
                std::unique_ptr<std::istream> str(project.getInputStream(file));
674
                if (str) {
675
                    *str >> writer.Stream().rdbuf();
676
                }
677
            }
678
        }
679
        project.close();
680
    }
681

682
    return fn;
683
}
684

685
bool ProjectFile::replaceProjectFile(const std::string& name, bool keepfile)
686
{
687
    std::string uuid = Base::Uuid::createUuid();
688
    std::string fn = stdFile;
689
    fn += ".";
690
    fn += uuid;
691

692
    // Now rename the original file to something unique
693
    Base::FileInfo orig(stdFile);
694
    if (!orig.renameFile(fn.c_str())) {
695
        return false;
696
    }
697
    orig.setFile(fn);
698

699
    // rename the tmp.file to the original file name
700
    Base::FileInfo other(name);
701
    if (!other.renameFile(stdFile.c_str())) {
702
        return false;
703
    }
704

705
    // and delete the renamed original file.
706
    if (!keepfile) {
707
        if (!orig.deleteFile()) {
708
            return false;
709
        }
710
    }
711

712
    return true;
713
}
714

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.