/********************************************************************** * * Master.h * Copyright (C) 2003 UNESCO * * A component of the Greenstone digital library software * from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *********************************************************************/ /////////////////////////////////////// */ // Master.h: Master File Record object /////////////////////////////////////// */ #ifndef __MASTER_RECORD_H__ #define __MASTER_RECORD_H__ #include "BlkFile.h" #include #include #include // Length in bytes of master file header #define MFCTLLEN sizeof(SMfHeader)+sizeof(SMfHeader) // Length in bytes of master file header const int MFALIGN = 2; // Master file record alignment const int MFBLKSIZE = 512; // Master file block size typedef short int ISIS_INT; typedef long int ISIS_LONG; #ifdef UNIX_BIREME //Length of Leader in master record inline int GetLeaderSize() { return (2*sizeof(ISIS_LONG)+6*sizeof(ISIS_INT)); } // Mini Leader length guaranteed to be in same block inline int GetMinLeaderSize() { return (2*sizeof(ISIS_LONG)+4*sizeof(ISIS_INT)); } #else //Length of Leader in master record inline int GetLeaderSize() { return (2*sizeof(ISIS_LONG)+5*sizeof(ISIS_INT)); } // Mini Leader length guaranteed to be in same block inline int GetMinLeaderSize() { return (2*sizeof(ISIS_LONG)+3*sizeof(ISIS_INT)); } #endif // Size of Mfn and Mfrl in the leader part inline int GetSubLeaderSize() { return sizeof(ISIS_LONG)+sizeof(ISIS_INT); } inline int GetDirEntrySize() { return (3*sizeof(ISIS_INT)); } const TCHAR SYSRSEP = TCHAR('%'); // Repeatable field separator const TCHAR SUBFIELD_SEP = TCHAR('^'); // Subfield separator //////////////////////////////////////// // Directory entry aggregate structure // struct DirEntry { ISIS_INT tag_; ISIS_INT pos_; ISIS_INT len_; DirEntry() : tag_(0), pos_(0), len_ (0) { } DirEntry(ISIS_INT tag, ISIS_INT pos, ISIS_INT len) : tag_(tag), pos_(pos), len_ (len) { } bool operator==(const DirEntry& rhs) const { if (tag_!=rhs.tag_ || pos_!=rhs.pos_ || len_!=rhs.len_) return false; return true; } bool operator!=(const DirEntry& rhs) const { if (tag_!=rhs.tag_ || pos_!=rhs.pos_ || len_!=rhs.len_) return true; return false; } }; ////////////////////////////////////////////////////////////////////////// // Data Master record aggregate structure // struct LeaderAndDirectory { ISIS_LONG mfn_; // Master file number ISIS_INT mfrl_; // Record length ISIS_LONG mfbwb_; // Backward pointer block number ISIS_INT mfbwp_; // Backward pointer offset ISIS_INT base_; // Offset to begining of variable fields ISIS_INT nvf_; // Number of directory entries ISIS_INT status_; // 1 = DELETED std::vector dir_; // Directory LeaderAndDirectory() { Clear(); } LeaderAndDirectory(const LeaderAndDirectory& src) { Copy(src); } LeaderAndDirectory& operator=(const LeaderAndDirectory& rhs) { if (&mfn_ != &rhs.mfn_) { Copy(rhs); } return *this; } void Copy(const LeaderAndDirectory& rhs) { mfn_ = rhs.mfn_; mfrl_ = rhs.mfrl_; mfbwb_ = rhs.mfbwb_; mfbwp_ = rhs.mfbwp_; base_ = rhs.base_; nvf_ = rhs.nvf_; status_ = rhs.status_; dir_ = rhs.dir_; } void Clear() { mfn_ = mfrl_ = mfbwb_ = mfbwp_ = base_ = nvf_ = status_ = 0; dir_.clear(); } bool operator==(const LeaderAndDirectory& rhs) const; bool operator!=(const LeaderAndDirectory& rhs) const; int GetFieldSize(); }; cstringstream& operator<<(cstringstream& s, const LeaderAndDirectory& leader); cstringstream& operator>>(cstringstream& s, LeaderAndDirectory& leader); //////////////////////////////////////////////////////////// // ///////////////////////////////// // Data master file record class // typedef std::map TAG2FIELD; class MfFile; class MstFile; class IsisDb; class ACE_InputCDR; class ACE_OutputCDR; class UMfRecord; class MfRecord { friend class MfFile; friend class MstFile; friend class IsisDb; friend class UMfRecord; friend int operator>>(ACE_InputCDR& cdr, MfRecord& mfr); friend int operator<<(ACE_OutputCDR& cdr, MfRecord& mfr); protected: CFdt* pFdt_; // Use a copy of the FDT cstring record_; // Record in continuous storage // always as ANSI! LeaderAndDirectory leader_directory_; TAG2FIELD fields_; std::vector tags_; static char m_buf[MFBLKSIZE]; // Buffer to hold 1 File block protected: // Additional data short int state_; // Record state in memory long mfb_read_; // Record was read at Block number [1...] int mfp_read_; // Record was read at position in block int mflen_read_; // Record length was when record read protected: void Copy(const MfRecord& rhs); void AddToRecord(const char* p, int len); int AddDirEntry(const DirEntry& d); int AddDirEntry(int tag, int pos, int len); int DelDirEntry(int i); void SetMfrl(int mfrl); void SetMfbwb(long mfbwb); void SetMfbwp(int mfbwp); void SetBase(int base); void SetNvf(int nvf); void SetStatus(int s); int SetDirEntry(int i, int tag, int pos, int len); int SetDirEntry(int i, const DirEntry& d); void SetMfbRead(long b); void SetMfpRead(int pos); void SetMflenRead(int len); void SetSubLeaderAndDirectory(const char* p, int len); void MakeTagToFieldMap(); void MakeTagVector(); long ComputeMfrl(); void Copy(UMfRecord& rhs); public: enum { Record_Empty, Record_Read, Record_Changed, Record_Created }; public: //----------------- // Public Interface //----------------- MfRecord(CFdt* pFdt=NULL); // Default constructor virtual ~MfRecord(); // Destructor MfRecord(const MfRecord& rhs); // Copy constructor MfRecord& operator=(const MfRecord& rhs); // Assignment MfRecord(const UMfRecord& umfr); MfRecord& operator=(const UMfRecord& rhs); void Clear(); void ClearData(); void ReadLeader(MfFile& f, long daddr); bool Read (MfFile& f, long mfb, int mfp); void Write(MfFile& f, long mfb, int mfp); void MakeISORecord(std::string& s); long GetMfn() const; // Get MFN int GetMfrl() const; // Get Master File Record Length long GetMfbwb() const; // Get Master File Backward Block number int GetMfbwp() const; // Get Master File Backward block position int GetBase() const; // Get Variable fields starting byte int GetNvf() const; // Get Number of entries in the directory int GetStatus() const; // Get Record Status DirEntry GetDirEntry(int i) const; // Get a reference to the ieme directory entry int GetState() const; // Get record state in memory long GetMfbRead() const; int GetMfpRead() const; int GetMflenRead() const; ustring GetAllFields(); // ANSI or UNICODE cstring GetRecordAsString() { return record_; } const char* GetRecord() { return record_.c_str(); } int GetRecordLength() { return record_.length(); } void ConvertToAnsi(); bool GetField(int tag, std::string& s); // Get field content for field with tag "tag" bool AddField(int tag, std::string& s); bool DeleteField(int tag); bool ReplaceField(int tag, std::string& s); bool AddOccurence(int tag, std::string& o); int GetFieldTag(int i); int GetFieldPos(int i); int GetFieldLen(int i); void SetMfn(long mfn); void SetState(int s); long GetDirectorySize(); int GetFieldSize() { return leader_directory_.GetFieldSize(); } std::vector GetFieldTags(); // Get tags of fields in increasing order, // Occurences made only 1 field void ExtractSubLeader(); void ExtractLeader(); bool CheckIntegrity(); bool CheckLeader(); bool CheckLeaderAndDirectory(); bool operator==(const MfRecord& rhs) const { return (record_ == rhs.record_); } bool operator!=(const MfRecord& rhs) const { return (record_ != rhs.record_); } void SetRecord(const char *s) { record_ = s; DecomposeRecord();} void SetRecord(const cstring &s) { record_ = s; DecomposeRecord();} void ComposeRecord(); bool DecomposeRecord(); bool CheckRecord(); void Dump(); } ; ////////////////////////////// inline void MfRecord::AddToRecord(const char* p, int len) { record_ += cstring(p,len); } ///////////////////////////// inline MfRecord::MfRecord(CFdt* pFdt) // Makes a Master file Record object { Clear(); pFdt_ = pFdt; // Nothing more to do } inline void MfRecord::Copy(const MfRecord& rhs) { record_ = rhs.record_; leader_directory_ = rhs.leader_directory_; fields_ = rhs.fields_; state_ = rhs.state_; mfb_read_ = rhs.mfb_read_; mfp_read_ = rhs.mfp_read_; mflen_read_ = rhs.mflen_read_; tags_ = rhs.tags_; pFdt_ = rhs.pFdt_; } inline MfRecord::MfRecord(const MfRecord& rhs) // Copy constructor { Copy(rhs); } inline MfRecord& MfRecord::operator=(const MfRecord& rhs) // Assignment { if (&leader_directory_ != &rhs.leader_directory_) { Copy(rhs); } return *this; } inline void MfRecord::Clear() { tags_.clear(); record_.erase(); leader_directory_.Clear(); fields_.clear(); SetBase(GetLeaderSize()); SetMfrl(GetLeaderSize()); state_ = Record_Empty; mfb_read_ = mfp_read_ = mflen_read_ = 0; pFdt_ = NULL; } // Clear the data part but keep other info intact so that // it appears as an empty record inline void MfRecord::ClearData() { tags_.clear(); record_.erase(); leader_directory_.Clear(); fields_.clear(); SetBase(GetLeaderSize()); SetMfrl(GetLeaderSize()); } ////////////////////////////// inline MfRecord::~MfRecord() { } ////////////////////////////// inline long MfRecord::GetMfn() const // Returns Master file number { return leader_directory_.mfn_; } ////////////////////////////// inline int MfRecord::GetMfrl() const // Returns Master file record length { return leader_directory_.mfrl_; } ////////////////////////////// inline long MfRecord::GetMfbwb() const // Returns backward pointer block number { return leader_directory_.mfbwb_; } ////////////////////////////// inline int MfRecord::GetMfbwp() const // Returns backward pointer offset { return leader_directory_.mfbwp_; } ////////////////////////////// inline int MfRecord::GetBase() const // Returns base value to field data { return leader_directory_.base_; } ////////////////////////////// inline int MfRecord::GetNvf() const // Returns the number of directory entries // in the master file record { return leader_directory_.nvf_; } ////////////////////////////// inline int MfRecord::GetStatus() const // Returns the status of the record { return leader_directory_.status_; } ////////////////////////////// ////////////////////////////// inline DirEntry MfRecord::GetDirEntry(int i) const // Returns the ith dir entry { return leader_directory_.dir_[i]; } ////////////////////////////// inline int MfRecord::GetState() const { return state_; } ////////////////////////////// inline long MfRecord::GetMfbRead() const { return mfb_read_; } ////////////////////////////// inline int MfRecord::GetMfpRead() const { return mfp_read_; } ////////////////////////////// // Get tags of fields in increasing order, inline std::vector MfRecord::GetFieldTags() { PRECONDITION(tags_.size() == fields_.size()); return tags_; } ////////////////////////////// inline int MfRecord::GetMflenRead() const { return mflen_read_; } /////////////////////////////////////////////////////////////////////////////// inline void MfRecord::SetMfn(long mfn) // Set Master file number { assert(mfn>0); leader_directory_.mfn_ = mfn; } ////////////////////////////// inline void MfRecord::SetMfrl(int mfrl) // Set Master file record length { assert(mfrl>0); leader_directory_.mfrl_ = mfrl; } ////////////////////////////// inline void MfRecord::SetMfbwb(long mfbwb) // Sets backward pointer block number to mfbwb { assert(mfbwb>=0); leader_directory_.mfbwb_ = mfbwb; } ////////////////////////////// inline void MfRecord::SetMfbwp(int mfbwp) // Sets backward pointer block offset to mfbwp { assert(mfbwp>=0); leader_directory_.mfbwp_ = mfbwp; } ////////////////////////////// inline void MfRecord::SetBase(int base) // Sets the base value in the record aggregate { assert(base>=0); leader_directory_.base_ = base; } ////////////////////////////// inline void MfRecord::SetNvf(int nvf) // Sets the number of entries in the directory part { assert(nvf>=0); leader_directory_.nvf_ = nvf; } ////////////////////////////// inline void MfRecord::SetStatus(int s) // Sets the status of the record { leader_directory_.status_ = s; } ////////////////////////////// inline void MfRecord::SetState(int s) // Sets the status of the record { assert(s==MfRecord::Record_Empty || s==MfRecord::Record_Read || s==MfRecord::Record_Changed || s==MfRecord::Record_Created); state_ = s; } inline void MfRecord::SetMfbRead(long b) { mfb_read_ = b; } inline void MfRecord::SetMfpRead(int pos) { mfp_read_ = pos; } inline void MfRecord::SetMflenRead(int len) { mflen_read_ = len; } inline int MfRecord::GetFieldTag(int i) { return leader_directory_.dir_[i].tag_; } inline int MfRecord::GetFieldPos(int i) { return leader_directory_.dir_[i].pos_; } inline int MfRecord::GetFieldLen(int i) { return leader_directory_.dir_[i].len_; } #endif