FreeCAD

Форк
0
/
ProjectFile.cpp 
708 строк · 24.4 Кб
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
XERCES_CPP_NAMESPACE_USE
60
using namespace App;
61

62
namespace {
63
class DocumentMetadata
64
{
65
public:
66
    explicit DocumentMetadata(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* xmlDocument)
67
        : xmlDocument{xmlDocument}
68
    {}
69

70
    ProjectFile::Metadata getMetadata() const
71
    {
72
        return metadata;
73
    }
74

75
    void readXML()
76
    {
77
        readProgramVersion();
78

79
        std::map<std::string, std::string> propMap = initMap();
80

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

95
        setMetadata(propMap);
96
    }
97

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

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

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

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

169
        return {};
170
    }
171

172
private:
173
    XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* xmlDocument;
174
    ProjectFile::Metadata metadata;
175
};
176
}
177

178
ProjectFile::ProjectFile()
179
    : xmlDocument(nullptr)
180
{}
181

182
ProjectFile::ProjectFile(std::string zipArchive)
183
    : stdFile(std::move(zipArchive))
184
    , xmlDocument(nullptr)
185
{}
186

187
ProjectFile::~ProjectFile()
188
{
189
    delete xmlDocument;
190
}
191

192
void ProjectFile::setProjectFile(const std::string& zipArchive)
193
{
194
    stdFile = zipArchive;
195
    delete xmlDocument;
196
    xmlDocument = nullptr;
197
}
198

199
bool ProjectFile::loadDocument()
200
{
201
    if (xmlDocument) {
202
        return true;  // already loaded
203
    }
204

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

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

232
    return false;
233
}
234

235
ProjectFile::Metadata ProjectFile::getMetadata() const
236
{
237
    if (!xmlDocument) {
238
        return {};
239
    }
240

241
    DocumentMetadata reader(xmlDocument);
242
    reader.readXML();
243
    return reader.getMetadata();
244
}
245

246
std::list<ProjectFile::Object> ProjectFile::getObjects() const
247
{
248
    std::list<Object> names;
249
    if (!xmlDocument) {
250
        return names;
251
    }
252

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

275
    return names;
276
}
277

278
std::list<std::string> ProjectFile::getObjectsOfType(const Base::Type& typeId) const
279
{
280
    std::list<std::string> names;
281
    if (!xmlDocument) {
282
        return names;
283
    }
284

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

306
    return names;
307
}
308

309
bool ProjectFile::restoreObject(const std::string& name,
310
                                App::PropertyContainer* obj,
311
                                bool verbose)
312
{
313
    Base::FileInfo fi(stdFile);
314
    Base::ifstream file(fi, std::ios::in | std::ios::binary);
315

316
    zipios::ZipInputStream zipstream(file);
317
    Base::XMLReader reader(stdFile.c_str(), zipstream);
318
    reader.setVerbose(verbose);
319

320
    if (!reader.isValid()) {
321
        return false;
322
    }
323

324
    // skip document properties
325
    reader.readElement("Properties");
326
    reader.readEndElement("Properties");
327

328
    // skip objects
329
    reader.readElement("Objects");
330
    reader.readEndElement("Objects");
331

332
    reader.readElement("ObjectData");
333
    long Cnt = reader.getAttributeAsInteger("Count");
334
    for (long i = 0; i < Cnt; i++) {
335
        reader.readElement("Object");
336
        std::string nameAttr = reader.getAttribute("name");
337

338
        if (nameAttr == name) {
339
            // obj->StatusBits.set(4);
340
            obj->Restore(reader);
341
            // obj->StatusBits.reset(4);
342
        }
343
        reader.readEndElement("Object");
344
    }
345
    reader.readEndElement("ObjectData");
346

347
    reader.readFiles(zipstream);
348

349
    return true;
350
}
351

