XdmfWriter.cpp 27.3 KB
Newer Older
Kenneth Leiter's avatar
Kenneth Leiter committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*****************************************************************************/
/*                                    XDMF                                   */
/*                       eXtensible Data Model and Format                    */
/*                                                                           */
/*  Id : XdmfWriter.cpp                                                      */
/*                                                                           */
/*  Author:                                                                  */
/*     Kenneth Leiter                                                        */
/*     kenneth.leiter@arl.army.mil                                           */
/*     US Army Research Laboratory                                           */
/*     Aberdeen Proving Ground, MD                                           */
/*                                                                           */
/*     Copyright @ 2011 US Army Research Laboratory                          */
/*     All Rights Reserved                                                   */
/*     See Copyright.txt for details                                         */
/*                                                                           */
/*     This software is distributed WITHOUT ANY WARRANTY; without            */
/*     even the implied warranty of MERCHANTABILITY or FITNESS               */
/*     FOR A PARTICULAR PURPOSE.  See the above copyright notice             */
/*     for more information.                                                 */
/*                                                                           */
/*****************************************************************************/
23

24
#include <fstream>
25
#include <libxml/tree.h>
26
#include <sstream>
27
#include <utility>
28
#include "XdmfArray.hpp"
29
#include "XdmfInformation.hpp"
30
#include "XdmfHeavyDataWriter.hpp"
31
#include "XdmfHDF5Controller.hpp"
32
#include "XdmfHDF5Writer.hpp"
33
#include "XdmfItem.hpp"
34
#include "XdmfSystemUtils.hpp"
35
#include "XdmfWriter.hpp"
36
#include "XdmfVersion.hpp"
37
#include "XdmfError.hpp"
38
#include "string.h"
39

40 41 42
/**
 * PIMPL
 */
43
class XdmfWriter::XdmfWriterImpl {
44 45 46

public:

47
  XdmfWriterImpl(const std::string & xmlFilePath,
48 49
                 const shared_ptr<XdmfHeavyDataWriter> heavyDataWriter,
                 std::ostream * stream) :
50 51 52
    mDepth(0),
    mDocumentTitle("Xdmf"),
    mHeavyDataWriter(heavyDataWriter),
53
    mHeavyWriterIsOpen(false),
54 55 56
    mLastXPathed(false),
    mLightDataLimit(100),
    mMode(Default),
57
    mStream(stream),
58
    mWriteXPaths(true),
59
    mXPathParse(true),
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    mXMLCurrentNode(NULL),
    mXMLDocument(NULL),
    mXMLFilePath(XdmfSystemUtils::getRealPath(xmlFilePath)),
    mXPathCount(0),
    mXPathString(""),
    mVersionString(XdmfVersion.getShort())
  {
  };

  ~XdmfWriterImpl()
  {
  };

  void
  closeFile()
  {
    mXPath.clear();
77
    mXPathCount = 0;
78

79
    // This section writes to file
80 81 82 83 84 85 86 87
    std::ofstream fileStream;
    if(!mStream) {
      fileStream.open(mXMLFilePath.c_str());
      mStream = &fileStream;
    }

    xmlBufferPtr buffer = xmlBufferCreate();
    xmlOutputBuffer * outputBuffer = xmlOutputBufferCreateBuffer(buffer,
88
                                                                 NULL);
89 90 91 92 93 94 95 96 97 98 99 100
    xmlSaveFormatFileTo(outputBuffer,
                        mXMLDocument,
                        "utf-8",
                        1);
    *mStream << buffer->content;
    xmlBufferFree(buffer);
    
    if(fileStream.is_open()) {
      fileStream.close();
      mStream = NULL;
    }
    
101
//    xmlFreeDoc(mXMLDocument);
102
    xmlCleanupParser();
103

104
    if(mHeavyDataWriter->getMode() == XdmfHeavyDataWriter::Default) {
105 106 107
      if (mHeavyWriterIsOpen) {
        mHeavyDataWriter->closeFile();
      }
108
    }
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
  };

