diff --git a/niflib_internal.cpp b/niflib_internal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6436e0f3a1826c042ad48117b6c7bcb5957cef73 --- /dev/null +++ b/niflib_internal.cpp @@ -0,0 +1,581 @@ +/* Copyright (c) 2005, NIF File Format Library and Tools +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NIF File Format Library and Tools + project nor the names of its contributors may be used to endorse + or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "niflib_internal.h" + +extern unsigned int blocks_in_memory; + +/*********************************************************** + * ABlock methods + **********************************************************/ + +ABlock::ABlock() : _block_num(-1), _ref_count(0) { + blocks_in_memory++; + } + +ABlock::~ABlock() { + blocks_in_memory--; + + // Delete all attributes + for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { + delete _attr_vect[i].ptr(); + } + + //cout << endl << "Removing cross reference to " << this << " from " << uint(_cross_refs.size()) << " blocks"; + // Inform all cross-linked blocks that have added their references that this block is dying + list<IBlock*>::iterator it; + for (it = _cross_refs.begin(); it != _cross_refs.end(); ++it) { + //IBlockInternal * blk_int = (IBlockInternal*)(*it)->QueryInterface(BlockInternal); + //if ( blk_int != NULL ) { + ((ABlock*)(*it))->RemoveCrossLink(this); + //} + } +} + +//void ABlock::AddAttr( AttrType type, string const & name, unsigned int first_ver, unsigned int last_ver ) { +// IAttr * attr; +// +// switch( type ) { +// case attr_int: +// attr = new IntAttr( name, this, first_ver, last_ver ); +// break; +// case attr_short: +// attr = new ShortAttr( name, this, first_ver, last_ver ); +// break; +// case attr_byte: +// attr = new ByteAttr( name, this, first_ver, last_ver ); +// break; +// case attr_float: +// attr = new FloatAttr( name, this, first_ver, last_ver ); +// break; +// case attr_float3: +// attr = new Float3Attr( name, this, first_ver, last_ver ); +// break; +// case attr_string: +// attr = new StringAttr( name, this, first_ver, last_ver ); +// break; +// case attr_link: +// attr = new LinkAttr( name, this, first_ver, last_ver ); +// break; +// case attr_flags: +// attr = new FlagsAttr( name, this, first_ver, last_ver ); +// break; +// case attr_matrix33: +// attr = new MatrixAttr( name, this, first_ver, last_ver ); +// break; +// case attr_linkgroup: +// attr = new LinkGroupAttr( name, this, first_ver, last_ver ); +// break; +// case attr_bones: +// attr = new BoneAttr( name, this, first_ver, last_ver ); +// break; +// case attr_bbox: +// attr = new BBoxAttr( name, this, first_ver, last_ver ); +// break; +// case attr_condint: +// attr = new CIntAttr( name, this, first_ver, last_ver ); +// break; +// case attr_vertmode: +// attr = new VertModeAttr( name, this, first_ver, last_ver ); +// break; +// case attr_lightmode: +// attr = new LightModeAttr( name, this, first_ver, last_ver ); +// break; +// case attr_texsource: +// attr = new TexSourceAttr( name, this, first_ver, last_ver ); +// break; +// case attr_pixellayout: +// attr = new PixelLayoutAttr( name, this, first_ver, last_ver ); +// break; +// case attr_mipmapformat: +// attr = new MipMapFormatAttr( name, this, first_ver, last_ver ); +// break; +// case attr_alphaformat: +// attr = new AlphaFormatAttr( name, this, first_ver, last_ver ); +// break; +// case attr_controllertarget: +// attr = new ControllerTargetAttr( name, this, first_ver, last_ver ); +// break; +// case attr_skeletonroot: +// attr = new SkeletonRootAttr( name, this, first_ver, last_ver ); +// break; +// case attr_particlegroup: +// attr = new ParticleGroupAttr( name, this, first_ver, last_ver ); +// break; +// case attr_lodinfo: +// attr = new LODInfoAttr( name, this, first_ver, last_ver ); +// break; +// case attr_vector3: +// attr = new Vector3Attr( name, this, first_ver, last_ver ); +// break; +// case attr_color3: +// attr = new Color3Attr( name, this, first_ver, last_ver ); +// break; +// case attr_parent: +// attr = new ParentAttr( name, this, first_ver, last_ver ); +// break; +// case attr_unk292bytes: +// attr = new Unk292BytesAttr( name, this, first_ver, last_ver ); +// break; +// case attr_bool: +// attr = new BoolAttr( name, this, first_ver, last_ver ); +// break; +// case attr_targetgroup: +// attr = new TargetGroupAttr( name, this, first_ver, last_ver ); +// break; +// case attr_shader: +// attr = new ShaderAttr( name, this, first_ver, last_ver ); +// break; +// case attr_modifiergroup: +// attr = new ModifierGroupAttr( name, this, first_ver, last_ver ); +// break; +// case attr_color4: +// attr = new Color4Attr( name, this, first_ver, last_ver ); +// break; +// case attr_quaternion: +// attr = new QuaternionAttr( name, this, first_ver, last_ver ); +// break; +// case attr_emitterobject: +// attr = new EmitterObjectAttr( name, this, first_ver, last_ver ); +// break; +// case attr_selflink: +// attr = new SelfLinkAttr( name, this, first_ver, last_ver ); +// break; +// case attr_crossref: +// attr = new CrossRefAttr( name, this, first_ver, last_ver ); +// break; +// default: +// cout << type << endl; +// throw runtime_error("Unknown attribute type requested."); +// }; +// +// _attr_map[name] = attr_ref(attr); +// _attr_vect.push_back(attr_ref(attr)); +//} + +attr_ref ABlock::GetAttr(string const & attr_name) const { + map<string, attr_ref>::const_iterator it; + it = _attr_map.find(attr_name); + if (it == _attr_map.end()) { + //cout << "Requested Attribute does not exist: " << attr_name << endl; + return attr_ref(NULL); + } else { + return attr_ref((*it).second); + } + //return _attr_map[attr_name]; +} + + +vector<attr_ref> ABlock::GetAttrs() const { + return _attr_vect; +} + +blk_ref ABlock::GetParent() const { + if (_parents.size() > 0 ) { + //Give preferential treatment to the first node parent + for ( uint i = 0; i < _parents.size(); ++i ) { + if ( _parents[i]->QueryInterface( ID_NODE ) ) { + return _parents[i]; + } + } + return blk_ref(_parents[0]); + } else { + return blk_ref(-1); + } +} + +void ABlock::Read( istream& in, unsigned int version ) { + + //Read Attributes + for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { + //_attr_vect[i]->Read( in, version ); + //if ( _attr_vect[i]->GetType() != "bones" ) { + // cout << " " << _attr_vect[i]->GetName() << ": " << _attr_vect[i]->asString() << endl; + //} + } + //map<string, attr_ref>::iterator it; + //it = _attr_map.find("Scale"); + //if (it != _attr_map.end()) { + // if ( _attr_map["Scale"]->asFloat() != 1.0f ) { + // cout << "\a Non-1.0 Scale found!!!" << endl; + // cin.get(); + // } + //} +} + +void ABlock::Write( ostream& out, unsigned int version ) const { + + //Write Attributes + for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { + //cout << "Writing " << blk_ref(this) << " " << _attr_vect[i]->GetName() << endl; + //_attr_vect[i]->Write( out, version ); + } +} + +string ABlock::asString() const { + // Create a stringstream and set the floating point format + // fixed notation with one decimal place + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + //Output the first parent of this block + out << "Parent: " << GetParent() << endl; + + //Output Attributes + for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { + out << _attr_vect[i]->GetName() << ": " << _attr_vect[i]->asString() << endl; + } + + //Return result as a string + return out.str(); +} + +void ABlock::AddRef() { + ++_ref_count; + //cout << GetBlockType() << " Reference increased to: " << _ref_count << endl; +} + +void ABlock::SubtractRef() { + --_ref_count; + //cout << GetBlockType() << " Reference decreased to: " << _ref_count << endl; + + if ( _ref_count < 1 ) { + //cout << "Block #" << this->GetBlockNum() << " - " << this->GetBlockType() << ": Deleting block now." << endl; + delete this; + } +} + +void ABlock::IncCrossRef( IBlock * block ) { + _cross_refs.push_back(block); +} + +void ABlock::DecCrossRef( IBlock * block ) { + _cross_refs.remove(block); +} + +blk_ref ABlock::Clone( unsigned int version ) { + //Create a string stream to temporarily hold the state-save of this block + stringstream tmp; + + cout << "Getting a list of all the links in this block" << endl; + + //Get a list of all the links in this block + list<blk_ref> link_list = this->GetLinks(); + + cout << "Putting the links into a vector & resetting block numbers" << endl; + + //Put the link into a vector and reset the block number of each of these blocks to correspond to its position in the vector + int i = 0; + vector<blk_ref> link_vec( link_list.size() ); + list<blk_ref>::iterator it; + for ( it = link_list.begin(); it != link_list.end(); ++it ) { + ((ABlock*)it->get_block())->SetBlockNum(i); + link_vec[i] = *it; + ++i; + } + + cout << "Creating new block of same type" << endl; + + //Create a new block of the same type + blk_ref clone = CreateBlock( GetBlockType() ); + + cout << "Writing this block's data to the stream" << endl; + + //Write this block's data to the stream + Write( tmp, version ); + + cout << "Reading the data back from the stream" << endl; + + //Read the data back from the stream + ABlock * clone_ab = (ABlock*)clone.get_block(); + clone_ab->Read( tmp, version ); + + cout << "Fixing links of clone" << endl; + + //Fix the links of the clone using the original link list + clone_ab->FixLinks( link_vec ); + + cout << "Done Cloning" << endl; + + //return new block + return clone; +} + +list<blk_ref> ABlock::GetLinks() const { + list<blk_ref> links; + + //Search through all attributes for any links and add them to the list + vector<attr_ref>::const_iterator it; + for ( it = _attr_vect.begin(); it != _attr_vect.end(); ++it ) { + if ( (*it)->HasLinks() == true ) { + list<blk_ref> link_list = (*it)->asLinkList(); + links.merge( link_list ); + } + } + + //Remove NULL links + links.remove( blk_ref(-1) ); + + return links; +} + +void ABlock::FixLinks( const vector<blk_ref> & blocks ) { + //Search through all attributes for any links and fix their references based on the list + vector<attr_ref>::iterator it; + for ( it = _attr_vect.begin(); it != _attr_vect.end(); ++it ) { + if ( (*it)->HasLinks() == true ) { + //Get the links out of this attribute and fix each one + list<blk_ref> links = *it; + list<blk_ref>::iterator it2; + for (it2 = links.begin(); it2 != links.end(); ++it2) { + int index = it2->get_index(); + if (index < int(blocks.size()) && index >= 0 ) { + *it2 = blocks[index]; + } + } + //Now clear the old links and send in the new ones + (*it)->ClearLinks(); + (*it)->AddLinks(links); + } + } +} + +//-- Internal Functions --// + +void ABlock::AddChild( IBlock * new_child ) { + //If the poiner is null, do nothing + if ( new_child == NULL ) + return; + + //Register this block as a parent of new_child + ((ABlock*)new_child)->AddParent( this ); + //IBlockInternal * bk_intl = (IBlockInternal*)new_child->QueryInterface( BlockInternal ); + //if ( bk_intl != NULL ) { + // bk_intl->AddParent( this ); + //} +} +void ABlock::RemoveChild( IBlock * old_child ) { + //If the poiner is null, do nothing + if ( old_child == NULL ) + return; + + //Add this block to first child as a parent + ((ABlock*)old_child)->RemoveParent( this ); + //IBlockInternal * bk_intl = (IBlockInternal*)old_child->QueryInterface( BlockInternal ); + //if ( bk_intl != NULL ) { + // bk_intl->RemoveParent( this ); + //} +} + +void ABlock::RemoveCrossLink( IBlock * block_to_remove ) { + //Ask all attributes to remove any cross links they might have to the specified block + //cout << endl << "ABlock::RemoveCrossLink()"; + vector<attr_ref>::iterator it; + for ( it = _attr_vect.begin(); it != _attr_vect.end(); ++it ) { + //((AAttr*)it->ptr())->RemoveCrossLinks( block_to_remove ); + } +} + + +void ABlock::AddParent( IBlock * new_parent) { + //Don't add null parents + if ( new_parent != NULL ) + _parents.push_back( new_parent ); +} + +void ABlock::RemoveParent( IBlock * match ) { + //Remove just one copy of the parent if there is one, incase a temporary reference is floating around + vector<IBlock*>::iterator it = find< vector<IBlock*>::iterator, IBlock*>( _parents.begin(), _parents.end(), match); + if (it != _parents.end() ) { + _parents.erase( it ); + } + + /*cout << blk_ref(this) << " Parents Remaining:" << endl << " "; + for ( it = _parents.begin(); it != _parents.end(); ++it ) { + cout << blk_ref(*it) << " "; + } + cout << endl;*/ + + + //for (it = _parents.begin(); it != _parents.end(); ) { + // if ( *it == match ) + // _parents.erase( it ); + // else + // ++it; + //} +} + +//--Link Classes--// + +//Constructor +//It is required for a LinkGroup to be aware of the block it is part of + +void Link::SetIndex( const int new_index ) { + //This function is for the initial file read. It records the index of the block which + //will later be resolved to a link once all the blocks have been read + + //If there is already a link, kill it + if ( link.is_null() == false ) { + KillLink(); + link.nullify(); + } + + index = new_index; +} + +void Link::SetLink( const blk_ref & new_link ) { + if ( link != new_link ) { + //Kill previous link + KillLink(); + + //Set New Link + link = new_link; + InitLink(); + } +} + +void Link::Fix( const vector<blk_ref> & blocks ) { + //The purpouse of this function is to convert the block index to a link + //to the corresponding block. + + //Ensure that there is an index to convert + if (index == -1 ) { + return; + } + + if ( index < int(blocks.size()) && index >= 0 ) { + link = blocks[index]; + InitLink(); + } +} + +void Link::SetOwner( IBlock * owner ) { + if ( owner != NULL ) { + throw runtime_error("The owner for this Link is already set."); + } + _owner = owner; +} + +void Link::InitLink() { + //Ensure that the owner is set + if ( _owner == NULL ) { + throw runtime_error("You must specify an owner before you can store a blk_ref in a Link."); + } + //Add parent at new link site + IBlock * target = link.get_block(); + if ( target != NULL ) { + //Get internal interface + ((ABlock*)target)->AddParent( _owner ); + } +} +void Link::KillLink() { + //Remove parent at previous location + IBlock * target = link.get_block(); + if ( target != NULL ) { + ((ABlock*)target)->RemoveParent( _owner ); + } +} + +//--CrossRef Classes--// + +void CrossRef::SetIndex( const int new_index ) { + //This function is for the initial file read. It records the index of the block which + //will later be resolved to a reference once all the blocks have been read + + //If there is already a reference, kill it + if ( ref != NULL ) { + KillRef(); + ref = NULL; + } + + index = new_index; +} + +void CrossRef::SetCrossRef( IBlock * new_ref ) { + if ( ref != new_ref ) { + //Kill previous link + KillRef(); + + //Set New Link + ref = new_ref; + InitRef(); + } +} + +void CrossRef::LostRef( IBlock * match ) { + //This function's purpouse is to inform this CrossRef that the block it is referencing has died + //It will be called on every CrossRef in this block, we must check to see if this is the one that + //the message is meant for + if ( ref == match ) { + //Simply set it to NULL do not call KillRef because the reference is already dead + ref = NULL; + } +} + +void CrossRef::Fix( const vector<blk_ref> & blocks ) { + //The purpouse of this function is to convert the block index to a reference + //to the corresponding block. + + if (index < int(blocks.size()) && index >= 0 ) { + ref = blocks[index].get_block(); + index = -1; + InitRef(); + } +} + +void CrossRef::SetOwner( IBlock * owner ) { + if ( owner != NULL ) { + throw runtime_error("The owner for this Link is already set."); + } + _owner = owner; +} + +void CrossRef::InitRef() { + //Inform target block that it is being cross referenced + //Ensure that the owner is set + if ( _owner == NULL ) { + throw runtime_error("You must specify an owner before you can store an IBlock * in a CrossRef."); + } + if ( ref != NULL ) { + //Get internal interface + ((ABlock*)ref)->IncCrossRef( _owner ); + } +} +void CrossRef::KillRef() { + //Inform target block that it is no longer being cross referenced + if ( ref != NULL ) { + ((ABlock*)ref)->IncCrossRef( _owner ); + } +} + diff --git a/niflib_internal.h b/niflib_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..a797303781e45f54cb652054bedf06aa92f1bfb1 --- /dev/null +++ b/niflib_internal.h @@ -0,0 +1,214 @@ +/* Copyright (c) 2005, NIF File Format Library and Tools +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NIF File Format Library and Tools + project nor the names of its contributors may be used to endorse + or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef _INTERNAL_H_ +#define _INTERNAL_H_ + +#include "niflib.h" +#include <iomanip> +#include <sstream> + +typedef unsigned char byte; +typedef unsigned short ushort; +typedef unsigned int uint; + +const char ATTRERR[] = "Attribute type Missmatch."; + +//Inernal Attribute Abstract Class +class AAttr : public IAttr { +public: + AAttr( string const & name, IBlock * owner ) : _name(name), _owner(owner) {} + ~AAttr() {} + string GetName() const { return _name; } + //Getters + int asInt() const { throw runtime_error(ATTRERR); } + float asFloat() const { throw runtime_error(ATTRERR); } + Float3 asFloat3() const { throw runtime_error(ATTRERR); } + Float4 asFloat4() const { throw runtime_error(ATTRERR); } + Matrix33 asMatrix33() const { throw runtime_error(ATTRERR); } + blk_ref asLink() const { throw runtime_error(ATTRERR); } + TexSource asTexSource() const { throw runtime_error(ATTRERR); } + BoundingBox asBoundingBox() const { throw runtime_error(ATTRERR); } + TexDesc asTexDesc() const { throw runtime_error(ATTRERR); } + list<blk_ref> asLinkList() const { throw runtime_error(ATTRERR); } + //Setters + void Set(int) { throw runtime_error(ATTRERR); } + void Set(float) { throw runtime_error(ATTRERR); } + void Set(Float3 const &) { throw runtime_error(ATTRERR); } + void Set(Float4 const &) { throw runtime_error(ATTRERR); } + void Set(string const &) { throw runtime_error(ATTRERR); } + void Set(Matrix33 const &) { throw runtime_error(ATTRERR); } + void Set(blk_ref const &) { throw runtime_error(ATTRERR); } + void Set(TexSource const &) { throw runtime_error(ATTRERR); } + void Set(BoundingBox const &) { throw runtime_error(ATTRERR); } + void Set(TexDesc const &) { throw runtime_error(ATTRERR); } + //Link functions + bool HasLinks() const { return false; } + void AddLink( blk_ref const & block ) { cout << "AddLink" << endl; throw runtime_error(ATTRERR); } + void AddLinks( list<blk_ref> const & new_links ) { cout << "AddLinkS" << endl; throw runtime_error(ATTRERR); } + void ClearLinks() { cout << "ClearLinks" << endl; throw runtime_error(ATTRERR); } + void RemoveLinks( blk_ref const & block ) { cout << "RemoveLinks" << endl; throw runtime_error(ATTRERR); } + blk_ref FindLink( string const & block_type ) const { cout << "FindLink" << endl; throw runtime_error(ATTRERR); } +protected: + string _name; + IBlock * _owner; +}; + +//Internal Abstract Block Class + +class ABlock : public IBlock { +public: + ABlock(); + ~ABlock(); + blk_ref Clone( unsigned int version = 0xFFFFFFFF ); + //void AddAttr( AttrType type, string const & name, unsigned int first_ver = 0, unsigned int last_ver = 0xFFFFFFFF ); + attr_ref GetAttr(string const & attr_name) const; + vector<attr_ref> GetAttrs() const; + int GetBlockNum() const { return _block_num; } + bool IsControllable() const { return false; } + bool IsController() const { return false; } + string asString() const; + + //Links + blk_ref GetParent() const; + list<blk_ref> GetLinks() const; + + //Reference Counting + void AddRef(); + void SubtractRef(); + + //Interface + void * QueryInterface( int id ) { + /*if ( id == BlockInternal ) { + return (void*)static_cast<IBlockInternal*>(this);; + } else {*/ + return NULL; + /*}*/ + } + + void const * QueryInterface( int id ) const { + /*if ( id == BlockInternal ) { + return (void const *)static_cast<IBlockInternal const *>(this);; + } else {*/ + return NULL; + /*}*/ + } + + //--Internal Functions--// + void AddParent( IBlock * new_parent); + void RemoveParent( IBlock * match ); + void SetBlockNum( int n ) { _block_num = n; } + virtual void FixLinks( const vector<blk_ref> & blocks ); + void SetBlockTypeNum( int n ) { _block_type_num = n; } + int GetBlockTypeNum() { return _block_type_num; } + + void AddChild( IBlock * new_child ); + void RemoveChild( IBlock * old_child ); + + virtual void RemoveCrossLink( IBlock * block_to_remove ); + + void IncCrossRef( IBlock * block ); + void DecCrossRef( IBlock * block ); + virtual void ReassignCrossRefs( const map<string,blk_ref> & name_map ) {} + + virtual void Read( istream& in, unsigned int version ); + virtual void Write( ostream& out, unsigned int version ) const; +protected: + map<string, attr_ref> _attr_map; + vector<attr_ref> _attr_vect; + int _block_num; + int _block_type_num; + unsigned int _ref_count; + vector<IBlock*> _parents; + list<IBlock*> _cross_refs; +}; + +//--Link Classes--// + +class Link { +public: + //Constructors + Link () : _owner(NULL), index(-1) {} + Link ( IBlock * owner) : _owner(owner), index(-1) {} + //Destructor + ~Link() { KillLink(); } + void SetIndex( const int new_index ); + void Nullify() { + KillLink(); + link.nullify(); + }; + blk_ref GetLink() const { return link; } + void SetLink( const blk_ref & new_link ); + void Fix( const vector<blk_ref> & blocks ); + void SetOwner( IBlock * owner ); +private: + IBlock * _owner; + blk_ref link; + int index; + void InitLink(); + void KillLink(); +}; + +//--CrossRef Classes--// + +class CrossRef { +public: + //Constructors + CrossRef () : _owner(NULL), ref(NULL), index(-1) {} + CrossRef ( IBlock * owner) : _owner(owner), ref(NULL), index(-1) {} + //Destructor + ~CrossRef() { KillRef(); } + void SetIndex( const int new_index ); + void Nullify() { + KillRef(); + ref = NULL; + } + IBlock * GetCrossRef() const { return ref; } + void SetCrossRef( IBlock * new_ref ); + void LostRef( IBlock * match ); + void Fix( const vector<blk_ref> & blocks ); + void SetOwner( IBlock * owner ); +private: + IBlock * _owner; + IBlock * ref; + int index; + void InitRef(); + void KillRef(); +}; + + +struct HeaderString { + string header; +}; + +#endif \ No newline at end of file