src/CoreArray/dFile.cpp
c736b191
 // ===========================================================
 //     _/_/_/   _/_/_/  _/_/_/_/    _/_/_/_/  _/_/_/   _/_/_/
 //      _/    _/       _/             _/    _/    _/   _/   _/
 //     _/    _/       _/_/_/_/       _/    _/    _/   _/_/_/
 //    _/    _/       _/             _/    _/    _/   _/
 // _/_/_/   _/_/_/  _/_/_/_/_/     _/     _/_/_/   _/_/
 // ===========================================================
 //
 // dFile.cpp: Functions and classes for CoreArray Genomic Data Structure (GDS)
 //
9dad7f5c
 // Copyright (C) 2007-2020    Xiuwen Zheng
c736b191
 //
 // This file is part of CoreArray.
 //
 // CoreArray is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Lesser General Public License Version 3 as
 // published by the Free Software Foundation.
 //
 // CoreArray is distributed in the hope that it will be useful, but
 // WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Lesser General Public License for more details.
 //
 // You should have received a copy of the GNU Lesser General Public
 // License along with CoreArray.
 // If not, see <http://www.gnu.org/licenses/>.
 
 #include "dFile.h"
 #include <algorithm>
 
 
 using namespace CoreArray;
 
 /// GDS file version
 #define COREARRAY_FILE_VERSION   COREARRAY_VERSION
 
1763e5bd
 /// GDS file prefix, SHOULD NOT BE CHANGED
c736b191
 #define COREARRAY_FILE_PREFIX    "COREARRAYx0A"
 
 
174580a2
 static const char *ERR_OBJ_RELEASE = "%s(), Release() should return ZERO.";
 
c736b191
 
 // =====================================================================
 // CdGDSObj
 // =====================================================================
 
 // CdObjAttr
 
 static const char *VAR_ATTRCNT  = "ATTRCNT";
 static const char *VAR_ATTRLIST = "ATTRLIST";
 
1c861a99
 static const char *ERR_ATTR_NAME = "No Attribute Name ('%s').";
 static const char *ERR_ATTR_NAME_EXIST = "Attribute '%s' has existed.";
174580a2
 static const char *ERR_ATTR_INVALID_NAME = "Invalid zero-length name.";
c736b191
 
 CdObjAttr::CdObjAttr(CdGDSObj &vOwner): CdObject(), fOwner(vOwner)
 { }
 
 CdObjAttr::~CdObjAttr()
 {
 	vector<TdPair*>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 	{
 		TdPair *p = *it;
 		*it = NULL;
 		delete p;
 	}
 }
 
 void CdObjAttr::Assign(CdObjAttr &Source)
 {
 	Clear();
1763e5bd
 	const size_t n = Source.Count();
 	fList.reserve(n);
 	for (size_t i=0; i < n; i++)
 	{
 		TdPair *I = new TdPair;
 		I->name = Source.Names(i);
 		fList.push_back(I);
 		Changed();
 		I->val = Source[i];
 	}
c736b191
 }
 
663a9c18
 CdAny &CdObjAttr::Add(const UTF8String &Name)
c736b191
 {
1763e5bd
 	_ValidateName(Name);
 	vector<TdPair*>::iterator it = _Find(Name);
c736b191
 	if (it == fList.end())
 	{
 		TdPair *I = new TdPair;
 		I->name = Name;
 		fList.push_back(I);
 		Changed();
 		return I->val;
 	} else
663a9c18
 		throw ErrGDSObj(ERR_ATTR_NAME_EXIST, Name.c_str());
c736b191
 }
 
663a9c18
 int CdObjAttr::IndexName(const UTF8String &Name)
c736b191
 {
1763e5bd
 	vector<TdPair*>::iterator it = _Find(Name);
c736b191
 	if (it != fList.end())
     	return it - fList.begin();
 	else
 		return -1;
 }
 
663a9c18
 bool CdObjAttr::HasName(const UTF8String &Name)
1763e5bd
 {
 	return (IndexName(Name) >= 0);
 }
 
663a9c18
 void CdObjAttr::Delete(const UTF8String &Name)
c736b191
 {
1763e5bd
 	vector<TdPair*>::iterator it = _Find(Name);
c736b191
 	if (it == fList.end())
663a9c18
 		throw ErrGDSObj(ERR_ATTR_NAME, Name.c_str());
c736b191
 	TdPair *p = *it;
 	*it = NULL;
 	fList.erase(it);
 	delete p;
 	Changed();
 }
 
 void CdObjAttr::Delete(int Index)
 {
 	fList.at(Index); // check range
 	TdPair *p = fList[Index];
 	fList[Index] = NULL;
     fList.erase(fList.begin() + Index);
 	delete p;
 	Changed();
 }
 
 void CdObjAttr::Clear()
 {
 	if (!fList.empty())
 	{
 		vector<TdPair*>::iterator it;
 		for (it = fList.begin(); it != fList.end(); it++)
 		{
 			TdPair *p = *it;
 			*it = NULL;
 			delete p;
 		}
 		fList.clear();
 		Changed();
 	}
 }
 
 void CdObjAttr::Changed()
 {
 	this->fOwner.fChanged = true;
 }
 
663a9c18
 CdAny & CdObjAttr::operator[](const UTF8String &Name)
c736b191
 {
1763e5bd
 	vector<TdPair*>::iterator it = _Find(Name);
c736b191
 	if (it == fList.end())
663a9c18
 		throw ErrGDSObj(ERR_ATTR_NAME, Name.c_str());
c736b191
 	return (*it)->val;
 }
 
 CdAny & CdObjAttr::operator[](int Index)
 {
 	return fList.at(Index)->val;
 }
 
 void CdObjAttr::Loading(CdReader &Reader, TdVersion Version)
 {
 	C_Int32 Cnt;
 	Reader[VAR_ATTRCNT] >> Cnt;
 	if (!fList.empty())
 	{
 		vector<TdPair*>::iterator it;
 		for (it = fList.begin(); it != fList.end(); it++)
 		{
 			TdPair *p = *it;
 			*it = NULL;
 			delete p;
 		}
 		fList.clear();
 	}
 
 	if (Cnt > 0)
 	{
 		Reader[VAR_ATTRLIST].BeginStruct();
 		for (int i=0; i < Cnt; i++)
 		{
 			TdPair *I = new TdPair;
 			try {
663a9c18
 				I->name = UTF16ToUTF8(Reader.Storage().RpUTF16()); // TODO
c736b191
 				Reader >> I->val;
 			} catch (...) {
 				delete I;
 				break;
 			}
 			fList.push_back(I);
 		}
 		Reader.EndStruct();
 	}
 }
 
 void CdObjAttr::Saving(CdWriter &Writer)
 {
 	C_Int32 Cnt = fList.size();
 	Writer[VAR_ATTRCNT] << Cnt;
 	if (Cnt > 0)
 	{
 		Writer[VAR_ATTRLIST].NewStruct();
 		vector<TdPair*>::iterator it;
 		for (it=fList.begin(); it != fList.end(); it++)
 		{
663a9c18
 			Writer.Storage().WpUTF16(UTF8ToUTF16((*it)->name)); // TODO
c736b191
 			Writer << (*it)->val;
 		}
 		Writer.EndStruct();
 	}
 }
 
663a9c18
 vector<CdObjAttr::TdPair*>::iterator CdObjAttr::_Find(const UTF8String &Name)
c736b191
 {
 	vector<TdPair*>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 	{
 		if ((*it)->name == Name)
 			break;
 	}
 	return it;
 }
 
663a9c18
 void CdObjAttr::SetName(const UTF8String &OldName, const UTF8String &NewName)
c736b191
 {
1763e5bd
 	_ValidateName(NewName);
 	vector<TdPair*>::iterator it = _Find(OldName);
c736b191
 	if (it == fList.end())
663a9c18
 		throw ErrGDSObj(ERR_ATTR_NAME, OldName.c_str());
c736b191
 	if (OldName != NewName)
 	{
079b2f49
 		if (HasName(NewName))
663a9c18
 			throw ErrGDSObj(ERR_ATTR_NAME_EXIST, NewName.c_str());
c736b191
 		(*it)->name = NewName;
 		Changed();
 	}
 }
 
663a9c18
 void CdObjAttr::SetName(int Index, const UTF8String &NewName)
c736b191
 {
 	TdPair &p = *fList.at(Index); // check range
1763e5bd
 	_ValidateName(NewName);
c736b191
 	if (p.name != NewName)
 	{
079b2f49
 		if (HasName(NewName))
663a9c18
 			throw ErrGDSObj(ERR_ATTR_NAME_EXIST, NewName.c_str());
c736b191
 		p.name = NewName;
 		Changed();
 	}
 }
 
663a9c18
 void CdObjAttr::_ValidateName(const UTF8String &name)
c736b191
 {
 	if (name.empty())
174580a2
         throw ErrGDSObj(ERR_ATTR_INVALID_NAME);
c736b191
 }
 
 
 // CdGDSObj
 
174580a2
 static const char *ERR_NO_NAME      = "No name exists!";
 static const char *ERR_NO_OBJECT    = "No parent folder.";
 static const char *ERR_DUP_NAME     = "Duplicate name!";
 static const char *ERR_MOVE_TO_ADD  = "Please call 'AddObj' to add an object.";
 static const char *ERR_SAME_FILE    = "'MoveTo' should be within the same GDS file.";
 static const char *ERR_MOVETO_CHILD = "Cannot move to its sub folder.";
 static const char *ERR_GDS_READONLY = "The GDS file is read-only.";
 static const char *ERR_GDSStream    = "%s: GDSStream should not be NULL.";
 
 static const char *ERR_INVALID_ASSIGN  = "Invalid assignment.";
 static const char *ERR_INVALID_ASSIGN2 = "Invalid assignment to '%s' from '%s'.";
 static const char *ERR_INVALID_ASSIGN3 = "Invalid assignment to '%s'.";
 static const char *ERR_INVALID_ASSIGN4 = "Invalid assignment from '%s'.";
c736b191
 
 CdGDSObj::CdGDSObj(): CdObjMsg(), fAttr(*this)
 {
 	fFolder = NULL;
 	fGDSStream = NULL;
 	fChanged = false;
 }
 
 CdGDSObj::~CdGDSObj()
 {
 	if (fGDSStream)
 		fGDSStream->Release();
 }
 
1763e5bd
 void CdGDSObj::AssignAttribute(CdGDSObj &Source)
c736b191
 {
1763e5bd
 	fAttr.Assign(Source.Attribute());
c736b191
 }
 
663a9c18
 UTF8String CdGDSObj::Name() const
c736b191
 {
 	if (fFolder)
 	{
 		vector<CdGDSFolder::TNode>::const_iterator it;
 		for (it = fFolder->fList.begin(); it != fFolder->fList.end(); it++)
 		{
 			if (it->Obj == this)
 				return it->Name;
 		}
 	}
 	throw ErrGDSObj(ERR_NO_NAME);
 }
 
663a9c18
 UTF8String CdGDSObj::FullName() const
c736b191
 {
663a9c18
 	const UTF8String Delimiter = "/";
 	UTF8String rv = Name();
c736b191
 	CdGDSFolder *p = fFolder;
 	if (p != NULL)
 	{
 		while (p->fFolder)
 		{
 			rv = p->Name() + Delimiter + rv;
 			p = p->fFolder;
 		}
 	}
 	return rv;
 }
 
663a9c18
 void CdGDSObj::SetName(const UTF8String &NewName)
c736b191
 {
 	if (fFolder)
 	{
48c1b22b
 		vector<CdGDSFolder::TNode>::iterator it = fFolder->FindObj(this);
 		if (it != fFolder->fList.end())
c736b191
 		{
48c1b22b
 			if (it->Name != NewName)
c736b191
 			{
48c1b22b
 				if (fFolder->_HasName(NewName))
 					throw ErrGDSObj(ERR_DUP_NAME);
 				it->Name = NewName;
 				fFolder->fChanged = true;
c736b191
 			}
48c1b22b
 			return;
c736b191
 		}
48c1b22b
 		throw ErrGDSObj(ERR_NO_OBJECT);
c736b191
 	}
 	throw ErrGDSObj(ERR_NO_NAME);
 }
 
48c1b22b
 bool CdGDSObj::GetHidden() const
 {
 	if (fFolder)
 	{
 		vector<CdGDSFolder::TNode>::const_iterator it =
 			fFolder->FindObj(this);
 		if (it != fFolder->fList.end())
 		{
 			return (it->Flag & CdGDSFolder::TNode::FLAG_ATTR_HIDDEN) != 0;
 		}
 		throw ErrGDSObj(ERR_NO_OBJECT);
 	}
 	return false;
 }
 
 void CdGDSObj::SetHidden(bool hidden)
 {
 	if (fFolder)
 	{
 		vector<CdGDSFolder::TNode>::iterator it = fFolder->FindObj(this);
 		if (it != fFolder->fList.end())
 		{
 			bool flag = (it->Flag & CdGDSFolder::TNode::FLAG_ATTR_HIDDEN) != 0;
 			if (flag != hidden)
 			{
 				if (hidden)
 					it->Flag |= CdGDSFolder::TNode::FLAG_ATTR_HIDDEN;
 				else
 					it->Flag &= ~CdGDSFolder::TNode::FLAG_ATTR_HIDDEN;
 				fFolder->fChanged = true;
 			}
 			return;
 		}
 		throw ErrGDSObj(ERR_NO_OBJECT);
 	}
 }
 