  void
  openFile()
  {
    mXMLDocument = xmlNewDoc((xmlChar*)"1.0");
    mXMLCurrentNode = xmlNewNode(NULL, (xmlChar*)mDocumentTitle.c_str());
    xmlNewProp(mXMLCurrentNode,
               (xmlChar*)"xmlns:xi",
               (xmlChar*)"http://www.w3.org/2001/XInclude");
    xmlNewProp(mXMLCurrentNode,
               (xmlChar*)"Version",
               (xmlChar*)mVersionString.c_str());
    xmlDocSetRootElement(mXMLDocument, mXMLCurrentNode);
  }

  int mDepth;
  std::string mDocumentTitle;
127
  shared_ptr<XdmfHeavyDataWriter> mHeavyDataWriter;
128
  bool mHeavyWriterIsOpen;
129 130 131
  bool mLastXPathed;
  unsigned int mLightDataLimit;
  Mode mMode;
132
  std::ostream * mStream;
133
  bool mWriteXPaths;
134
  bool mXPathParse;
135 136 137 138 139 140 141
  xmlNodePtr mXMLCurrentNode;
  xmlDocPtr mXMLDocument;
  std::string mXMLFilePath;
  std::map<const XdmfItem * const, std::string> mXPath;
  unsigned int mXPathCount;
  std::string mXPathString;
  std::string mVersionString;
142

143 144
};

145
shared_ptr<XdmfWriter>
146
XdmfWriter::New(const std::string & xmlFilePath)
147
{
148 149 150 151 152 153 154 155
  std::stringstream heavyFileName;
  size_t extension = xmlFilePath.rfind(".");
  if(extension != std::string::npos) {
    heavyFileName << xmlFilePath.substr(0, extension) << ".h5";
  }
  else {
    heavyFileName << xmlFilePath << ".h5";
  }
156
  shared_ptr<XdmfHDF5Writer> hdf5Writer = 
157
    XdmfHDF5Writer::New(heavyFileName.str());
158
  shared_ptr<XdmfWriter> p(new XdmfWriter(xmlFilePath, hdf5Writer));
159
  return p;
160 161
}

162
shared_ptr<XdmfWriter>
163
XdmfWriter::New(const std::string & xmlFilePath,
164
                const shared_ptr<XdmfHeavyDataWriter> heavyDataWriter)
165
{
166 167
  shared_ptr<XdmfWriter> p(new XdmfWriter(xmlFilePath,
                                          heavyDataWriter));
168
  return p;
169 170
}

171 172 173 174 175 176 177 178 179 180
shared_ptr<XdmfWriter> 
XdmfWriter::New(std::ostream & stream,
                const shared_ptr<XdmfHeavyDataWriter> heavyDataWriter)
{
  shared_ptr<XdmfWriter> p(new XdmfWriter("",
                                          heavyDataWriter,
                                          &stream));
  return p;
}

181
XdmfWriter::XdmfWriter(const std::string & xmlFilePath,
182 183
                       shared_ptr<XdmfHeavyDataWriter> heavyDataWriter,
                       std::ostream * stream) :
184
  mRebuildAlreadyVisited(true),
185 186 187
  mImpl(new XdmfWriterImpl(xmlFilePath, 
                           heavyDataWriter,
                           stream))
188 189 190
{
}

191 192
XdmfWriter::XdmfWriter(const XdmfWriter & writerRef) :
  mRebuildAlreadyVisited(writerRef.mRebuildAlreadyVisited)
193 194 195 196 197 198
{
  char * transferPath = strdup(writerRef.getFilePath().c_str());
  char * heavyTransferPath = strdup(writerRef.getHeavyDataWriter()->getFilePath().c_str());
  mImpl = new XdmfWriterImpl(transferPath, XdmfHDF5Writer::New(heavyTransferPath), NULL);
}

199
XdmfWriter::~XdmfWriter()
200
{
201 202
  mXMLArchive.clear();
  xmlFreeDoc(mImpl->mXMLDocument);
203
  delete mImpl;
204
}
205

