// - close the file
bferr TBinFileBase::close(void)
{
  if (platformFileIsOpen()) {
    // remove empty space from end of file
    truncate(fBinFileHeader.numrecords);
    // write new header
    flushHeader();
    // close file
    platformCloseFile();
  }
  return BFE_OK;
} // TBinFileBase::close
//______________________________________________________________________________
void xml2guidovisitor::visitStart ( S_part& elt )
{
	partsummary ps;
	xml_tree_browser browser(&ps);
	browser.browse(*elt);

	smartlist<int>::ptr voices = ps.getVoices ();
	int targetStaff = 0xffff;	// initialized to a value we'll unlikely encounter
	bool notesOnly = false;
	rational currentTimeSign (0,1);
	// browse the parts voice by voice: allows to describe voices that spans over several staves
	for (unsigned int i = 0; i < voices->size(); i++) {
		int targetVoice = (*voices)[i];
		int mainstaff = ps.getMainStaff(targetVoice);
		if (targetStaff == mainstaff) {
			notesOnly = true;
		}
		else {
			notesOnly = false;
			targetStaff = mainstaff;
			fCurrentStaffIndex++;
		}

		Sguidoelement seq = guidoseq::create();
		push (seq);

		Sguidoelement tag = guidotag::create("staff");
		tag->add (guidoparam::create(fCurrentStaffIndex, false));
		add (tag);

		flushHeader (fHeader);
		flushPartHeader (fPartHeaders[elt->getAttributeValue("id")]);

		xmlpart2guido pv(fGenerateComments, fGenerateStem, fGenerateBars);
		pv.generatePositions (fGeneratePositions);
		xml_tree_browser browser(&pv);
		pv.initialize(seq, targetStaff, fCurrentStaffIndex, targetVoice, notesOnly, currentTimeSign);
		browser.browse(*elt);
		pop();
		currentTimeSign = pv.getTimeSign();
	}
}
// - create new DB file according to params set with setFileInfo
bferr TBinFileBase::create(uInt32 aRecordsize, uInt32 aExtraHeadersize, void *aExtraHeaderP, bool aOverwrite)
{
  bferr e;

  close();
  // try to open
  e=open(aExtraHeadersize,NULL); // do not pass our new header data in case there is an old file already
  if (e==BFE_NOTFOUND || aOverwrite) {
    close();
    // create new file
    if (!platformOpenFile(fFilename.c_str(),fopm_create))
      return BFE_IOERR; // could not create for some reason
    // prepare header
    fBinFileHeader.idword=fIdWord;
    fBinFileHeader.version=fVersion;
    fBinFileHeader.headersize=sizeof(TBinFileHeader)+aExtraHeadersize;
    fBinFileHeader.recordsize=aRecordsize;
    fBinFileHeader.numrecords=0;
    fBinFileHeader.allocatedrecords=0;
    fBinFileHeader.uniquerecordid=0;
    fHeaderDirty = true;
    // - link in the new extra header buffer
    fExtraHeaderP = aExtraHeaderP;
    fExtraHeaderDirty = true; // make sure it gets written
    // write entire header
    e=flushHeader();
    // opened with new version
    fFoundVersion = fVersion;
  }
  else if (e==BFE_OK) {
    // already exists
    close();
    e=BFE_EXISTS;
  }
  return e;
} // TBinFileBase::create
// - try to open existing DB file according to params set with setFileInfo
bferr TBinFileBase::open(uInt32 aExtraHeadersize, void *aExtraHeaderP, TUpdateFunc aUpdateFunc)
{
  // make sure it is closed first
  close();
  // save extra header info
  fExtraHeaderSize=aExtraHeadersize;
  fExtraHeaderP=aExtraHeaderP;
  // try to open file for (binary) update
  if (!platformOpenFile(fFilename.c_str(),fopm_update))
    return BFE_NOTFOUND;
  // read header
  fHeaderDirty=false;
  platformSeekFile(0);
  if (!platformReadFile(&fBinFileHeader,sizeof(fBinFileHeader))) {
    close();
    return BFE_BADSTRUCT;
  }
  // check type and Version
  if (fBinFileHeader.idword!=fIdWord) {
    close();
    return BFE_BADTYPE;
  }
  // remember the version we found when trying to open
  fFoundVersion = fBinFileHeader.version;
  // check need for upgrade
  if (fBinFileHeader.version!=fVersion) {
    // try to update file if update-func is provided
    if (aUpdateFunc) {
      // check if we can update (no data provided for update)
      uInt32 newrecordsize=aUpdateFunc(fFoundVersion,fVersion,NULL,NULL,0);
      if (newrecordsize) {
        // we can update from current to requested version
        // - allocate buffer for all records
        uInt32 numrecords = fBinFileHeader.numrecords;
        uInt32 oldrecordsize = fBinFileHeader.recordsize;
        void *oldrecords = malloc(numrecords * oldrecordsize);
        if (!oldrecords) return BFE_MEMORY;
        // - read all current records into memory (relative to old headersize)
        readRecord(0,oldrecords,numrecords);
        // Update header because extra header might have changed in size
        if (fExtraHeaderP && (fBinFileHeader.headersize!=sizeof(TBinFileHeader)+fExtraHeaderSize)) {
          // (extra) header has changed in size
          // - read old extra header (or part of it that will be retained in case it shrinks between versions)
          uInt32 oldEHdrSz = fBinFileHeader.headersize-sizeof(TBinFileHeader);
          platformSeekFile(sizeof(TBinFileHeader));
          platformReadFile(fExtraHeaderP,oldEHdrSz<=fExtraHeaderSize ? oldEHdrSz : fExtraHeaderSize);
          // - adjust the overall header size
          fBinFileHeader.headersize = sizeof(TBinFileHeader)+fExtraHeaderSize;
          // - let the update function handle init of the extra header
          aUpdateFunc(fFoundVersion,fVersion,NULL,fExtraHeaderP,0);
          // - make sure new extra header gets written
          fExtraHeaderDirty = true;
        }
        // - modify header fields
        fBinFileHeader.version=fVersion; // update version
        fBinFileHeader.recordsize=newrecordsize; // update record size
        fHeaderDirty=true; // header must be updated
        // - write new header (to make sure file is at least as long as header+extraheader)
        flushHeader();
        // - truncate the file (taking new extra header size into account already, in case it has changed)
        truncate();
        // - now convert buffered records
        void *newrecord = malloc(newrecordsize);
        for (uInt32 i=0; i<numrecords; i++) {
          // call updatefunc to convert record
          if (aUpdateFunc(fFoundVersion,fVersion,(void *)((uInt8 *)oldrecords+i*oldrecordsize),newrecord,oldrecordsize)) {
            // save new record
            uInt32 newi;
            newRecord(newi,newrecord);
          }
        }
        // - forget buffers
        free(newrecord);
        free(oldrecords);
        // - flush new header
        flushHeader();
      }
      else {
        // cannot update
        close();
        return BFE_BADVERSION;
      }
    }
    else {
      // cannot update
      close();
      return BFE_BADVERSION;
    }
  }
  // check record compatibility
  if (fExpectedRecordSize && fExpectedRecordSize!=fBinFileHeader.recordsize) {
    close();
    return BFE_BADSTRUCT;
  }
  // check extra header compatibility
  if (fBinFileHeader.headersize<sizeof(TBinFileHeader)+fExtraHeaderSize) {
    close();
    return BFE_BADSTRUCT;
  }
  // read extra header
  if (fExtraHeaderP && fExtraHeaderSize>0) {
    platformSeekFile(sizeof(TBinFileHeader));
    platformReadFile(fExtraHeaderP,fExtraHeaderSize);
    fExtraHeaderDirty=false;
  }
  return BFE_OK;
} // TBinFileBase::open