c736b191
 void CdGDSObj::MoveTo(CdGDSFolder &folder)
 {
 	if (fGDSStream && folder.GDSStream() && fFolder)
 	{
 		CdBlockCollection *n1 = &fGDSStream->Collection();
 		CdBlockCollection *n2 = &folder.GDSStream()->Collection();
 		if (n1 == n2)
 		{
 			if (dynamic_cast<CdGDSFolder*>(this))
 			{
ceab6642
 				if (static_cast<CdGDSFolder*>(this)->HasChild(&folder, true))
174580a2
 					throw ErrGDSObj(ERR_MOVETO_CHILD);
c736b191
 			}
 			if ((fFolder!=&folder) && (this!=&folder))
 			{
 				vector<CdGDSFolder::TNode>::iterator it;
48c1b22b
 				it = fFolder->FindObj(this);
c736b191
 				if (folder._HasName(it->Name))
 					throw ErrGDSObj(ERR_DUP_NAME);
 				folder.fList.push_back(*it);
 				fFolder->fList.erase(it);
 				fFolder->fChanged = folder.fChanged = true;
 				fFolder = &folder;
 			}
 		} else
174580a2
 			throw ErrGDSObj(ERR_SAME_FILE);
c736b191
 	} else
 		throw ErrGDSObj(ERR_MOVE_TO_ADD);
 }
 
 void CdGDSObj::Synchronize()
 {
 	if (fChanged)
 		SaveToBlockStream();
 }
 
87646568
 void CdGDSObj::GetOwnBlockStream(vector<const CdBlockStream*> &Out) const
 {
 	Out.clear();
 }
 
 void CdGDSObj::GetOwnBlockStream(vector<CdStream*> &Out)
c736b191
 {
 	Out.clear();
 }
 
 CdGDSFile *CdGDSObj::GDSFile()
 {
 	if (fGDSStream)
 	{
 		CdBlockCollection *collect = &fGDSStream->Collection();
 		// static_cast, not dynamic_cast
 		// because 'cannot cast protected base class'
 		CdGDSFile *rv = (CdGDSFile*)(collect);
 		return rv;
 	} else
 		return NULL;
 }
 
 void CdGDSObj::LoadStruct(CdReader &Reader, TdVersion Version)
 {
9dad7f5c
 	// call the function 'Loading'
c736b191
 	CdObjMsg::LoadStruct(Reader, Version);
9dad7f5c
 	// load attributes
 	COREARRAY_READER_CALL_SILENT(fAttr.Loading(Reader, Version));
c736b191
 }
 
 void CdGDSObj::SaveStruct(CdWriter &Writer, bool IncludeName)
 {
 	// beginning ...
 	Writer.BeginNameSpace();
 	if (IncludeName)
 	{
 		TdVersion Version = SaveVersion();
 		Writer.Storage() << C_UInt16(Version);
 		Writer.WriteClassName(dName());
 	}
 	// call save function ::Saving
 	this->Saving(Writer);
 	// save attribute
 	fAttr.Saving(Writer);
 	// ending ...
 	Writer.EndStruct();
 	fChanged = false;
 }
 
 void CdGDSObj::SaveToBlockStream()
 {
 	_CheckGDSStream();
 	if (fGDSStream)
 	{
 		CdWriter Writer(fGDSStream, &GDSFile()->Log());
 		SaveStruct(Writer, IsWithClassName());
 	}
 }
 
1c861a99
 #ifdef COREARRAY_CODE_USING_LOG
 string CdGDSObj::LogValue()
 {
 	if (fFolder)
663a9c18
 		return FullName();
1c861a99
 	else
 		return "/";
 }
 #endif
 
1763e5bd
 void CdGDSObj::_CheckWritable()
 {
 	CdGDSFile *file = GDSFile();
 	if (file && file->ReadOnly())
174580a2
 		throw ErrGDSObj(ERR_GDS_READONLY);
1763e5bd
 }
 
c736b191
 void CdGDSObj::_CheckGDSStream()
 {
 	if (!fGDSStream)
174580a2
 		throw ErrGDSObj(ERR_GDSStream, "CdGDSObj");
c736b191
 }
 
1763e5bd
 void CdGDSObj::RaiseInvalidAssign(const char *ThisClass, CdGDSObj *Source)
c736b191
 {
1763e5bd
 	const char *SourceClass = NULL;
 	if (Source)
 	{
 		SourceClass = Source->dName();
 		if (SourceClass && (SourceClass[0]==0))
 			SourceClass = NULL;
 	}
 
 	if (ThisClass)
 	{
 		if (SourceClass)
174580a2
 			throw ErrGDSObj(ERR_INVALID_ASSIGN2, ThisClass, SourceClass);
1763e5bd
 		else
174580a2
 			throw ErrGDSObj(ERR_INVALID_ASSIGN3, ThisClass);
1763e5bd
 	} else {
 		if (SourceClass)
174580a2
 			throw ErrGDSObj(ERR_INVALID_ASSIGN4, SourceClass);
1763e5bd
 		else
174580a2
 			throw ErrGDSObj(ERR_INVALID_ASSIGN);
1763e5bd
 	}
c736b191
 }
 
9dad7f5c
 void CdGDSObj::_GDSObjInitProc(CdObjClassMgr &Sender, CdObject *Obj, void *Data)
c736b191
 {
9dad7f5c
 	if (dynamic_cast<CdGDSObj*>(Obj))
 		static_cast<CdGDSObj*>(Obj)->fGDSStream = (CdBlockStream*)Data;
c736b191
 }
 
 
 
 // =====================================================================
 // Stream Manage Pipe
 // =====================================================================
 
 namespace CoreArray
 {
e6df59b3
 	static const char *VAR_PIPE_SIZE   = "PIPE_SIZE";
 	static const char *VAR_PIPE_LEVEL  = "PIPE_LEVEL";
c736b191
 	static const char *VAR_PIPE_BKSIZE = "PIPE_BKSIZE";
 
fa35cdff
 	static const CdRecodeStream::TLevel CompressionLevels[] =
c736b191
 	{
8b4044d3
 		CdRecodeStream::clMin,
c736b191
 		CdRecodeStream::clFast,
 		CdRecodeStream::clDefault,
 		CdRecodeStream::clMax,
fa35cdff
 		CdRecodeStream::clUltra,     // ultra  (LZMA 512MiB)
 		CdRecodeStream::clUltraMax,  // ultra_max  (LZMA 1536MiB)
c736b191
 		CdRecodeStream::clDefault
 	};
 
 	static const char *RA_Str_BSize[] =
 	{
 		"16K", "32K", "64K", "128K",
 		"256K", "512K", "1M", "2M",
 		"4M", "8M", NULL
 	};
 
 	/// The pipe for writing data to a compressed stream
 	template<typename CLASS>
 		class COREARRAY_DLL_DEFAULT CdWritePipe: public CdStreamPipe
 	{
 	public:
 		CdWritePipe(CdRecodeStream::TLevel vLevel,
 				TdCompressRemainder &vRemainder):
 			CdStreamPipe(), fRemainder(vRemainder)
 		{
 			fLevel = vLevel;
 		}
 
 	protected:
 		CdStream *fStream;
 		CLASS *fPStream;
 		CdRecodeStream::TLevel fLevel;
 		TdCompressRemainder &fRemainder;
 
 		virtual CdStream *InitPipe(CdBufStream *BufStream)
 		{
 			fStream = BufStream->Stream();
 			fPStream = new CLASS(*fStream, fLevel);
 			fPStream->PtrExtRec = &fRemainder;
 			return fPStream;
 		}
 		virtual CdStream *FreePipe()
 		{
9dad7f5c
 			if (fPStream) { fPStream->Release(); fPStream = NULL; }
c736b191
 			return fStream;
 		}
 	};
 
 	/// The pipe for writing data to a compressed stream
 	template<typename CLASS, typename BSIZE>
 		class COREARRAY_DLL_DEFAULT CdWritePipe2: public CdStreamPipe
 	{
 	public:
 		CdWritePipe2(CdRecodeStream::TLevel vLevel, BSIZE bs,
 				TdCompressRemainder &vRemainder):
 			CdStreamPipe(), fRemainder(vRemainder)
 		{
 			fLevel = vLevel;
 			fBSize = bs;
 		}
 
 	protected:
 		CdStream *fStream;
 		CLASS *fPStream;
 		CdRecodeStream::TLevel fLevel;
 		BSIZE fBSize;
 		TdCompressRemainder &fRemainder;
 
 		virtual CdStream *InitPipe(CdBufStream *BufStream)
 		{
 			fStream = BufStream->Stream();
 			fPStream = new CLASS(*fStream, fLevel, fBSize);
 			fPStream->PtrExtRec = &fRemainder;
 			return fPStream;
 		}
 		virtual CdStream *FreePipe()
 		{
9dad7f5c
 			if (fPStream) { fPStream->Release(); fPStream = NULL; }
c736b191
 			return fStream;
 		}
 	};
 
 
 	/// The pipe system with a template
 	template<int MaxBVal, int DefBVal, typename BSIZE,
 		typename CLASS, typename TYPE>
 		class COREARRAY_DLL_DEFAULT CdPipe: public CdPipeMgrItem2
 	{
 	private:
 		SIZE64 vSizeInfo_Ptr;
 
 	public:
 		CdPipe(): CdPipeMgrItem2()
 		{
 			fLevel = CdRecodeStream::clDefault;
 			fBlockSize = (BSIZE)DefBVal;
 			vSizeInfo_Ptr = -1;
 		}
 
1763e5bd
 		virtual CdPipeMgrItem *New()
c736b191
 		{
 			CdPipe<MaxBVal, DefBVal, BSIZE, CLASS, TYPE> *rv = new TYPE();
 			rv->fCoderIndex = fCoderIndex;
 			rv->fParamIndex = fParamIndex;
 			rv->fLevel = fLevel;
 			rv->fBlockSize = fBlockSize;
 			return rv;
 		}
 
 		virtual void PopPipe(CdBufStream &buf)
 		{
 			buf.PopPipe();
 		}
 
 		virtual bool WriteMode(CdBufStream &buf) const
 		{
 			return (dynamic_cast<CLASS*>(buf.Stream()) != NULL);
 		}
 
 		virtual void ClosePipe(CdBufStream &buf)
 		{
 			CLASS *s = dynamic_cast<CLASS*>(buf.Stream());
 			if (s) s->Close();
         }
 
 		virtual bool GetStreamInfo(CdBufStream *buf)
 		{
 			SIZE64 in, out;
 			if (buf)
 			{
 				CLASS *s = dynamic_cast<CLASS*>(buf->Stream());
 				if (s)
 				{
 					in = s->TotalIn();
 					out = s->TotalOut() + (s->HaveClosed() ? 0 : s->Pending());
 				} else
 					return false;
 			} else
 				in = out = 0;
 			if ((in!=fStreamTotalIn) || (out!=fStreamTotalOut))
 			{
 				fStreamTotalIn = in;
 				fStreamTotalOut = out;
 				return true;
 			} else
 				return false;
 		}
 
 	protected:
 		CdRecodeStream::TLevel fLevel;
 		BSIZE fBlockSize;
 
 		virtual CdPipeMgrItem *Match(const char *Mode) const
 		{
 			int ic, ip;
 			ParseMode(Mode, ic, ip);
 			if (ic >= 0)
 			{
 				CdPipe<MaxBVal, DefBVal, BSIZE, CLASS, TYPE> *rv = new TYPE();
 				rv->fLevel = CompressionLevels[ic];
 				if (ip < 0) ip = DefBVal;
 				rv->fBlockSize = (BSIZE)ip;
 				rv->fCoderIndex = rv->fLevel;
 				rv->fParamIndex = ip;
 				return rv;
 			} else
 				return NULL;
 		}
 
 		virtual void UpdateStreamInfo(CdStream &Stream)
 		{
 			if (vSizeInfo_Ptr >= 0)
 			{
 				BYTE_LE<CdStream> S(Stream);
 				S.SetPosition(vSizeInfo_Ptr);
 				S << fStreamTotalIn << fStreamTotalOut;
fa35cdff
 			}
c736b191
 		}
 		virtual void LoadStream(CdReader &Reader, TdVersion Version)
 		{
 			// pipe size
 			if (Reader.HaveProperty(VAR_PIPE_SIZE))
 			{
 				vSizeInfo_Ptr = Reader.PropPosition(VAR_PIPE_SIZE);
 				C_Int64 Ary[2];
 				Reader[VAR_PIPE_SIZE].GetShortRec(Ary, 2);
 				fStreamTotalIn = Ary[0];
 				fStreamTotalOut = Ary[1];
 			} else {
 				vSizeInfo_Ptr = -1;
 				fStreamTotalIn = fStreamTotalOut = -1;
 			}
 
 			// pipe level
 			if (Reader.HaveProperty(VAR_PIPE_LEVEL))
 			{
 				C_UInt8 I = 0;
 				Reader[VAR_PIPE_LEVEL] >> I;
fa35cdff
 				if (I > 5)
c736b191
 				{
 					// Since clNone=0, clFast=1, clDefault=2, clMax=3
fa35cdff
 					// clUltra=4, clUltraMax=5
 					throw ErrGDSObj("Invalid 'PIPE_LEVEL %d'", I);
 				}
c736b191
 				fLevel = (CdRecodeStream::TLevel)I;
 			} else
 				fLevel = CdRecodeStream::clUnknown;
 			fCoderIndex = (int)fLevel;
 
 			// pipe block size
 			if (MaxBVal > 0)
 			{
 				if (Reader.HaveProperty(VAR_PIPE_BKSIZE))
 				{
 					C_UInt8 I = 0;
 					Reader[VAR_PIPE_BKSIZE] >> I;
 					if ((int)I > MaxBVal)
 	            	    throw ErrGDSObj("Invalid 'PIPE_BKSIZE %d'", I);
 					fBlockSize = (BSIZE)I;
 				} else
 					fBlockSize = (BSIZE)(-1);
 				fParamIndex = (int)fBlockSize;
 			}
 		}
 		virtual void SaveStream(CdWriter &Writer)
 		{
237e476e
 			UpdateStreamSize();
c736b191
 			C_Int64 Ary[2] = { fStreamTotalIn, fStreamTotalOut };
 			Writer[VAR_PIPE_SIZE].NewShortRec(Ary, 2);
 			vSizeInfo_Ptr = Writer.PropPosition(VAR_PIPE_SIZE);
 			Writer[VAR_PIPE_LEVEL] << C_UInt8(fLevel);
 			if (MaxBVal > 0)
 				Writer[VAR_PIPE_BKSIZE] << C_UInt8(fBlockSize);
 		}
 	};
 }
 
 
 namespace CoreArray
 {
 	// =====================================================================
 	// ZIP: ZIP Pipe
 	// =====================================================================
 
8b4044d3
 	typedef CdStreamPipe2<CdZDecoder> CdZIPReadPipe;
 	typedef CdWritePipe<CdZEncoder> CdZIPWritePipe;
c736b191
 
 	static const char *ZIP_Strings[] =
 	{
fa35cdff
 		"ZIP.min", "ZIP.fast", "ZIP.def", "ZIP.max", "", "", "ZIP", NULL
c736b191
 	};
 
 	class COREARRAY_DLL_DEFAULT CdPipeZIP:
8b4044d3
 		public CdPipe<0, -1, int, CdZEncoder, CdPipeZIP>
c736b191
 	{
 	public:
 		virtual const char *Coder() const
 			{ return "ZIP"; }
 		virtual const char *Description() const
 			{ return "zlib_" ZLIB_VERSION; }
 		virtual void PushReadPipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdZIPReadPipe); }
 		virtual void PushWritePipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdZIPWritePipe(fLevel, fRemainder)); }
 
 	protected:
 		virtual const char **CoderList() const { return ZIP_Strings; }
 		virtual const char **ParamList() const { return NULL; }
 	};
 
 
 	// =====================================================================
 	// ZRA: ZIP Pipe with the support of random access
 	// =====================================================================
 