206
shared_ptr<XdmfHeavyDataWriter>
207
XdmfWriter::getHeavyDataWriter()
208
{
209 210
  return boost::const_pointer_cast<XdmfHeavyDataWriter>
    (static_cast<const XdmfWriter &>(*this).getHeavyDataWriter());
211 212
}

213
shared_ptr<const XdmfHeavyDataWriter>
214
XdmfWriter::getHeavyDataWriter() const
215
{
216
  return mImpl->mHeavyDataWriter;
217 218
}

219 220
std::string
XdmfWriter::getFilePath() const
221
{
222
  return mImpl->mXMLFilePath;
223 224
}

225 226
unsigned int
XdmfWriter::getLightDataLimit() const
227
{
228
  return mImpl->mLightDataLimit;
229 230
}

231 232
XdmfWriter::Mode
XdmfWriter::getMode() const
233
{
234
  return mImpl->mMode;
235 236
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
bool
XdmfWriter::getRebuildXML()
{
  return mRebuildAlreadyVisited;
}

xmlNodePtr
XdmfWriter::getXMLNode(XdmfItem * item, xmlDocPtr parentDoc, xmlNodePtr parentNode)
{
  std::map<XdmfItem *, xmlNodePtr>::iterator node =
    mXMLArchive.find(item);
  if (node != mXMLArchive.end())
  {
    xmlAddChild(parentNode, mXMLArchive[item]);
    return mXMLArchive[item];
  }
  else
  {
    return xmlNewNode(NULL, (xmlChar*)"NULL");
  }
}

bool
XdmfWriter::getHasXMLArchive(XdmfItem * item)
{
  std::map<XdmfItem *, xmlNodePtr>::iterator node =
    mXMLArchive.find(item);
  if (node != mXMLArchive.end())
  {
    return true;
  }
  else
  {
    return false;
  }
}

274 275
bool
XdmfWriter::getWriteXPaths() const
276
{
277
  return mImpl->mWriteXPaths;
278 279
}

280 281 282 283 284 285
bool
XdmfWriter::getXPathParse() const
{
  return mImpl->mXPathParse;
}

286 287
void
XdmfWriter::setDocumentTitle(std::string title)
Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
288
{
289
  mImpl->mDocumentTitle = title;
290
}
291

292 293 294 295 296 297
void
XdmfWriter::setHeavyDataWriter(shared_ptr<XdmfHeavyDataWriter> heavyDataWriter)
{
  mImpl->mHeavyDataWriter = heavyDataWriter;
}

298 299
void
XdmfWriter::setLightDataLimit(const unsigned int numValues)
300
{
301
  mImpl->mLightDataLimit = numValues;
302 303
}

304 305
void
XdmfWriter::setMode(const Mode mode)
306
{
307
  mImpl->mMode = mode;
308 309
}

310 311 312 313 314 315
void
XdmfWriter::setRebuildXML(bool newStatus)
{
  mRebuildAlreadyVisited = newStatus;
}

316 317 318 319 320 321
void
XdmfWriter::setVersionString(std::string version)
{
  mImpl->mVersionString = version;
}

322 323 324 325 326 327
void
XdmfWriter::setXMLNode(XdmfItem * item, xmlNodePtr & newNode)
{
    mXMLArchive[item] = xmlCopyNode(newNode, 1);
}

328 329
void
XdmfWriter::setWriteXPaths(const bool writeXPaths)
330
{
331
  mImpl->mWriteXPaths = writeXPaths;
332 333
}

334 335 336 337 338 339
void
XdmfWriter::setXPathParse(const bool xPathParse)
{
  mImpl->mXPathParse = xPathParse;
}

340 341
void
XdmfWriter::visit(XdmfArray & array,
342
                  const shared_ptr<XdmfBaseVisitor> visitor)
343
{
344 345 346 347 348
  if (mImpl->mDepth == 0) {
    mImpl->openFile();
  }
  mImpl->mDepth++;

Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
349
  // Pull the Function and Subset accociated with the array
350
  shared_ptr<XdmfArrayReference> internalReference = array.getReference();
351

Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
352 353
  // If in the correct read mode process the function or subset
  // if it exists
354
  if (internalReference && array.getReadMode() == XdmfArray::Reference) {
Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
355 356
    // Pass information about the array to the function
    // so it can properly recreate it when read
357 358 359
    internalReference->setConstructedType(array.getItemTag());
    internalReference->setConstructedProperties(array.getItemProperties());
    internalReference->accept(visitor);
Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
360 361 362 363 364
    // This does not write the data contained within the array to file
    // The data is regenerated upon read
  }
  else if (array.getReadMode() == XdmfArray::Controller) {
    // Controller mode is the default mode
365 366
    const bool isSubclassed = 
      array.getItemTag().compare(XdmfArray::ItemTag) != 0;
367

368
    if(isSubclassed) {
369
      this->visit(dynamic_cast<XdmfItem &>(array), visitor);
370
    }
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385
    if(array.getSize() > 0 && !(mImpl->mLastXPathed && isSubclassed)) {
      std::vector<std::string> xmlTextValues;

      // Take care of writing to single heavy data file (Default behavior)
      if(!array.isInitialized() && array.getHeavyDataController(0) &&
         array.getHeavyDataController(0)->getFilePath().compare(mImpl->mHeavyDataWriter->getFilePath()) != 0 &&
         mImpl->mMode == Default) {
        array.read();
      }

      if(array.getHeavyDataController(0) ||
         array.getSize() > mImpl->mLightDataLimit) {
        // Write values to heavy data

386
        // This takes about half the time needed
387 388 389 390 391
        if ((!mImpl->mHeavyWriterIsOpen) &&
            mImpl->mHeavyDataWriter->getMode() == XdmfHeavyDataWriter::Default) {
          mImpl->mHeavyDataWriter->openFile();
          mImpl->mHeavyWriterIsOpen = true;
        }
392
        mImpl->mHeavyDataWriter->visit(array, mImpl->mHeavyDataWriter);
393 394 395

        std::stringstream valuesStream;
        for(unsigned int i = 0; i < array.getNumberHeavyDataControllers(); ++i) {
396

397 398 399 400 401 402
          std::string heavyDataPath =
            array.getHeavyDataController(i)->getFilePath();
          size_t index = heavyDataPath.find_last_of("/\\");
          if(index != std::string::npos) {
            // If path is not a folder
            // put the directory path into this variable
403
            const std::string heavyDataDir = heavyDataPath.substr(0, index + 1);
404 405 406 407 408 409 410 411
            // If the directory is in the XML File Path
            if(mImpl->mXMLFilePath.find(heavyDataDir) == 0) {
              heavyDataPath =
                heavyDataPath.substr(heavyDataDir.size(),
                                     heavyDataPath.size() - heavyDataDir.size());
              // Pull the file off of the end and place it in the DataPath
            }
            // Otherwise the full path is required
412
          }
413 414
          // Clear the stream
          valuesStream.str(std::string());
415
          valuesStream << heavyDataPath << array.getHeavyDataController(i)->getDescriptor();
416 417 418 419
          if (array.getNumberHeavyDataControllers() > 1 ||
              (array.getHeavyDataController(i)->getSize() !=
               array.getHeavyDataController(i)->getDataspaceSize())) {
            valuesStream << "|" << array.getHeavyDataController(i)->getDataspaceDescription();
420
            if (i + 1 < array.getNumberHeavyDataControllers()) {
421 422 423 424
              valuesStream << "|";
            }
          }
          xmlTextValues.push_back(valuesStream.str());
425
        }
426
      }
427 428 429 430
      else {
        // Write values to XML
        xmlTextValues.push_back(array.getValuesString());
      }
431

432 433 434 435
      bool oldWriteXPaths = mImpl->mWriteXPaths;

      // Write XML (metadata) description
      if(isSubclassed) {
436 437 438 439 440 441
        // We don't want temporary items to be on the XPath List
        // This is a one-of anyway, so it shouldn't be equivalent
        // to anything written before now or after.
        mImpl->mWriteXPaths = false;
        const unsigned int parentCount = mImpl->mXPathCount;
        mImpl->mXPathCount = 0;
442 443 444 445 446 447 448 449 450 451
        shared_ptr<XdmfArray> arrayToWrite = XdmfArray::New();
        array.swap(arrayToWrite);
        mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->last;
        this->visit(dynamic_cast<XdmfItem &>(*arrayToWrite.get()), visitor);
        for(unsigned int i = 0; i<xmlTextValues.size(); ++i) {
          xmlAddChild(mImpl->mXMLCurrentNode->last,
                      xmlNewText((xmlChar*)xmlTextValues[i].c_str()));
        }
        mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
        array.swap(arrayToWrite);
452 453
        mImpl->mXPathCount = parentCount;
        mImpl->mLastXPathed = false;
454
      }
455
      else {
456 457
        std::map<const XdmfItem * const, std::string>::const_iterator iter =
          mImpl->mXPath.find(&array);
458
        this->visit(dynamic_cast<XdmfItem &>(array), visitor);
459 460 461 462 463
        if(iter == mImpl->mXPath.end()) {
          for(unsigned int i = 0; i<xmlTextValues.size(); ++i) {
            xmlAddChild(mImpl->mXMLCurrentNode->last,
                        xmlNewText((xmlChar*)xmlTextValues[i].c_str()));
          }
464
        }
465
      }
466
      mImpl->mWriteXPaths = oldWriteXPaths;
467 468
    }
  }
Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
469 470 471
  else {
    // These statements are reached when an unsupported read mode is used
    // or when a read mode is not properly set up
472
    if (array.getReadMode() == XdmfArray::Reference) {
473 474 475
      XdmfError::message(XdmfError::FATAL,
                         "Error: Array to be output as an array reference"
                         " does not have an associated reference.");
Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
476 477
    }
    else {
478 479
      XdmfError::message(XdmfError::FATAL,
                         "Error: Invalid output type.");
Andrew J. Burns (Cont's avatar
Andrew J. Burns (Cont committed
480 481
    }
  }
482 483 484 485 486

  mImpl->mDepth--;
  if(mImpl->mDepth <= 0) {
    mImpl->closeFile();
  }
487 488
}

489 490
void
XdmfWriter::visit(XdmfItem & item,
491
                  const shared_ptr<XdmfBaseVisitor> visitor)
492
{
493 494 495 496 497
  if (mImpl->mDepth == 0) {
    mImpl->openFile();
  }
  mImpl->mDepth++;

498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
  if ((item.getItemTag().compare("Grid") != 0) || // If not a grid
      (item.getItemTag().compare("Grid") == 0 && item.getIsChanged()) || // If a Grid that is changed
      (item.getItemTag().compare("Grid") == 0 && !getHasXMLArchive(&item)) || // If the grid doesn't have an XML Archive
      mRebuildAlreadyVisited) // If Rebuild
  {
    std::string tag = item.getItemTag();
    if (tag.length() == 0) {
      item.traverse(visitor);
    }
    else {
      if(mImpl->mWriteXPaths) {
        if (tag == "Information" && mImpl->mXPathParse) {
          XdmfInformation & xpathinfo = dynamic_cast<XdmfInformation &>(item);
          if (xpathinfo.getKey() == "XIncludes") {
            shared_ptr<XdmfInformation> outputinfo;
            for (unsigned int i = 0; i < xpathinfo.getNumberInformations(); ++i) {
              mImpl->mXPathCount++;
              outputinfo = xpathinfo.getInformation(i);
              mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                                   NULL,
                                                   (xmlChar*)"xi:include",
                                                   NULL);
              xmlNewProp(mImpl->mXMLCurrentNode,
                         (xmlChar*)"href",
                         (xmlChar*)(outputinfo->getKey().c_str()));
              xmlNewProp(mImpl->mXMLCurrentNode,
                         (xmlChar*)"xpointer",
                         (xmlChar*)(outputinfo->getValue().c_str()));
              if (i < xpathinfo.getNumberInformations()-1) {
                mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
              }
            }
          }
          else {
532
            mImpl->mXPathCount++;
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

            const std::string parentXPathString = mImpl->mXPathString;

            std::stringstream newXPathString;
            newXPathString << mImpl->mXPathString << "/" << mImpl->mXPathCount;
            mImpl->mXPathString = newXPathString.str();

            std::map<const XdmfItem * const, std::string>::const_iterator iter =
              mImpl->mXPath.find(&item);
            if(iter != mImpl->mXPath.end()) {
              // Inserted before --- just xpath location of previously written node
              mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                                   NULL,
                                                   (xmlChar*)"xi:include",
                                                   NULL);
              xmlNewProp(mImpl->mXMLCurrentNode,
                         (xmlChar*)"xpointer",
                         (xmlChar*)iter->second.c_str());
              mImpl->mLastXPathed = true;
552
            }
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
            else {
              // Not inserted before --- need to write all data and traverse.
              mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                                   NULL,
                                                   (xmlChar *)tag.c_str(),
                                                   NULL);
              std::stringstream xPathProp;
              xPathProp << "element(/1" << mImpl->mXPathString << ")";
              mImpl->mXPath.insert(std::make_pair(&item, xPathProp.str()));
              const std::map<std::string, std::string> & itemProperties =
                item.getItemProperties();
              for(std::map<std::string, std::string>::const_iterator iter =
                  itemProperties.begin();
                  iter != itemProperties.end();
                  ++iter) {
                xmlNewProp(mImpl->mXMLCurrentNode,
                           (xmlChar*)iter->first.c_str(),
                           (xmlChar*)iter->second.c_str());
              }
              const unsigned int parentCount = mImpl->mXPathCount;
              mImpl->mXPathCount = 0;
              item.traverse(visitor);
              mImpl->mXPathCount = parentCount;
              mImpl->mLastXPathed = false;
            }

            mImpl->mXPathString = parentXPathString;

581 582 583 584 585 586 587 588 589 590 591 592
          }
        }
        else {
          mImpl->mXPathCount++;

          const std::string parentXPathString = mImpl->mXPathString;

          std::stringstream newXPathString;
          newXPathString << mImpl->mXPathString << "/" << mImpl->mXPathCount;
          mImpl->mXPathString = newXPathString.str();

          std::map<const XdmfItem * const, std::string>::const_iterator iter =
593
          mImpl->mXPath.find(&item);
594 595 596 597 598 599
          if(iter != mImpl->mXPath.end()) {
            // Inserted before --- just xpath location of previously written node
            mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                                 NULL,
                                                 (xmlChar*)"xi:include",
                                                 NULL);
600 601 602 603
           xmlNewProp(mImpl->mXMLCurrentNode,
                      (xmlChar*)"xpointer",
                      (xmlChar*)iter->second.c_str());
           mImpl->mLastXPathed = true;
604 605 606
          }
          else {
            // Not inserted before --- need to write all data and traverse.
607

608 609 610 611 612 613 614 615
            mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                                 NULL,
                                                 (xmlChar *)tag.c_str(),
                                                 NULL);
            std::stringstream xPathProp;
            xPathProp << "element(/1" << mImpl->mXPathString << ")";
            mImpl->mXPath.insert(std::make_pair(&item, xPathProp.str()));
            const std::map<std::string, std::string> & itemProperties =
616
            item.getItemProperties();
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
            for(std::map<std::string, std::string>::const_iterator iter =
                itemProperties.begin();
                iter != itemProperties.end();
                ++iter) {
              xmlNewProp(mImpl->mXMLCurrentNode,
                         (xmlChar*)iter->first.c_str(),
                         (xmlChar*)iter->second.c_str());
            }
            const unsigned int parentCount = mImpl->mXPathCount;
            mImpl->mXPathCount = 0;
            item.traverse(visitor);
            mImpl->mXPathCount = parentCount;
            mImpl->mLastXPathed = false;
          }
          mImpl->mXPathString = parentXPathString;
        }
      }
634 635 636
      else
      {
        // Increment XPathCount, handling temporary arrays not written to XPath
637
        mImpl->mXPathCount++;
638 639 640 641 642 643
        // Not inserted before --- need to write all data and traverse.
        mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                             NULL,
                                             (xmlChar*)tag.c_str(),
                                             NULL);
        const std::map<std::string, std::string> itemProperties =
644
          item.getItemProperties();
645
        for(std::map<std::string, std::string>::const_iterator iter =
646
              itemProperties.begin();
647 648 649 650 651
            iter != itemProperties.end();
            ++iter) {
          xmlNewProp(mImpl->mXMLCurrentNode,
                     (xmlChar*)iter->first.c_str(),
                     (xmlChar*)iter->second.c_str());
652
        }
653 654 655 656 657
        const unsigned int parentCount = mImpl->mXPathCount;
        mImpl->mXPathCount = 0;
        item.traverse(visitor);
        mImpl->mXPathCount = parentCount;
        mImpl->mLastXPathed = false;
658
      }