352
Base::Type ProjectFile::getTypeId(const std::string& name) const
353
{
354
    // <Objects Count="1">
355
    //   <Object type="Mesh::MeshFeature" name="Mesh" />
356
    // <Objects/>
357
    if (!xmlDocument) {
358
        return Base::Type::badType();
359
    }
360

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

383
    return Base::Type::badType();
384
}
385

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

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

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

440
                DOMNode* typeAttr =
441
                    parentNode->getAttributes()->getNamedItem(XStr("type").unicodeForm());
442
                if (typeAttr) {
443
                    prop.type = Base::Type::fromName(StrX(typeAttr->getNodeValue()).c_str());
444
                }
445
            }
446

447
            prop.file = StrX(fileAttr->getNodeValue()).c_str();
448
            files.push_back(prop);
449
        }
450
    }
451

452
    DOMNodeList* subNodes = node->getChildNodes();
453
    for (XMLSize_t i = 0; i < subNodes->getLength(); i++) {
454
        DOMNode* child = subNodes->item(i);
455
        findFiles(child, files);
456
    }
457
}
458

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

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

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

507
    DOMNodeList* subNodes = node->getChildNodes();
508
    for (XMLSize_t i = 0; i < subNodes->getLength(); i++) {
509
        DOMNode* child = subNodes->item(i);
510
        findFiles(child, files);
511
    }
512
}
513

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

530
    return {};
531
}
532

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

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

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

565
    // standard compression
566
    const int compressionLevel = 6;
567
    zipios::ZipOutputStream outZip(newZip);
568
    outZip.setComment("FreeCAD Document");
569
    outZip.setLevel(compressionLevel);
570

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

588
    project.close();
589
    outZip.close();
590
    newZip.close();
591

592
    return fn;
593
}
594

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

605
    // standard compression
606
    const int compressionLevel = 6;
607
    zipios::ZipOutputStream outZip(newZip);
608
    outZip.setComment("FreeCAD Document");
609
    outZip.setLevel(compressionLevel);
610

611
    // open the original zip file
612
    zipios::ZipFile project(stdFile);
613
    zipios::ConstEntries files = project.entries();
614
    for (const auto& it : files) {
615
        std::string file = it->getFileName();
616
        outZip.putNextEntry(file);
617

618
        auto jt = inp.find(file);
619
        if (jt != inp.end()) {
620
            *jt->second >> outZip.rdbuf();
621
        }
622
        else {
623
            std::unique_ptr<std::istream> str(project.getInputStream(file));
624
            if (str) {
625
                *str >> outZip.rdbuf();
626
            }
627
        }
628
    }
629

630
    project.close();
631
    outZip.close();
632
    newZip.close();
633

634
    return fn;
635
}
636

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

648
    // open extra scope
649
    {
650
        // standard compression
651
        const int compressionLevel = 6;
652
        Base::ZipWriter writer(newZip);
653
        writer.setComment("FreeCAD Document");
654
        writer.setLevel(compressionLevel);
655

656
        // open the original zip file
657
        zipios::ZipFile project(stdFile);
658
        zipios::ConstEntries files = project.entries();
659
        for (const auto& it : files) {
660
            std::string file = it->getFileName();
661
            writer.putNextEntry(file.c_str());
662

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

677
    return fn;
678
}
679

680
bool ProjectFile::replaceProjectFile(const std::string& name, bool keepfile)
681
{
682
    std::string uuid = Base::Uuid::createUuid();
683
    std::string fn = stdFile;
684
    fn += ".";
685
    fn += uuid;
686

687
    // Now rename the original file to something unique
688
    Base::FileInfo orig(stdFile);
689
    if (!orig.renameFile(fn.c_str())) {
690
        return false;
691
    }
692
    orig.setFile(fn);
693

694
    // rename the tmp.file to the original file name
695
    Base::FileInfo other(name);
696
    if (!other.renameFile(stdFile.c_str())) {
697
        return false;
698
    }
699

700
    // and delete the renamed original file.
701
    if (!keepfile) {
702
        if (!orig.deleteFile()) {
703
            return false;
704
        }
705
    }
706

707
    return true;
708
}
709

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

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

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

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