8b4044d3
 	typedef CdStreamPipe2<CdZDecoder_RA> CdZRAReadPipe;
 	typedef CdWritePipe2<CdZEncoder_RA, CdRAAlgorithm::TBlockSize> CdZRAWritePipe;
c736b191
 
 	static const char *ZRA_Strings[] =
 	{
fa35cdff
 		"ZIP_RA.min", "ZIP_RA.fast", "ZIP_RA.def", "ZIP_RA.max",
 		"", "", "ZIP_RA", NULL
c736b191
 	};
 
 	class COREARRAY_DLL_DEFAULT CdPipeZRA:
 		public CdPipe<CdRAAlgorithm::raLast, CdRAAlgorithm::raDefault,
8b4044d3
 		CdRAAlgorithm::TBlockSize, CdZEncoder_RA, CdPipeZRA>
c736b191
 	{
 	public:
 		virtual const char *Coder() const
8b4044d3
 			{ return "ZIP_ra"; }
c736b191
 		virtual const char *Description() const
8b4044d3
 			{ return "zlib_" ZLIB_VERSION " (random access)"; }
c736b191
 		virtual void PushReadPipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdZRAReadPipe); }
 		virtual void PushWritePipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdZRAWritePipe(fLevel, fBlockSize, fRemainder)); }
 
 	protected:
 		virtual const char **CoderList() const { return ZRA_Strings; }
 		virtual const char **ParamList() const { return RA_Str_BSize; }
 	};
 
 
 	// =====================================================================
 	// LZ4: LZ4 Pipe
 	// =====================================================================
 
2bc440fd
 #ifndef COREARRAY_NO_LZ4
 
8b4044d3
 	typedef CdStreamPipe2<CdLZ4Decoder> CdLZ4ReadPipe;
 	typedef CdWritePipe2<CdLZ4Encoder, CdBaseLZ4Stream::TLZ4Chunk> CdLZ4WritePipe;
c736b191
 
 	static const char *LZ4_Strings[] =
8b4044d3
 	{
fa35cdff
 		"LZ4.min", "LZ4.fast", "LZ4.hc", "LZ4.max", "", "", "LZ4", NULL
8b4044d3
 	};
c736b191
 	static const char *LZ4_Str_BSize[] =
 		{ "64K", "256K", "1M", "4M", NULL };
 
 	class COREARRAY_DLL_DEFAULT CdPipeLZ4:
 		public CdPipe<CdBaseLZ4Stream::bsLast, CdBaseLZ4Stream::bsDefault,
8b4044d3
 		CdBaseLZ4Stream::TLZ4Chunk, CdLZ4Encoder, CdPipeLZ4>
c736b191
 	{
 	public:
 		virtual const char *Coder() const
 			{ return "LZ4"; }
 		virtual const char *Description() const
48c1b22b
 		{
0cc5598c
 			static char LZ4_TEXT[] = "lz4_v?.?.?";
48c1b22b
 			LZ4_TEXT[5] = '0' + LZ4_VERSION_MAJOR;
 			LZ4_TEXT[7] = '0' + LZ4_VERSION_MINOR;
0cc5598c
 			LZ4_TEXT[9] = '0' + LZ4_VERSION_RELEASE;
48c1b22b
 			return LZ4_TEXT;
 		}
c736b191
 		virtual void PushReadPipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdLZ4ReadPipe); }
 		virtual void PushWritePipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdLZ4WritePipe(fLevel, fBlockSize, fRemainder)); }
 
 	protected:
 		virtual const char **CoderList() const { return LZ4_Strings; }
 		virtual const char **ParamList() const { return LZ4_Str_BSize; }
 	};
 
 
 	// =====================================================================
 	// LZ4: LZ4 Pipe with random access
 	// =====================================================================
 
8b4044d3
 	typedef CdStreamPipe2<CdLZ4Decoder_RA> CdLZ4RAReadPipe;
 	typedef CdWritePipe2<CdLZ4Encoder_RA, CdRAAlgorithm::TBlockSize> CdLZ4RAWritePipe;
c736b191
 
 	static const char *LZ4RA_Strings[] =
 	{
fa35cdff
 		"LZ4_RA.min", "LZ4_RA.fast", "LZ4_RA.hc", "LZ4_RA.max",
 		"", "", "LZ4_RA", NULL
c736b191
 	};
 
 	class COREARRAY_DLL_DEFAULT CdPipeLZ4RA:
 		public CdPipe<CdRAAlgorithm::raLast, CdRAAlgorithm::raDefault,
8b4044d3
 		CdRAAlgorithm::TBlockSize, CdLZ4Encoder_RA, CdPipeLZ4RA>
c736b191
 	{
 	public:
 		virtual const char *Coder() const
8b4044d3
 			{ return "LZ4_ra"; }
c736b191
 		virtual const char *Description() const
4f372597
 		{
0cc5598c
 			static char LZ4_TEXT[] = "lz4_v?.?.? (random access)";
4f372597
 			LZ4_TEXT[5] = '0' + LZ4_VERSION_MAJOR;
 			LZ4_TEXT[7] = '0' + LZ4_VERSION_MINOR;
0cc5598c
 			LZ4_TEXT[9] = '0' + LZ4_VERSION_RELEASE;
4f372597
 			return LZ4_TEXT;
 		}
c736b191
 		virtual void PushReadPipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdLZ4RAReadPipe); }
 		virtual void PushWritePipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdLZ4RAWritePipe(fLevel, fBlockSize, fRemainder)); }
 
 	protected:
 		virtual const char **CoderList() const { return LZ4RA_Strings; }
 		virtual const char **ParamList() const { return RA_Str_BSize; }
 	};
8b4044d3
 
2bc440fd
 #endif
 
8b4044d3
 
 	// =====================================================================
 	// XZ: xz stream
 	// =====================================================================
 
2bc440fd
 #ifndef COREARRAY_NO_LZMA
 
8b4044d3
 	typedef CdStreamPipe2<CdXZDecoder> CdXZReadPipe;
 	typedef CdWritePipe<CdXZEncoder> CdXZWritePipe;
 
 	static const char *XZ_Strings[] =
 	{
fa35cdff
 		"LZMA.min", "LZMA.fast", "LZMA.def", "LZMA.max",
 		"LZMA.ultra", "LZMA.ultra_max", "LZMA", NULL
8b4044d3
 	};
 
 	class COREARRAY_DLL_DEFAULT CdPipeXZ:
 		public CdPipe<0, -1, int, CdXZEncoder, CdPipeXZ>
 	{
 	public:
 		virtual const char *Coder() const
 			{ return "LZMA"; }
 		virtual const char *Description() const
 			{ return "xz_" LZMA_VERSION_STRING; }
 		virtual void PushReadPipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdXZReadPipe); }
 		virtual void PushWritePipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdXZWritePipe(fLevel, fRemainder)); }
 
 	protected:
 		virtual const char **CoderList() const { return XZ_Strings; }
 		virtual const char **ParamList() const { return NULL; }
 	};
 
 
 	// =====================================================================
fa35cdff
 	// XZ_RA: XZ Pipe with the support of random access
8b4044d3
 	// =====================================================================
 
 	typedef CdStreamPipe2<CdXZDecoder_RA> CdXZReadPipe_RA;
 	typedef CdWritePipe2<CdXZEncoder_RA, CdRAAlgorithm::TBlockSize> CdXZWritePipe_RA;
 
 	static const char *XZ_RA_Strings[] =
 	{
fa35cdff
 		"LZMA_RA.min", "LZMA_RA.fast", "LZMA_RA.def", "LZMA_RA.max",
 		"LZMA_RA.ultra", "LZMA_RA.ultra_max", "LZMA_RA", NULL
8b4044d3
 	};
 
 	class COREARRAY_DLL_DEFAULT CdPipeXZ_RA:
 		public CdPipe<CdRAAlgorithm::raLast, CdRAAlgorithm::raDefault,
 		CdRAAlgorithm::TBlockSize, CdXZEncoder_RA, CdPipeXZ_RA>
 	{
 	public:
 		virtual const char *Coder() const
 			{ return "LZMA_ra"; }
 		virtual const char *Description() const
 			{ return "xz_" LZMA_VERSION_STRING " (random access)"; }
 		virtual void PushReadPipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdXZReadPipe_RA); }
 		virtual void PushWritePipe(CdBufStream &buf)
 			{ buf.PushPipe(new CdXZWritePipe_RA(fLevel, fBlockSize, fRemainder)); }
 
 	protected:
 		virtual const char **CoderList() const { return XZ_RA_Strings; }
 		virtual const char **ParamList() const { return RA_Str_BSize; }
 	};
2bc440fd
 
 #endif
 