659 660 661 662 663 664 665 666 667 668 669

      if (!mRebuildAlreadyVisited)
      {
        if (item.getItemTag().compare("Grid") == 0)
        {
          setXMLNode(&item, mImpl->mXMLCurrentNode);
        }
        item.setIsChanged(false);
      }

      mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
670
    }
671 672 673 674 675 676 677
  }
  else
  {
    std::map<const XdmfItem * const, std::string>::const_iterator iter =
      mImpl->mXPath.find(&item);
    if(iter != mImpl->mXPath.end()) {
      // Inserted before --- just xpath location of previously written node
678 679
      mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode,
                                           NULL,
680
                                           (xmlChar*)"xi:include",
681
                                           NULL);
682 683 684 685 686 687 688
      xmlNewProp(mImpl->mXMLCurrentNode,
                 (xmlChar*)"xpointer",
                 (xmlChar*)iter->second.c_str());
      mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
    }
    else {
      this->getXMLNode(&item, mImpl->mXMLDocument, mImpl->mXMLCurrentNode);
689
    }
690 691 692 693 694 695
  }

  mImpl->mDepth--;
  if(mImpl->mDepth <= 0) {
    mImpl->closeFile();
  }
696
}
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842

// C Wrappers

XDMFWRITER * XdmfWriterNew(char * fileName)
{
  try
  {
    shared_ptr<XdmfWriter> generatedWriter = XdmfWriter::New(std::string(fileName));
    return (XDMFWRITER *)((void *)(new XdmfWriter(*generatedWriter.get())));
  }
  catch (...)
  {
    shared_ptr<XdmfWriter> generatedWriter = XdmfWriter::New(std::string(fileName));
    return (XDMFWRITER *)((void *)(new XdmfWriter(*generatedWriter.get())));
  }
}

XDMFWRITER * XdmfWriterNewSpecifyHeavyDataWriter(char * fileName, XDMFHEAVYDATAWRITER * heavyDataWriter)
{
  try
  {
    shared_ptr<XdmfWriter> generatedWriter = XdmfWriter::New(std::string(fileName), shared_ptr<XdmfHeavyDataWriter>((XdmfHeavyDataWriter *) heavyDataWriter));
    return (XDMFWRITER *)((void *)(new XdmfWriter(*generatedWriter.get())));
  }
  catch (...)
  {
    shared_ptr<XdmfWriter> generatedWriter = XdmfWriter::New(std::string(fileName), shared_ptr<XdmfHeavyDataWriter>((XdmfHeavyDataWriter *) heavyDataWriter));
    return (XDMFWRITER *)((void *)(new XdmfWriter(*generatedWriter.get())));
  }
}

void XdmfWriterFree(XDMFWRITER * item)
{
  if (item != NULL) {
    delete ((XdmfWriter *)item);
    item = NULL;
  }
}

char * XdmfWriterGetFilePath(XDMFWRITER * writer, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  char * returnPointer = strdup(((XdmfWriter *)writer)->getFilePath().c_str());
  return returnPointer;
  XDMF_ERROR_WRAP_END(status)
  return NULL;
}