c736b191
 }
 
 
 using namespace std;
 using namespace CoreArray;
 
 
 // CdPipeMgrItem
 
 CdPipeMgrItem::CdPipeMgrItem(): CdAbstractItem()
 {
 	fOwner = NULL;
 	fStreamTotalIn = fStreamTotalOut = -1;
 }
 
 CdPipeMgrItem::~CdPipeMgrItem() {}
 
 void CdPipeMgrItem::UpdateStreamSize()
 {
 	if (fOwner)
 		fOwner->GetPipeInfo();
 }
 
 void CdPipeMgrItem::LoadStream(CdReader &Reader, TdVersion Version) { }
 
 void CdPipeMgrItem::SaveStream(CdWriter &Writer) { }
 
 bool CdPipeMgrItem::EqualText(const char *s1, const char *s2)
 {
 	for (;*s1 || *s2; s1++, s2++)
 	{
 		if (toupper(*s1) != toupper(*s2))
 			return false;
 	}
 	return true;
 }
 
 
 // CdPipeMgrItem2
 
 CdPipeMgrItem2::CdPipeMgrItem2(): CdPipeMgrItem()
 {
 	fCoderIndex = fParamIndex = -1;
 }
 
fa35cdff
 string CdPipeMgrItem2::CoderOptString() const
 {
 	string rv;
 	const char **ss = CoderList();
 	for (; *ss; ss++)
 	{
 		if (strlen(*ss) > 0)
 		{
 			if (!rv.empty()) rv.append(", ");
 			rv.append(*ss);
 		}
 	}
 	return rv;
 }
 
 string CdPipeMgrItem2::ExtOptString() const
 {
 	string rv;
 	const char **ss = ParamList();
 	if (ss)
 	{
 		for (; *ss; ss++)
 		{
 			if (strlen(*ss) > 0)
 			{
 				if (!rv.empty()) rv.append(", ");
 				rv.append(":");
 				rv.append(*ss);
 			}
 		}
 	}
 	return rv;
 }
 
c736b191
 bool CdPipeMgrItem2::Equal(const char *Mode) const
 {
 	int ic, ip;
 	ParseMode(Mode, ic, ip);
 	if (fCoderIndex >= 0)
 		return (fCoderIndex == ic) && (fParamIndex == ip);
 	else
 		return false;
 }
 
 string CdPipeMgrItem2::CoderParam() const
 {
 	string ans;
 	if (fCoderIndex >= 0)
 		ans.append(CoderList()[fCoderIndex]);
 	if (fParamIndex >= 0)
 	{
 		ans.append(":");
 		ans.append(ParamList()[fParamIndex]);
 	}
 	return ans;
 }
 
 void CdPipeMgrItem2::ParseMode(const char *Mode, int &IdxCoder,
 	int &IdxParam) const
 {
 	IdxCoder = IdxParam = -1;
 
 	string s = Mode;
 	size_t pos = s.find(':');
 	if (pos != string::npos)
 	{
 		s.resize(pos);
 		Mode += (pos + 1);
 	} else
 		Mode = NULL;
 
 	const char **ss = CoderList();
 	for (int i=0; *ss != NULL; ss++, i++)
 	{
fa35cdff
 		if (strlen(*ss)>0 && EqualText(s.c_str(), *ss))
c736b191
 		{
 			IdxCoder = i;
 			break;
 		}
 	}
 	if (IdxCoder < 0) return;
 
 	ss = ParamList();
 	if ((ss != NULL) && (Mode != NULL))
 	{
 		for (int i=0; *ss != NULL; ss++, i++)
 		{
fa35cdff
 			if (strlen(*ss)>0 && EqualText(Mode, *ss))
c736b191
 			{
 				IdxParam = i;
 				break;
 			}
 		}
 		if (IdxParam < 0) IdxCoder = -1;
 	}
 }
 
 
 
 // CdStreamPipeMgr
 
 CdStreamPipeMgr CoreArray::dStreamPipeMgr;
 
 CdStreamPipeMgr::CdStreamPipeMgr(): CdAbstractManager()
 {
 	Register(new CdPipeZIP);
 	Register(new CdPipeZRA);
2bc440fd
 #ifndef COREARRAY_NO_LZ4
c736b191
 	Register(new CdPipeLZ4);
 	Register(new CdPipeLZ4RA);
2bc440fd
 #endif
 #ifndef COREARRAY_NO_LZMA
8b4044d3
 	Register(new CdPipeXZ);
 	Register(new CdPipeXZ_RA);
2bc440fd
 #endif
c736b191
 }
 
 CdStreamPipeMgr::~CdStreamPipeMgr()
 {
 	vector<CdPipeMgrItem*>::iterator it;
 	for (it = fRegList.begin(); it != fRegList.end(); it++)
 		delete *it;
 }
 
 void CdStreamPipeMgr::Register(CdPipeMgrItem *vNewPipe)
 {
 	if (vNewPipe)
 		fRegList.push_back(vNewPipe);
 }
 
 
 CdPipeMgrItem *CdStreamPipeMgr::Match(CdGDSObjPipe &Obj, const char *Mode)
 {
 	vector<CdPipeMgrItem*>::iterator it;
 	for (it = fRegList.begin(); it != fRegList.end(); it++)
 	{
 		CdPipeMgrItem *rv = (*it)->Match(Mode);
 		if (rv)
 		{
         	rv->fOwner = &Obj;
 			return rv;
         }
 	}
 	return NULL;
 }
 
 
 // =====================================================================
 // CdGDSObjPipe
 // =====================================================================
 
 static const char *VAR_PIPE = "PIPE";
 static const char *ERR_PIPE_CODER = "Invalid pipe coder: %s";
 
 CdGDSObjPipe::CdGDSObjPipe(): CdGDSObj()
 {
 	fPipeInfo = NULL;
 }
 
 CdGDSObjPipe::~CdGDSObjPipe()
 {
 	if (fPipeInfo)
1763e5bd
 	{
c736b191
 		delete fPipeInfo;
1763e5bd
 		fPipeInfo = NULL;
 	}
c736b191
 }
 
1763e5bd
 CdGDSObjPipe *CdGDSObjPipe::AssignPipe(CdGDSObjPipe &Source)
c736b191
 {
1763e5bd
 	if (fPipeInfo)
 	{
 		delete fPipeInfo;
 		fPipeInfo = NULL;
 	}
 	if (Source.fPipeInfo)
 		fPipeInfo = Source.fPipeInfo->New();
 	fChanged = true;
 	return this;
c736b191
 }
 
 void CdGDSObjPipe::Loading(CdReader &Reader, TdVersion Version)
 {
 	// clear Pipe
 	if (fPipeInfo) delete fPipeInfo;
 	fPipeInfo = NULL;
 
 	// load Pipe object
 	if (Reader.HaveProperty(VAR_PIPE))
 	{
 		UTF8String Coder;
 		Reader[VAR_PIPE] >> Coder;
 		{
 			fPipeInfo = dStreamPipeMgr.Match(*this, RawText(Coder).c_str());
 			if (fPipeInfo==NULL)
     	    	throw ErrGDSObj(ERR_PIPE_CODER, RawText(Coder).c_str());
 			fPipeInfo->LoadStream(Reader, Version);
 		}
 	}
 }
 
 void CdGDSObjPipe::Saving(CdWriter &Writer)
 {
 	CdGDSObj::Saving(Writer);
 	if (fPipeInfo)
 	{
 		Writer[VAR_PIPE] << UTF8Text(fPipeInfo->Coder());
 		fPipeInfo->SaveStream(Writer);
 	}
 }
 
 void CdGDSObjPipe::GetPipeInfo() {}
 
 
 
 // CdGDSLabel
 
1763e5bd
 CdGDSObj *CdGDSLabel::NewObject()
c736b191
 {
 	return new CdGDSLabel;
 }
 
1763e5bd
 void CdGDSLabel::Assign(CdGDSObj &Source, bool Full)
 {
 	if (dynamic_cast<CdGDSLabel*>(&Source))
 	{
 		if (Full)
 			AssignAttribute(Source);
 	} else
 		RaiseInvalidAssign("CdGDSLabel", &Source);
 }
c736b191
 
1c861a99
 
 // =====================================================================
c736b191
 // CdGDSFolder
1c861a99
 // =====================================================================
c736b191
 
e6df59b3
 static const char *ERR_NAME_EXIST   = "The GDS node \"%s\" exists.";
663a9c18
 static const char *ERR_NAME_INVALID = "The GDS node name \"%s\" should not contain '/' or '\x0'.";
e6df59b3
 static const char *ERR_FOLDER_ITEM  = "Invalid index %d.";
 static const char *ERR_FOLDER_NAME  = "Invalid node name \"%s\".";
 static const char *ERR_NO_FOLDER    = "There is not a folder named \"%s\".";
 static const char *ERR_OBJ_INDEX    = "Invalid object index %d in the folder.";
174580a2
 static const char *ERR_INVALID_ASSOC = "The object has been associated with a GDS file!";
 static const char *ERR_INVALID_PATH  = "The GDS node \"%s\" does not exist.";
 static const char *ERR_INVALID_INDEX = "%s(), invalid 'Index' %d.";
c736b191
 
 CdGDSFolder::TNode::TNode()
 {
 	Obj = NULL;
 	StreamID = 0;
 	Flag = FLAG_TYPE_CLASS;
 	_pos = 0;
 }
 
 bool CdGDSFolder::TNode::IsFlagType(C_UInt32 val) const
 {
 	return (Flag & FLAG_TYPE_MASK) == (val & FLAG_TYPE_MASK);
 }
 
 void CdGDSFolder::TNode::SetFlagType(C_UInt32 val)
 {
 	Flag &= ~FLAG_TYPE_MASK;
 	Flag |= (val & FLAG_TYPE_MASK);
 }
 
48c1b22b
 bool CdGDSFolder::TNode::IsFlagAttr(C_UInt32 val) const
 {
 	return (Flag & FLAG_ATTR_MASK) == (val & FLAG_ATTR_MASK);
 }
 
 void CdGDSFolder::TNode::SetFlagAttr(C_UInt32 val)
 {
 	Flag &= ~FLAG_ATTR_MASK;
 	Flag |= (val & FLAG_ATTR_MASK);
 }
 
c736b191
 
 CdGDSFolder::~CdGDSFolder()
 {
     _ClearFolder();
 }
 
1763e5bd
 CdGDSObj *CdGDSFolder::NewObject()
c736b191
 {
     return new CdGDSFolder;
 }
 
1763e5bd
 void CdGDSFolder::Assign(CdGDSObj &Source, bool Full)
 {
 	if (dynamic_cast<CdGDSAbsFolder*>(&Source))
 	{
 		if (Full)
 			AssignAttribute(Source);
 		AssignFolder(*static_cast<CdGDSAbsFolder*>(&Source));
 	} else
 		RaiseInvalidAssign("CdGDSFolder", &Source);
 }
 
 void CdGDSFolder::AssignFolder(CdGDSAbsFolder &Source)