XDMFHEAVYDATAWRITER * XdmfWriterGetHeavyDataWriter(XDMFWRITER * writer, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  return (XDMFHEAVYDATAWRITER *)((void *)(((XdmfWriter *)writer)->getHeavyDataWriter().get()));
  XDMF_ERROR_WRAP_END(status)
  return NULL;
}

unsigned int XdmfWriterGetLightDataLimit(XDMFWRITER * writer, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  return ((XdmfWriter *)writer)->getLightDataLimit();
  XDMF_ERROR_WRAP_END(status)
  return 0;
}

int XdmfWriterGetMode(XDMFWRITER * writer, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  XdmfWriter::Mode testMode = ((XdmfWriter *)writer)->getMode();
  if (testMode == XdmfWriter::Default) {
    return XDMF_WRITER_MODE_DEFAULT;
  }
  else if (testMode == XdmfWriter::DistributedHeavyData) {
    return XDMF_WRITER_MODE_DISTRIBUTED_HEAVY_DATA;
  }
  else {
    return -1;
  }
  XDMF_ERROR_WRAP_END(status)
  return -1;
}

int XdmfWriterGetWriteXPaths(XDMFWRITER * writer, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  return ((XdmfWriter *)writer)->getWriteXPaths();
  XDMF_ERROR_WRAP_END(status)
  return 0;
}