c736b191
 {
 	for (int i=0; i < Source.NodeCount(); i++)
 	{
 		CdGDSObj *obj = Source.ObjItem(i);
1763e5bd
 		CdGDSObj *dst = obj->NewObject();
 		AddObj(obj->Name(), dst);
 		dst->Assign(*obj, true);
c736b191
 	}
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::AddFolder(const UTF8String &Name)
c736b191
 {
1763e5bd
 	_CheckWritable();
c736b191
 	_CheckGDSStream();
 
ef235d43
 	if (!_ValidName(Name))
663a9c18
 		throw ErrGDSObj(ERR_NAME_INVALID, Name.c_str());
c736b191
 	if (_HasName(Name))
663a9c18
 		throw ErrGDSObj(ERR_NAME_EXIST, Name.c_str());
c736b191
 
 	CdGDSFolder *rv = new CdGDSFolder;
 	rv->fFolder = this;
 	rv->fGDSStream = fGDSStream->Collection().NewBlockStream();
 	rv->fGDSStream->AddRef();
 	rv->fChanged = true;
 	rv->AddRef();
 
 	TNode I;
 	I.Name = Name; I.Obj = rv;
 	I.StreamID = rv->fGDSStream->ID();
 	I.SetFlagType(CdGDSFolder::TNode::FLAG_TYPE_FOLDER);
 	fList.push_back(I);
 	fChanged = true;
 
 	return rv;
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::AddObj(const UTF8String &Name, CdGDSObj *val)
c736b191
 {
 	return InsertObj(-1, Name, val);
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::InsertObj(int index, const UTF8String &Name,
c736b191
 	CdGDSObj *val)
 {
174580a2
 	static const char *ERR_INSERT_DIFF_OWNER =
 		"CdGDSFolder::InsertObj, 'val' has a different owner.";
 
c736b191
 	if ((index < -1) || (index > (int)fList.size()))
174580a2
 		throw ErrGDSObj(ERR_INVALID_INDEX, "CdGDSFolder::InsertObj", index);
1763e5bd
 	if (val && (val->fFolder!=NULL) && (val->fFolder!=this))
174580a2
 		throw ErrGDSObj(ERR_INSERT_DIFF_OWNER);
c736b191
 
1763e5bd
 	_CheckWritable();
c736b191
 	_CheckGDSStream();
 
ef235d43
 	if (!_ValidName(Name))
663a9c18
 		throw ErrGDSObj(ERR_NAME_INVALID, Name.c_str());
c736b191
 	if (_HasName(Name))
663a9c18
 		throw ErrGDSObj(ERR_NAME_EXIST, Name.c_str());
c736b191
 
 	TNode I;
 	if (val == NULL)
 	{
 		val = new CdGDSLabel;
 		I.SetFlagType(CdGDSFolder::TNode::FLAG_TYPE_LABEL);
 	} else if (dynamic_cast<CdGDSLabel*>(val))
 	{
 		I.SetFlagType(CdGDSFolder::TNode::FLAG_TYPE_LABEL);
 	} else if (dynamic_cast<CdGDSFolder*>(val))
 	{
 		I.SetFlagType(CdGDSFolder::TNode::FLAG_TYPE_FOLDER);
 	} else if (dynamic_cast<CdGDSVirtualFolder*>(val))
 	{
 		I.SetFlagType(CdGDSFolder::TNode::FLAG_TYPE_VIRTUAL_FOLDER);
 	} else if (dynamic_cast<CdGDSStreamContainer*>(val))
 	{
 		I.SetFlagType(CdGDSFolder::TNode::FLAG_TYPE_STREAM);
 	}
 
 	val->fFolder = this;
 
 	if (val->fGDSStream == NULL)
 	{
 		val->fGDSStream = fGDSStream->Collection().NewBlockStream();
 		val->fGDSStream->AddRef();
 		I.StreamID = val->fGDSStream->ID();
 		val->AddRef();
 		val->SaveToBlockStream();
 	} else
174580a2
 		throw ErrGDSObj(ERR_INVALID_ASSOC);
c736b191
 
 	I.Name = Name; I.Obj = val;
 	if (index < 0)
 		fList.push_back(I);
 	else
 		fList.insert(fList.begin()+index, I);
 	fChanged = true;
 
 	return val;
 }
 
 void CdGDSFolder::MoveTo(int Index, int NewPos)
 {
174580a2
 	static const char *ERR_MOVETO_INVALID_NEWPOS =
 		"CdGDSFolder::MoveTo, invalid 'NewPos' %d.";
 
c736b191
 	if ((Index < -1) || (Index >= (int)fList.size()))
174580a2
 		throw ErrGDSObj(ERR_INVALID_INDEX, "CdGDSFolder::MoveTo", Index);
c736b191
 	if ((NewPos < -1) || (NewPos >= (int)fList.size()))
174580a2
 		throw ErrGDSObj(ERR_MOVETO_INVALID_NEWPOS, NewPos);
1763e5bd
 	_CheckWritable();
c736b191
 
 	if (Index != NewPos)
 	{
 		TNode ND = fList[Index];
 		if (NewPos >= (int)fList.size()-1)
 		{
 			fList.erase(fList.begin() + Index);
 			fList.push_back(ND);
 		} else {
 			fList.erase(fList.begin() + Index);
 			fList.insert(fList.begin() + NewPos, ND);
 		}
 
 		fChanged = true;
 	}
 }
 
814bd0f1
 void CdGDSFolder::UnloadObj(int Index)
 {
 	if ((Index < 0) || (Index >= (int)fList.size()))
 		throw ErrGDSObj(ERR_OBJ_INDEX, Index);
 
 	vector<TNode>::iterator it = fList.begin() + Index;
6eb5180b
 	if (it->Obj)
814bd0f1
 	{
174580a2
 		static const char *ERR_IS_FOLDER = "Not allowed to unload a folder.";
 		static const char *ERR_UNLOAD = "Fails to unload %p.";
 
6eb5180b
 		if (dynamic_cast<CdGDSAbsFolder*>(it->Obj))
174580a2
 			throw ErrGDSObj(ERR_IS_FOLDER);
814bd0f1
 	#ifdef COREARRAY_CODE_DEBUG
 		if (it->Obj->Release() != 0)
174580a2
 			throw ErrGDSObj(ERR_UNLOAD, (void*)(it->Obj));
814bd0f1
 	#else
 		it->Obj->Release();
 	#endif
 		it->Obj = NULL;
 	}
 }
 
 void CdGDSFolder::UnloadObj(CdGDSObj *val)
 {
 	if (val == NULL) return;
 	vector<CdGDSFolder::TNode>::iterator it;
 	int Index = 0;
 	for (it = fList.begin(); it != fList.end(); it++, Index++)
 	{
 		if (it->Obj == val)
 		{
 			UnloadObj(Index);
 			return;
 		}
 	}
 	throw ErrGDSObj();
 }
 
c736b191
 void CdGDSFolder::DeleteObj(int Index, bool force)
 {
 	if ((Index < 0) || (Index >= (int)fList.size()))
e6df59b3
 		throw ErrGDSObj(ERR_OBJ_INDEX, Index);
1763e5bd
 	_CheckWritable();
c736b191
 
 	vector<TNode>::iterator it = fList.begin() + Index;
daaf1c32
 	_LoadItem(*it);
 
c736b191
 	if (it->Obj != NULL)
 	{
 		CdBlockStream *stream = it->Obj->fGDSStream;
 
 		vector<const CdBlockStream*> BL;
 		it->Obj->GetOwnBlockStream(BL);
 
 		// check whether it is a folder
 		if (dynamic_cast<CdGDSFolder*>(it->Obj))
 		{
 			CdGDSFolder *folder = static_cast<CdGDSFolder*>(it->Obj);
 			if (!force && (folder->NodeCount()>0))
 			{
174580a2
 				static const char *ERR_REMOVE_FIRST =
 					"Please delete the item(s) in the folder before removing it.";
 				throw ErrGDSObj(ERR_REMOVE_FIRST);
c736b191
 			}
 			folder->ClearObj(force);
 		}
 
 	#ifdef COREARRAY_CODE_DEBUG
 		if (it->Obj->Release() != 0)
174580a2
 			throw ErrGDSObj(ERR_OBJ_RELEASE, "CdGDSFolder::DeleteObj");
c736b191
 	#else
 		it->Obj->Release();
 	#endif
 
 		if (fGDSStream)
 		{
 			if (stream)
 				fGDSStream->Collection().DeleteBlockStream(stream->ID());
 
 			vector<const CdBlockStream*>::iterator it;
 			for (it=BL.begin(); it != BL.end(); it++)
 			{
 				fGDSStream->Collection().DeleteBlockStream((*it)->ID());
 			}
 		}
 	}
 
daaf1c32
     fList.erase(it);
c736b191
 	fChanged = true;
 }
 
 void CdGDSFolder::DeleteObj(CdGDSObj *val, bool force)
 {
 	if (val == NULL) return;
 	vector<CdGDSFolder::TNode>::iterator it;
 	int Index = 0;
 	for (it = fList.begin(); it != fList.end(); it++, Index++)
 	{
 		if (it->Obj == val)
 		{
 			DeleteObj(Index, force);
 			return;
 		}
 	}
 	throw ErrGDSObj();
 }
 
 void CdGDSFolder::ClearObj(bool force)
 {
1763e5bd
 	_CheckWritable();
 
c736b191
 	vector<CdGDSObj *> lst;
 	for (size_t i=0; i < fList.size(); i++)
 		lst.push_back(ObjItem(i));
 
 	for (size_t i=0; i < lst.size(); i++)
 		DeleteObj(lst[i], force);	
 }
 
 CdGDSFolder & CdGDSFolder::DirItem(int Index)
 {
 	if ((Index < 0) || (Index >= (int)fList.size()))
e6df59b3
 		throw ErrGDSObj(ERR_FOLDER_ITEM, Index);
c736b191
 	CdGDSFolder::TNode &I = fList[Index];
 	_LoadItem(I);
 	if (dynamic_cast<CdGDSFolder*>(I.Obj))
 		return *static_cast<CdGDSFolder*>(I.Obj);
 	else
663a9c18
     	throw ErrGDSObj(ERR_NO_FOLDER, I.Name.c_str());
c736b191
 }
 
663a9c18
 CdGDSFolder & CdGDSFolder::DirItem(const UTF8String &Name)
c736b191
 {
 	CdGDSFolder::TNode &I = _NameItem(Name);
 	_LoadItem(I);
 	if (dynamic_cast<CdGDSFolder*>(I.Obj))
 		return *static_cast<CdGDSFolder*>(I.Obj);
 	else
663a9c18
     	throw ErrGDSObj(ERR_NO_FOLDER, I.Name.c_str());
c736b191
 }
 
bf52e3ba
 CdGDSObj *CdGDSFolder::ObjItem(int Index)
c736b191
 {
 	if ((Index < 0) || (Index >= (int)fList.size()))
e6df59b3
 		throw ErrGDSObj(ERR_OBJ_INDEX, Index);
c736b191
 	CdGDSFolder::TNode &I = fList[Index];
 	_LoadItem(I);
 	return I.Obj;
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::ObjItem(const UTF8String &Name)
c736b191
 {
 	CdGDSFolder::TNode &I = _NameItem(Name);
 	_LoadItem(I);
 	return I.Obj;
 }
 
bf52e3ba
 CdGDSObj *CdGDSFolder::ObjItemEx(int Index)
c736b191
 {
 	if ((Index < 0) || (Index >= (int)fList.size()))
 		return NULL;
 	CdGDSFolder::TNode &I = fList[Index];
 	_LoadItem(I);
 	return I.Obj;
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::ObjItemEx(const UTF8String &Name)
c736b191
 {
 	vector<CdGDSFolder::TNode>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 	{
 		if (it->Name == Name)
 		{
 			_LoadItem(*it);
 			return it->Obj;
 		}
 	}
 	return NULL;
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::Path(const UTF8String &FullName)
c736b191
 {
 	CdGDSObj *rv = PathEx(FullName);
 	if (!rv)
663a9c18
 		throw ErrGDSObj(ERR_INVALID_PATH, FullName.c_str());
c736b191
 	return rv;
 }
 
663a9c18
 CdGDSObj *CdGDSFolder::PathEx(const UTF8String &FullName)
c736b191
 {
663a9c18
 	const char delimit = '/';
 	const char *p = FullName.c_str();
c736b191
 
 	CdGDSObj *rv = this;
 	while ((*p) && (rv))
 	{
 		if (!dynamic_cast<CdGDSAbsFolder*>(rv))
 			return NULL;
 		if (*p == delimit) p ++;
 
663a9c18
 		const char *s = p;
c736b191
 		while ((*p != delimit) && (*p != 0))
 			p ++;
 		if (s == p)
 			return rv;
663a9c18
 		rv = ((CdGDSAbsFolder*)rv)->ObjItemEx(UTF8String(s, p));
c736b191
 	}
 
 	return rv;
 }
 
 int CdGDSFolder::IndexObj(CdGDSObj *Obj)
 {
 	vector<CdGDSObj*> lst;
 	for (size_t i=0; i < fList.size(); i++)
 	{
 		if (Obj == ObjItem(i))
 			return i;
 	}
 	return -1;
 }
 
ceab6642
 bool CdGDSFolder::HasChild(CdGDSObj *Obj, bool Recursive)
c736b191
 {
 	if (Obj == NULL) return false;
 
 	vector<TNode>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 	{
 		if (it->Obj == Obj) return true;
ceab6642
 		if (dynamic_cast<CdGDSAbsFolder*>(it->Obj) && Recursive)
c736b191
 		{
ceab6642
 			if (dynamic_cast<CdGDSAbsFolder*>(it->Obj)->HasChild(Obj, Recursive))
c736b191
 				return true;
         }
 	}
 	return false;
 }
 
 int CdGDSFolder::NodeCount()
 {
 	return fList.size();
 }
 
1c861a99
 static const char *VAR_DIRCNT   = "DIRCNT";
 static const char *VAR_DIRLIST  = "DIRLIST";
 static const char *VAR_DIR_ID   = "ID";
c736b191
 static const char *VAR_DIR_FLAG = "FLAG";
 static const char *VAR_DIR_NAME = "NAME";
 
 void CdGDSFolder::Loading(CdReader &Reader, TdVersion Version)
 {
 	// Load directory inforamtion
 	fList.clear();
 	C_Int32 L = 0;
 	Reader[VAR_DIRCNT] >> L;
 
 	if (L > 0)
 	{
 		Reader[VAR_DIRLIST].BeginStruct();
 		for (C_Int32 k = 0; k < L; k++)
 		{
 			TNode I;
 			Reader.BeginNameSpace();
 			{
 				Reader[VAR_DIR_ID]   >> I.StreamID;
 				Reader[VAR_DIR_FLAG] >> I.Flag;
 				Reader[VAR_DIR_NAME] >> I.Name;
 			}
 			Reader.EndStruct();
 
 			fList.push_back(I);
 		}
 		Reader.EndStruct();
 	}
 
 	// Load the attribute
 	CdGDSAbsFolder::Loading(Reader, Version);
 }
 
 void CdGDSFolder::Saving(CdWriter &Writer)
 {
 	C_Int32 L = fList.size();
 	Writer[VAR_DIRCNT] << L;
 
 	if (L > 0)
 	{
 		Writer[VAR_DIRLIST].NewStruct();
 		{
 			vector<TNode>::iterator it;
 			for (it = fList.begin(); it != fList.end(); it++)
 			{
 				Writer.BeginNameSpace();
 				Writer[VAR_DIR_ID] << it->StreamID;
 				it->_pos = Writer.PropPosition(VAR_DIR_ID);
 				Writer[VAR_DIR_FLAG] << it->Flag;
 				Writer[VAR_DIR_NAME] << it->Name;
 				Writer.EndStruct();
 			}
 		}
 		Writer.EndStruct();
 	}
 
 	// Save the attribute
 	CdGDSAbsFolder::Saving(Writer);
 }
 
 void CdGDSFolder::_ClearFolder()
 {
 	vector<CdGDSFolder::TNode>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 	{
 		if (it->Obj)
 		{
 		#ifdef COREARRAY_CODE_DEBUG
 			if (it->Obj->Release() != 0)
174580a2
 				throw ErrGDSObj(ERR_OBJ_RELEASE, "CdGDSFolder::_ClearFolder");
c736b191
 		#else
 			it->Obj->Release();
 		#endif
 		}
 	}
 	fList.clear();
 }
 
663a9c18
 bool CdGDSFolder::_HasName(const UTF8String &Name)
c736b191
 {
 	vector<CdGDSFolder::TNode>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 		if (it->Name == Name)
 			return true;
 	return false;
 }
 
663a9c18
 bool CdGDSFolder::_ValidName(const UTF8String &Name)
ef235d43
 {
 	for (size_t i=0; i < Name.size(); i++)
 	{
663a9c18
 		char ch = Name[i];
 		if (ch=='/' || ch=='\x0') return false;
ef235d43
 	}
 	return true;
 }
 
663a9c18
 CdGDSFolder::TNode &CdGDSFolder::_NameItem(const UTF8String &Name)
c736b191
 {
 	vector<CdGDSFolder::TNode>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 		if (it->Name == Name)
 			return *it;
663a9c18
 	throw ErrGDSObj(ERR_FOLDER_NAME, Name.c_str());
c736b191
 }
 
 void CdGDSFolder::_LoadItem(TNode &I)
 {
9dad7f5c
 	static const char *ERR_INVALID_GDS_OBJ =
 		"Invalid GDS object (it should be inherited from CdGDSObj).";
 
c736b191
 	if (I.Obj == NULL)
 	{
 		_CheckGDSStream();
9dad7f5c
 		CdBlockStream *IStream = fGDSStream->Collection()[I.StreamID];
 		CdReader Reader(IStream, &GDSFile()->Log());
c736b191
 
 		if (I.IsFlagType(CdGDSFolder::TNode::FLAG_TYPE_LABEL))
 		{
 			// it is a label
 			CdGDSLabel *vObj = new CdGDSLabel;
 			vObj->fFolder = this;
 			I.Obj = vObj;
 
 			Reader.BeginNameSpace();
 			_INTERNAL::CdObject_LoadStruct(*vObj, Reader, 0x100);
 			Reader.EndStruct();
 
 			/// todo: check
9dad7f5c
 			vObj->fGDSStream = IStream;
 			IStream->AddRef();
c736b191
 
 		} else if (I.IsFlagType(CdGDSFolder::TNode::FLAG_TYPE_FOLDER))
 		{
 			// it is a GDS folder
 			CdGDSFolder *vObj = new CdGDSFolder;
 			vObj->fFolder = this;
 			I.Obj = vObj;
 
 			Reader.BeginNameSpace();
60fa5034
 			vObj->LoadStruct(Reader, COREARRAY_CLASS_VERSION);
c736b191
 			Reader.EndStruct();
 
 			/// todo: check
9dad7f5c
 			vObj->fGDSStream = IStream;
 			IStream->AddRef();
c736b191
 
 		} else if (I.IsFlagType(CdGDSFolder::TNode::FLAG_TYPE_VIRTUAL_FOLDER))
 		{
 			// it is a virtual folder linking to another GDS file
 			CdGDSVirtualFolder *vObj = new CdGDSVirtualFolder;
 			vObj->fFolder = this;
 			I.Obj = vObj;
 
 			Reader.BeginNameSpace();
60fa5034
 			vObj->LoadStruct(Reader, COREARRAY_CLASS_VERSION);
c736b191
 			Reader.EndStruct();
 
 			/// todo: check
9dad7f5c
 			vObj->fGDSStream = IStream;
 			IStream->AddRef();
c736b191
 
 		} else if (I.IsFlagType(CdGDSFolder::TNode::FLAG_TYPE_STREAM))
 		{
 			// it is a stream container
 			CdGDSStreamContainer *vObj = new CdGDSStreamContainer;
 			vObj->fFolder = this;
 			I.Obj = vObj;
 
 			/// todo: check
9dad7f5c
 			vObj->fGDSStream = IStream;
 			IStream->AddRef();
c736b191
 
 			Reader.BeginNameSpace();
60fa5034
 			vObj->LoadStruct(Reader, COREARRAY_CLASS_VERSION);
c736b191
 			Reader.EndStruct();
 
 		} else {
 			// it is a class object
 			CdObjRef *obj = NULL;
 
 			try{
9dad7f5c
 				obj = fGDSStream->Collection().ClassMgr()->
c736b191
 					ToObj(Reader, _GDSObjInitProc, fGDSStream, false);
 			}
 			catch (exception &E)
 			{
 				I.Obj = new CdGDSUnknown;
 				I.Obj->fFolder = this;
 				I.Obj->AddRef();
 				throw;
 			}
 
 			if (dynamic_cast<CdGDSObj*>(obj))
 			{
 				I.Obj = static_cast<CdGDSObj*>(obj);
 				I.Obj->fFolder = this;
9dad7f5c
 				I.Obj->fGDSStream = IStream;
 				IStream->AddRef();
c736b191
 			} else {
 				if (obj) delete obj;
9dad7f5c
 				throw ErrGDSObj(ERR_INVALID_GDS_OBJ);
c736b191
 			}
 		}
 
 		I.Obj->AddRef();
 	}
 }
 
 void CdGDSFolder::_UpdateAll()
 {
 	if (fChanged)
 		SaveToBlockStream();
 
 	vector<CdGDSFolder::TNode>::iterator it;
 	for (it = fList.begin(); it != fList.end(); it++)
 	{
 		if (it->Obj)
 		{
 			if (dynamic_cast<CdGDSFolder*>(it->Obj))
a3b2645e
 			{
c736b191
 				static_cast<CdGDSFolder*>(it->Obj)->_UpdateAll();
a3b2645e
 			} else {
 				it->Obj->Synchronize();
 			}
c736b191
 		}
 	}
 }
 
48c1b22b
 vector<CdGDSFolder::TNode>::iterator CdGDSFolder::FindObj(CdGDSObj *Obj)
c736b191
 {
48c1b22b
 	vector<TNode>::iterator it  = fList.begin();
 	vector<TNode>::iterator end = fList.end();
 	for (; it != end; it++)
 	{
 		if (it->Obj == Obj) break;
 	}
 	return it;
 }
 
 vector<CdGDSFolder::TNode>::const_iterator CdGDSFolder::FindObj(
 	const CdGDSObj *Obj) const
 {
 	vector<TNode>::const_iterator it  = fList.begin();
 	vector<TNode>::const_iterator end = fList.end();
 	for (; it != end; it++)
 	{
 		if (it->Obj == Obj) break;
 	}
 	return it;
c736b191
 }
 
 
 // CdGDSVirtualFolder
 
 CdGDSVirtualFolder::CdGDSVirtualFolder(): CdGDSAbsFolder()
 {
 	fLinkFile = NULL;
 	fHasTried = true;
 }
 
 CdGDSVirtualFolder::~CdGDSVirtualFolder()
 {
 	if (fLinkFile)
 	{
 		delete fLinkFile;
 		fLinkFile = NULL;
 	}
 }
 
1763e5bd
 CdGDSObj *CdGDSVirtualFolder::NewObject()
 {
 	return new CdGDSVirtualFolder;
 }
 
 void CdGDSVirtualFolder::Assign(CdGDSObj &Source, bool Full)
 {
 	if (dynamic_cast<CdGDSLabel*>(&Source))
 	{
 		if (Full)
 			AssignAttribute(Source);
 
 		CdGDSVirtualFolder *S = static_cast<CdGDSVirtualFolder*>(&Source);
 		fLinkFileName = S->fLinkFileName;
 		fErrMsg = S->fErrMsg;
 		fHasTried = false;
 		if (fLinkFile)
 		{
 			delete fLinkFile;
 			fLinkFile = NULL;
 		}
 	} else
 		RaiseInvalidAssign("CdGDSVirtualFolder", &Source);
 }
 
c736b191
 bool CdGDSVirtualFolder::IsLoaded(bool Silent)
 {
 	if (!fHasTried)
 	{
 		fHasTried = true;
 
 		CdGDSFile *file = GDSFile();
 		UTF8String fn = file->FileName();
 
 		// remove the file name from 'fn'
 		int i = (int)fn.size() - 1;
 		for (; i >= 0; i--)
 		{
 			if ((fn[i]=='/') || (fn[i]=='\\'))
 				break;
 		}
 		fn.resize(i+1);
 		fn.append(fLinkFileName);
 
 		// open the linking GDS file
 		CdGDSFile *f = new CdGDSFile;
 		try {
 			f->LoadFile(fn.c_str(), file->ReadOnly());
 			f->fRoot.fFolder = fFolder;
 			f->fRoot.fVFolder = this;
 		}
 		catch (exception &E)
 		{
 			fErrMsg = E.what();
 			delete f; f = NULL;
 			if (!Silent)
 				throw;
 		}
 
 		fLinkFile = f;
 	}
 
 	return (fLinkFile != NULL);
 }
 
 void CdGDSVirtualFolder::_CheckLinked()
 {
 	if (!IsLoaded(false))
48c1b22b
 	{
174580a2
 		static const char *ERR_FAIL_LINK = "Fail to link the GDS file '%s'.";
 		throw ErrGDSObj(ERR_FAIL_LINK, fLinkFileName.c_str());
48c1b22b
 	}
c736b191
 }
 
 void CdGDSVirtualFolder::SetLinkFile(const UTF8String &FileName)
 {
 	if (FileName != fLinkFileName)
 	{
 		if (fLinkFile)
 		{
 			CdGDSFile *file = fLinkFile;
 			fLinkFile = NULL;
 			delete file;
 		}
 		fLinkFileName = FileName;
 		fHasTried = false;
 		fChanged = true;
 		fErrMsg.clear();
 	}
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::AddFolder(const UTF8String &Name)
c736b191
 {
 	_CheckLinked();
 	return fLinkFile->Root().AddFolder(Name);
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::AddObj(const UTF8String &Name, CdGDSObj *val)
c736b191
 {
 	_CheckLinked();
 	return fLinkFile->Root().AddObj(Name, val);
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::InsertObj(int index, const UTF8String &Name,
c736b191
 	CdGDSObj *val)
 {
 	_CheckLinked();
 	return fLinkFile->Root().AddObj(Name, val);
 }
 
 void CdGDSVirtualFolder::MoveTo(int Index, int NewPos)
 {
 	_CheckLinked();
 	fLinkFile->Root().MoveTo(Index, NewPos);
 }
 
814bd0f1
 void CdGDSVirtualFolder::UnloadObj(int Index)
 {
 	_CheckLinked();
 	fLinkFile->Root().UnloadObj(Index);
 }
 
 void CdGDSVirtualFolder::UnloadObj(CdGDSObj *val)
 {
 	_CheckLinked();
 	fLinkFile->Root().UnloadObj(val);
 }
 
c736b191
 void CdGDSVirtualFolder::DeleteObj(int Index, bool force)
 {
 	_CheckLinked();
 	fLinkFile->Root().DeleteObj(Index, force);
 }
 
 void CdGDSVirtualFolder::DeleteObj(CdGDSObj *val, bool force)
 {
 	_CheckLinked();
 	fLinkFile->Root().DeleteObj(val, force);
 }
 
 void CdGDSVirtualFolder::ClearObj(bool force)
 {
 	_CheckLinked();
 	fLinkFile->Root().ClearObj(force);
 }
 
 CdGDSObj *CdGDSVirtualFolder::ObjItem(int Index)
 {
 	_CheckLinked();
 	return fLinkFile->Root().ObjItem(Index);
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::ObjItem(const UTF8String &Name)
c736b191
 {
 	_CheckLinked();
 	return fLinkFile->Root().ObjItem(Name);
 }
 
 CdGDSObj *CdGDSVirtualFolder::ObjItemEx(int Index)
 {
 	_CheckLinked();
 	return fLinkFile->Root().ObjItemEx(Index);
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::ObjItemEx(const UTF8String &Name)
c736b191
 {
 	_CheckLinked();
 	return fLinkFile->Root().ObjItemEx(Name);
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::Path(const UTF8String &FullName)
c736b191
 {
 	_CheckLinked();
 	return fLinkFile->Root().Path(FullName);
 }
 
663a9c18
 CdGDSObj *CdGDSVirtualFolder::PathEx(const UTF8String &FullName)
c736b191
 {
 	_CheckLinked();
 	return fLinkFile->Root().PathEx(FullName);
 }
 
 int CdGDSVirtualFolder::IndexObj(CdGDSObj *Obj)
 {
 	_CheckLinked();
 	return fLinkFile->Root().IndexObj(Obj);
 }
 
ceab6642
 bool CdGDSVirtualFolder::HasChild(CdGDSObj *Obj, bool Recursive)
c736b191
 {
 	_CheckLinked();
ceab6642
 	return fLinkFile->Root().HasChild(Obj, Recursive);
c736b191
 }
 
 int CdGDSVirtualFolder::NodeCount()
 {
 	_CheckLinked();
 	return fLinkFile->Root().NodeCount();
 }
 
 static const char *VAR_FILENAME = "FILENAME";
 
 void CdGDSVirtualFolder::Loading(CdReader &Reader, TdVersion Version)
 {
 	UTF8String fn;
 	Reader[VAR_FILENAME] >> fn;
 	CdGDSAbsFolder::Loading(Reader, Version);
 
 	SetLinkFile(fn);
 	fChanged = false;
 }
 
 void CdGDSVirtualFolder::Saving(CdWriter &Writer)
 {
 	Writer[VAR_FILENAME] << fLinkFileName;
 	CdGDSAbsFolder::Saving(Writer);
 }
 
 void CdGDSVirtualFolder::Synchronize()
 {
 	CdGDSAbsFolder::Synchronize();
 	if (fLinkFile)
 		fLinkFile->fRoot.Synchronize();
 }
 
 
 // CdGDSStreamContainer
 
 static const char *VAR_DATA = "DATA";
 
 CdGDSStreamContainer::CdGDSStreamContainer(): CdGDSObjPipe()
 {
 	fBufStream = new CdBufStream(new CdMemoryStream);
 	fBufStream->AddRef();
 	vAllocStream = NULL;
 	fNeedUpdate = false;
 	vAllocID = 0;
 	vAlloc_Ptr = 0;
 }
 
 CdGDSStreamContainer::~CdGDSStreamContainer()
 {
 	CloseWriter();
 	if (fBufStream)
 		fBufStream->Release();
 }
 
 const char *CdGDSStreamContainer::dName()
 {
 	return "dStream";
 }
 
 const char *CdGDSStreamContainer::dTraitName()
 {
 	return "Stream";
 }
 
1763e5bd
 CdGDSObj *CdGDSStreamContainer::NewObject()
c736b191
 {
1763e5bd
 	return (new CdGDSStreamContainer)->AssignPipe(*this);
c736b191
 }
 
1763e5bd
 void CdGDSStreamContainer::Assign(CdGDSObj &Source, bool Full)
c736b191
 {
 	if (dynamic_cast<CdGDSStreamContainer*>(&Source))
 	{
1763e5bd
 		if (Full)
 		{
 			AssignAttribute(Source);
 		}
 		CdGDSStreamContainer *S = static_cast<CdGDSStreamContainer*>(&Source);
 		S->CloseWriter();
 		S->CopyTo(*BufStream());
c736b191
 		CloseWriter();
1763e5bd
 	} else
 		RaiseInvalidAssign("CdGDSStreamContainer", &Source);
c736b191
 }
 
 void CdGDSStreamContainer::Loading(CdReader &Reader, TdVersion Version)
 {
 	CdGDSObjPipe::Loading(Reader, Version);
 
174580a2
 	if (fGDSStream)
c736b191
 	{
 		vAllocID = 0;
 		Reader[VAR_DATA] >> vAllocID;
 		vAlloc_Ptr = Reader.PropPosition(VAR_DATA);
 
 		if (fBufStream)
 			fBufStream->Release();
 		fBufStream = new CdBufStream(fGDSStream->Collection()[vAllocID]);
 		fBufStream->AddRef();
 
 		if (fPipeInfo)
1763e5bd
 			fPipeInfo->PushReadPipe(*fBufStream);
c736b191
 	} else {
174580a2
 		throw ErrGDSStreamContainer(ERR_GDSStream, "CdGDSStreamContainer");
c736b191
 	}
 }
 
 void CdGDSStreamContainer::Saving(CdWriter &Writer)
 {
 	CdGDSObjPipe::Saving(Writer);
 
174580a2
 	if (fGDSStream)
c736b191
 	{
 		if (vAllocStream == NULL)
 		{
 			_CheckGDSStream();
 			vAllocStream = fGDSStream->Collection().NewBlockStream();
 
 			if (fBufStream) fBufStream->Release();
 			fBufStream = new CdBufStream(vAllocStream);
 			fBufStream->AddRef();
 			if (fPipeInfo)
 				fPipeInfo->PushWritePipe(*fBufStream);
 		}
 		TdGDSBlockID Entry = vAllocStream->ID();
 		Writer[VAR_DATA] << Entry;
 		vAlloc_Ptr = Writer.PropPosition(VAR_DATA);
 	} else {
174580a2
 		throw ErrGDSStreamContainer(ERR_GDSStream, "CdGDSStreamContainer");
c736b191
 	}
 }
 
 SIZE64 CdGDSStreamContainer::GetSize()
 {
 	if (fPipeInfo)
 		return fPipeInfo->StreamTotalIn();
 	else
     	return fBufStream->GetSize();
 }
 
 void CdGDSStreamContainer::SetPackedMode(const char *Mode)
 {
ceab6642
 	static const char *ERR_PACKED_MODE =
 		"Invalid packed/compression method '%s'.";
 
 	_CheckWritable();
c736b191
 
 	if (fPipeInfo ? (!fPipeInfo->Equal(Mode)) : true)
 	{
 		if (vAllocStream && fGDSStream && (vAllocStream->GetSize()>0))
 		{
 			Synchronize();
 
 			// total size
 			SIZE64 TotalSize = GetSize();
 
 			if (fPipeInfo) delete fPipeInfo;
 			fPipeInfo = dStreamPipeMgr.Match(*this, Mode);
 			if ((fPipeInfo==NULL) && (strcmp(Mode, "")!=0))
 				throw ErrGDSStreamContainer(ERR_PACKED_MODE, Mode);
 
 			{
 				// automatically release the temporary stream
 				CdStream *TmpStream = new CdTempStream;
 				TdAutoRef<CdBufStream> Output(new CdBufStream(TmpStream));
 				if (fPipeInfo)
 					fPipeInfo->PushWritePipe(*Output);
 
 				CopyTo(*Output, TotalSize);
 				Output.get()->FlushWrite();
 				if (fPipeInfo)
 				{
 					fPipeInfo->ClosePipe(*Output);
 					fPipeInfo->GetStreamInfo(Output.get());
 				}
 
 				// copy
 				vAllocStream->SetPosition(0);
 				vAllocStream->SetSizeOnly(0);
64acf6cb
 				vAllocStream->CopyFrom(*TmpStream, 0, -1);
c736b191
 			}
 
 			vAllocStream->SetPosition(0);
 			if (fBufStream)
 				fBufStream->Release();
 			fBufStream = new CdBufStream(vAllocStream);
 			fBufStream->AddRef();
 			if (fPipeInfo)
 				fPipeInfo->PushReadPipe(*fBufStream);
 
 			// save, since PipeInfo has been changed.
 			SaveToBlockStream();
 		} else {
 			if (fPipeInfo)
 				delete fPipeInfo;
 			fPipeInfo = dStreamPipeMgr.Match(*this, Mode);
 			if ((fPipeInfo==NULL) && (strcmp(Mode, "")!=0))
 				throw ErrGDSStreamContainer(ERR_PACKED_MODE, Mode);
 		}
 	}
 }
 
 void CdGDSStreamContainer::CloseWriter()
 {
 	fBufStream->OnFlush.Clear();
 	fBufStream->FlushWrite();
 	if (fPipeInfo && vAllocStream)
 	{
 		if (fPipeInfo->WriteMode(*fBufStream))
 		{
 			fPipeInfo->ClosePipe(*fBufStream);
 			if (_GetStreamPipeInfo(fBufStream, false))
 				_UpdateStreamPipeInfo(*fGDSStream);
 
 			if (fBufStream)
 				fBufStream->Release();
 			vAllocStream->SetPosition(0);
 			fBufStream = new CdBufStream(vAllocStream);
         	fBufStream->AddRef();
 			if (fPipeInfo)
 				fPipeInfo->PushReadPipe(*fBufStream);
 		}
 	}
 }
 
64acf6cb
 void CdGDSStreamContainer::CopyFromBuf(CdBufStream &Source, SIZE64 Count)
c736b191
 {
 	C_UInt8 Buffer[COREARRAY_STREAM_BUFFER];
 
 	if (Count < 0)
 	{
 		Source.SetPosition(0);
 		Count = Source.GetSize();
 	}
 	while (Count > 0)
 	{
 		ssize_t N = (Count <= (int)sizeof(Buffer)) ? Count : sizeof(Buffer);
 		Source.ReadData((void*)Buffer, N);
 		fBufStream->WriteData((void*)Buffer, N);
 		Count -= N;
 	}
 }
 
 void CdGDSStreamContainer::CopyFrom(CdStream &Source, SIZE64 Count)
 {
 	C_UInt8 Buffer[COREARRAY_STREAM_BUFFER];
 
 	if (Count < 0)
 	{
 		Source.SetPosition(0);
 		Count = Source.GetSize();
 	}
 	while (Count > 0)
 	{
 		ssize_t N = (Count <= (int)sizeof(Buffer)) ? Count : sizeof(Buffer);
 		Source.ReadData((void*)Buffer, N);
 		fBufStream->WriteData((void*)Buffer, N);
 		Count -= N;
 	}
 }
 
 void CdGDSStreamContainer::CopyTo(CdBufStream &Dest, SIZE64 Count)
 {
 	C_UInt8 Buffer[COREARRAY_STREAM_BUFFER];
 
 	if (Count < 0)
 	{
 		fBufStream->SetPosition(0);
 		Dest.SetPosition(0);
 		Count = GetSize();
 	}
 	while (Count > 0)
 	{
 		ssize_t N = (Count <= (int)sizeof(Buffer)) ? Count : sizeof(Buffer);
 		fBufStream->ReadData((void*)Buffer, N);
 		Dest.WriteData((void*)Buffer, N);
 		Count -= N;
 	}
 }
 
 void CdGDSStreamContainer::CopyTo(CdStream &Dest, SIZE64 Count)
 {
 	C_UInt8 Buffer[COREARRAY_STREAM_BUFFER];
 
 	if (Count < 0)
 	{
 		fBufStream->SetPosition(0);
 		Dest.SetPosition(0);
 		Count = GetSize();
 	}
 	while (Count > 0)
 	{
 		ssize_t N = (Count <= (int)sizeof(Buffer)) ? Count : sizeof(Buffer);
 		fBufStream->ReadData((void*)Buffer, N);
 		Dest.WriteData((void*)Buffer, N);
 		Count -= N;
 	}
 }
 
87646568
 void CdGDSStreamContainer::GetOwnBlockStream(vector<const CdBlockStream*> &Out) const
 {
 	Out.clear();
 	if (vAllocStream) Out.push_back(vAllocStream);
 }
 
 void CdGDSStreamContainer::GetOwnBlockStream(vector<CdStream*> &Out)
c736b191
 {
 	Out.clear();
 	if (vAllocStream) Out.push_back(vAllocStream);
 }
 
 
 // CdGDSRoot
 
 CdGDSRoot::CdGDSRoot(): CdGDSFolder()
 {
 	fVFolder = NULL;
 }
 
663a9c18
 UTF8String CdGDSRoot::Name() const
c736b191
 {
 	if (fVFolder)
 	{
 		return fVFolder->Name();
 	} else {
663a9c18
 		return UTF8String();
c736b191
 	}
 }
 
663a9c18
 void CdGDSRoot::SetName(const UTF8String &NewName)
c736b191
 {
174580a2
 	static const char *ERR_ROOT_NAME =
 		"The root of a GDS file is not allowed to have a name.";
c736b191
 	if (fVFolder)
 		fVFolder->SetName(NewName);
174580a2
 	else
 		throw ErrGDSFile(ERR_ROOT_NAME);
c736b191
 }
 
 
 
 // =====================================================================
 // CdGDSUnknown
 // =====================================================================
 
1763e5bd
 CdGDSObj *CdGDSUnknown::NewObject()
 {
 	return new CdGDSUnknown;
 }
 
 void CdGDSUnknown::Assign(CdGDSObj &Source, bool Full)
 {
 	if (dynamic_cast<CdGDSUnknown*>(&Source))
 	{
 		if (Full)
 			AssignAttribute(Source);
 	} else
 		RaiseInvalidAssign("CdGDSUnknown", &Source);
 }
c736b191
 
 void CdGDSUnknown::SaveStruct(CdWriter &Writer, bool IncludeName)
 {
 	// do nothing!
 }
 
 
 
1c861a99
 // =====================================================================
c736b191
 // CdGDSFile
1c861a99
 // =====================================================================
c736b191
 
1c861a99
 static const char *ERR_GDS_OPEN_MODE = "Invalid open mode in CdGDSFile.";
9dad7f5c
 static const char *ERR_GDS_MAGIC     = "Invalid magic number!";
 static const char *ERR_GDS_ENTRY     = "Invalid entry point(0x%04X).";
1c861a99
 static const char *ERR_GDS_SAVE      = "Should save it to a GDS file first!";
c736b191
 
 #ifdef COREARRAY_CODE_DEBUG
1c861a99
 static const char *ERR_GDS_STREAM    = "The GDS file has been saved.";
c736b191
 #endif
 
 const char *CdGDSFile::GDSFilePrefix()
 {
 	return COREARRAY_FILE_PREFIX;
 }
 
 void CdGDSFile::_Init()
 {
 	fVersion = COREARRAY_FILE_VERSION;
 	fRoot.AddRef();
9dad7f5c
 	fCodeStart = strlen(GDSFilePrefix()) + sizeof(TdVersion) + GDS_BLOCK_ID_SIZE;
c736b191
 	fReadOnly = false;
 	fLog = new CdLogRecord; fLog->AddRef();
 	fprocess_id = GetCurrentProcessID();
 }
 
1c861a99
 CdGDSFile::CdGDSFile(): CdBlockCollection()
 {
 	_Init();
 }
c736b191
 
 CdGDSFile::CdGDSFile(const UTF8String &fn, TdOpenMode Mode):
 	CdBlockCollection()
 {
 	_Init();
 	switch (Mode)
 	{
 		case dmCreate:
 			SaveAsFile(fn); break;
 		case dmOpenRead:
 			LoadFile(fn, true); break;
 		case dmOpenReadWrite:
 			LoadFile(fn, false); break;
 		default:
1c861a99
 			throw ErrGDSFile(ERR_GDS_OPEN_MODE);
c736b191
 	}
 }
 
 CdGDSFile::CdGDSFile(const char *fn, TdOpenMode Mode):
 	CdBlockCollection()
 {
 	_Init();
 	switch (Mode)
 	{
 		case dmCreate:
 			SaveAsFile(fn); break;
 		case dmOpenRead:
 			LoadFile(fn, true); break;
 		case dmOpenReadWrite:
 			LoadFile(fn, false); break;
 		default:
1c861a99
 			throw ErrGDSFile(ERR_GDS_OPEN_MODE);
c736b191
 	}
 }
 
5159c111
 CdGDSFile::~CdGDSFile()
c736b191
 {
 	CloseFile();
5159c111
 	if (fLog) fLog->Release();
c736b191
 }
 
9dad7f5c
 void CdGDSFile::LoadStream(CdStream *Stream, bool ReadOnly, bool AllowError)
c736b191
 {
 	// Initialize
 	CloseFile();
 	fLog->List().clear();
 	fReadOnly = ReadOnly;
 
 	// Check the prefix
9dad7f5c
 	const char *prefix = GDSFilePrefix();
 	const size_t L = strlen(prefix);  // should be > 0 always
c736b191
 	vector<char> buf(L);
 	Stream->ReadData((void*)&buf[0], L);
9dad7f5c
 	if (memcmp((void*)prefix, (void*)&buf[0], L) !=0)
 		throw ErrGDSFile(ERR_GDS_MAGIC);
c736b191
 
 	// Load Version
 	fVersion = Stream->R8b();
 	fVersion |= Stream->R8b() << 8;
 
1c861a99
 #ifdef COREARRAY_CODE_USING_LOG
9dad7f5c
 	Log().Add(CdLogRecord::LOG_INFO, "Open a GDS file (File Version: v%d.%d).",
1c861a99
 		int(fVersion >> 8), int(fVersion & 0xFF));
 #endif
 
c736b191
 	// The entry of stream ID
 	TdGDSBlockID Entry;
 	BYTE_LE<CdStream>(Stream) >> Entry;
 
9dad7f5c
 	// Block construction
 	CdBlockCollection::LoadStream(Stream, ReadOnly, AllowError, &Log());
c736b191
 
1c861a99
 #ifdef COREARRAY_CODE_USING_LOG
9dad7f5c
 	Log().Add(CdLogRecord::LOG_INFO,
1c861a99
 		"Load all data stream (%d in total) with an entry id (0x%04X).",
 		(int)BlockList().size(), Entry.Get());
 #endif
 
c736b191
 	if (HaveID(Entry))
 	{
 		fRoot.fGDSStream = (*this)[Entry];
 		fRoot.fGDSStream->AddRef();
 
1c861a99
 	#ifdef COREARRAY_CODE_USING_LOG
174580a2
 		Log().Add(CdLogRecord::LOG_INFO,
 			"Load the root folder from the entry (size: %g).",
1c861a99
 			(double)fRoot.fGDSStream->Size());
 	#endif
 
c736b191
 		CdReader Reader(fRoot.fGDSStream, &Log());
 		Reader.BeginNameSpace();
 		_INTERNAL::CdObject_LoadStruct(fRoot, Reader, fVersion);
 		Reader.EndStruct();
 	} else
1c861a99
 		throw ErrGDSFile(ERR_GDS_ENTRY, Entry.Get());
c736b191
 }
 
 void CdGDSFile::SaveStream(CdStream *Stream)
 {
 	#ifdef COREARRAY_CODE_DEBUG
 	if (fStream != NULL)
1c861a99
 		throw ErrGDSFile(ERR_GDS_STREAM);
c736b191
 	#endif
 
 	// Save Prefix
 	const size_t L = strlen(GDSFilePrefix());
 	Stream->WriteData((void*)GDSFilePrefix(), L);
 
 	// Save Ver
 	Stream->W8b(fVersion & 0xFF);
     Stream->W8b(fVersion >> 8);
 
 	SIZE64 _EntryPos = Stream->Position();
 	BYTE_LE<CdStream>(Stream) << TdGDSBlockID(0);
 
 	CdBlockCollection::WriteStream(Stream);
 	fRoot.fGDSStream = NewBlockStream();
 	fRoot.fGDSStream->AddRef();
 	SIZE64 _NewPos = Stream->Position();
 
 	Stream->SetPosition(_EntryPos);
 	BYTE_LE<CdStream>(Stream) << fRoot.fGDSStream->ID();
 	Stream->SetPosition(_NewPos);
 
 	fRoot.SaveToBlockStream();
 }
 
9dad7f5c
 void CdGDSFile::LoadFile(const UTF8String &fn, bool ReadOnly, bool AllowError)
c736b191
 {
 	TdAutoRef<CdStream> F(new CdFileStream(RawText(fn).c_str(),
 		ReadOnly ? CdFileStream::fmOpenRead : CdFileStream::fmOpenReadWrite));
9dad7f5c
 	LoadStream(F.get(), ReadOnly, AllowError);
c736b191
 	fFileName = fn;
 }
 
9dad7f5c
 void CdGDSFile::LoadFile(const char *fn, bool ReadOnly, bool AllowError)
c736b191
 {
 	TdAutoRef<CdStream> F(new CdFileStream(fn,
 		ReadOnly ? CdFileStream::fmOpenRead : CdFileStream::fmOpenReadWrite));
9dad7f5c
 	LoadStream(F.get(), ReadOnly, AllowError);
c736b191
 	fFileName = UTF8Text(fn);
 }
 
9dad7f5c
 void CdGDSFile::LoadFileFork(const char *fn, bool ReadOnly, bool AllowError)
c736b191
 {
 	TdAutoRef<CdStream> F(new CdForkFileStream(fn,
 		ReadOnly ? CdFileStream::fmOpenRead : CdFileStream::fmOpenReadWrite));
9dad7f5c
 	LoadStream(F.get(), ReadOnly, AllowError);
c736b191
 	fFileName = UTF8Text(fn);
 }
 
 void CdGDSFile::SyncFile()
 {
 	if (fStream == NULL)
1c861a99
 		throw ErrGDSFile(ERR_GDS_SAVE);
c736b191
 	fRoot._UpdateAll();
 }
 
 void CdGDSFile::SaveAsFile(const UTF8String &fn)
 {
 	TdAutoRef<CdStream> F(new CdFileStream(RawText(fn).c_str(),
 		CdFileStream::fmCreate));
 	fFileName = fn;
 	SaveStream(F.get());
 }
 
 void CdGDSFile::SaveAsFile(const char *fn)
 {
 	TdAutoRef<CdStream> F(new CdFileStream(fn, CdFileStream::fmCreate));
 	fFileName = UTF8Text(fn);
 	SaveStream(F.get());
 }
 
 void CdGDSFile::DuplicateFile(const UTF8String &fn, bool deep)
 {
 	if (deep)
 	{
 		CdGDSFile file(fn, CdGDSFile::dmCreate);
1763e5bd
 		file.Root().AssignFolder(Root());
c736b191
 	} else {
 		// create a new file
 		TdAutoRef<CdStream> F(new CdFileStream(RawText(fn).c_str(),
 			CdFileStream::fmCreate));
 
 		// Save Prefix
 		const size_t L = strlen(GDSFilePrefix());
 		F->WriteData((void*)GDSFilePrefix(), L);
 
 		// Save Version
 		F->W8b(fVersion & 0xFF);
 		F->W8b(fVersion >> 8);
 
 		// Save Entry ID
 		BYTE_LE<CdStream>(*F) << fRoot.fGDSStream->ID();
 
 		// for-loop for all stream blocks
 		for (int i=0; i < (int)fBlockList.size(); i++)
 		{
 			TdGDSPos bSize = fBlockList[i]->Size();
 			TdGDSPos sSize = (2*GDS_POS_SIZE +
1c861a99
 				CdBlockStream::TBlockInfo::HEAD_SIZE + bSize) |
c736b191
 				GDS_STREAM_POS_MASK_HEAD_BIT;
 			TdGDSPos sNext = 0;
 			BYTE_LE<CdStream>(*F) <<
 				sSize << sNext << fBlockList[i]->ID() << bSize;
64acf6cb
 			F->CopyFrom(*fBlockList[i], 0, -1);
c736b191
 		}
 	}
 }
 
 void CdGDSFile::DuplicateFile(const char *fn, bool deep)
 {
 	DuplicateFile(UTF8Text(fn), deep);
 }
 
 void CdGDSFile::CloseFile()
 {
 	if (fStream)
 	{
 		SyncFile();
 		fFileName.clear();
 		fLog->List().clear();
 		fRoot.Attribute().Clear();
 		fRoot._ClearFolder();
9dad7f5c
 
c736b191
 		if (fRoot.fGDSStream)
 		{
 			// todo: check
 			fRoot.fGDSStream->Release();
 			fRoot.fGDSStream = NULL;
 		}
 		CdBlockCollection::Clear();
     }
 }
 
 void CdGDSFile::TidyUp(bool deep)
 {
 	bool TempReadOnly = fReadOnly;
 	UTF8String fn, f;
 	fn = fFileName;
 	f = fn + ASC(".tmp");
 	DuplicateFile(f, deep);
 	CloseFile();
 
 	remove(RawText(fn).c_str());
 	rename(RawText(f).c_str(), RawText(fn).c_str());
 	LoadFile(fn, TempReadOnly);
 }
 
 bool CdGDSFile::_HaveModify(CdGDSFolder *folder)
 {
 	if (folder->fChanged) return true;
 
 	vector<CdGDSFolder::TNode>::iterator it;
 	for (it = folder->fList.begin(); it != folder->fList.end(); it++)
 	{
 		if (it->Obj)
 		{
 			if (dynamic_cast<CdGDSFolder*>(it->Obj))
 			{
 				if (_HaveModify(static_cast<CdGDSFolder*>(it->Obj)))
 					return true;
 			} else
 				if (it->Obj->fChanged) return true;
 		}
 	}
 	return false;
 }
 
 bool CdGDSFile::Modified()
 {
 	return _HaveModify(&fRoot);
 }
 
 SIZE64 CdGDSFile::GetFileSize()
 {
     return fStreamSize;
 }
 
 int CdGDSFile::GetNumOfFragment()
 {
 	return CdBlockCollection::NumOfFragment();
 }
 
 bool CdGDSFile::IfSupportForking()
 {
 	return (dynamic_cast<CdForkFileStream*>(fStream) != NULL);
 }
 
 TProcessID CdGDSFile::GetProcessID()
 {
 	return fprocess_id;
 }
 
 void CdGDSFile::SetProcessID()
 {
 	fprocess_id = GetCurrentProcessID();
 }