int XdmfWriterGetXPathParse(XDMFWRITER * writer, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  return ((XdmfWriter *)writer)->getXPathParse();
  XDMF_ERROR_WRAP_END(status)
  return 0;
}

void XdmfWriterSetHeavyDataWriter(XDMFWRITER * writer, XDMFHEAVYDATAWRITER * heavyDataWriter, int transferOwnership, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  if (transferOwnership) {
    ((XdmfWriter *)writer)->setHeavyDataWriter(shared_ptr<XdmfHeavyDataWriter>((XdmfHeavyDataWriter *) heavyDataWriter));
  }
  else {
    ((XdmfWriter *)writer)->setHeavyDataWriter(shared_ptr<XdmfHeavyDataWriter>((XdmfHeavyDataWriter *) heavyDataWriter, XdmfNullDeleter()));
  }
  XDMF_ERROR_WRAP_END(status)
}

void XdmfWriterSetLightDataLimit(XDMFWRITER * writer, unsigned int numValues, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  ((XdmfWriter *)writer)->setLightDataLimit(numValues);
  XDMF_ERROR_WRAP_END(status)
}

void XdmfWriterSetMode(XDMFWRITER * writer, int mode, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  switch (mode) {
    case XDMF_WRITER_MODE_DEFAULT:
      ((XdmfWriter *)writer)->setMode(XdmfWriter::Default);
      break;
    case XDMF_WRITER_MODE_DISTRIBUTED_HEAVY_DATA:
      ((XdmfWriter *)writer)->setMode(XdmfWriter::DistributedHeavyData);
      break;
    default:
      XdmfError::message(XdmfError::FATAL,
                         "Error: Invalid writer mode.");
  }
  XDMF_ERROR_WRAP_END(status)
}

void XdmfWriterSetWriteXPaths(XDMFWRITER * writer, int writeXPaths, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  ((XdmfWriter *)writer)->setWriteXPaths(writeXPaths);
  XDMF_ERROR_WRAP_END(status)
}

void XdmfWriterSetXPathParse(XDMFWRITER * writer, int xPathParse, int * status)
{
  XDMF_ERROR_WRAP_START(status)
  ((XdmfWriter *)writer)->setXPathParse(xPathParse);
  XDMF_ERROR_WRAP_END(status)
}