/********************************************************************** * * Master.cpp * 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.CPP: Master file record object methods // //////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "XRFFile.h" #include "IsisUtil.h" #include "Master.h" #include "MFFile.h" #include "IsisDb.h" #include "Unimarc.h" #include using namespace std; char MfRecord::m_buf[MFBLKSIZE]; // Buffer to hold 1 File block ///////////////////////////////////////////////////////////////////// // LeaderAndDirectory methods int LeaderAndDirectory::GetFieldSize() { int field_len = 0; for (int i=0; i!=nvf_; ++i) field_len += dir_[i].len_; return field_len; } bool LeaderAndDirectory::operator==(const LeaderAndDirectory& rhs) const { if (mfn_ != rhs.mfn_) // Master file number return false; if (mfrl_ != rhs.mfrl_) // Record length return false; if (mfbwb_ != rhs.mfbwb_) // Backward pointer block number return false; if (mfbwp_ != rhs.mfbwp_) // Backward pointer offset return false; if (base_ != rhs.base_) // Offset to begining of variable fields return false; if (nvf_ != rhs.nvf_) // Number of directory entries return false; if (status_ != rhs.status_) // 1 = DELETED return false; for(std::vector::size_type i=0; i!=nvf_; i++) // Directory { if (dir_[i]!=rhs.dir_[i]) return false; } return true; } bool LeaderAndDirectory::operator!=(const LeaderAndDirectory& rhs) const { if (mfn_ != rhs.mfn_) // Master file number return true; if (mfrl_ != rhs.mfrl_) // Record length return true; if (mfbwb_ != rhs.mfbwb_) // Backward pointer block number return true; if (mfbwp_ != rhs.mfbwp_) // Backward pointer offset return true; if (base_ != rhs.base_) // Offset to begining of variable fields return true; if (nvf_ != rhs.nvf_) // Number of directory entries return true; if (status_ != rhs.status_) // 1 = DELETED return true; for(std::vector::size_type i=0; i!=nvf_; i++) // Directory { if (dir_[i]!=rhs.dir_[i]) return true; } return false; } //------------------------------------------------------------------------------- // ostream& operator<<(ostream& s, const LeaderAndDirectory& leader_directory) // // Overloaded instance of the output operator for LeaderAndDirectory objects //--------------------------------------------------------------------------------- cstringstream& operator<<(cstringstream& s, const LeaderAndDirectory& leader_directory) { s.write((char *) &leader_directory.mfn_, sizeof(ISIS_LONG)); s.write((char *) &leader_directory.mfrl_, sizeof(ISIS_INT)); s.write((char *) &leader_directory.mfbwb_, sizeof(ISIS_LONG)); s.write((char *) &leader_directory.mfbwp_, sizeof(ISIS_INT)); #ifdef UNIX_BIREME ISIS_INT dummy = 0; s.write((char *) &dummy, sizeof(ISIS_INT)); #endif s.write((char *) &leader_directory.base_, sizeof(ISIS_INT)); s.write((char *) &leader_directory.nvf_, sizeof(ISIS_INT)); s.write((char *) &leader_directory.status_, sizeof(ISIS_INT)); int n = leader_directory.dir_.size(); assert(n==leader_directory.nvf_); for(vector::size_type i=0; i!=leader_directory.dir_.size(); i++) { assert(leader_directory.dir_[i].tag_>0 && leader_directory.dir_[i].tag_>(istream& s, LeaderAndDirectory& leader_directory) // // Overloaded instance of the input operator for LeaderAndDirectory objects //---------------------------------------------------------------------------------- cstringstream& operator>>(cstringstream& s, LeaderAndDirectory& leader_directory) { if (!s.good()) return s; ios::iostate err = ios::goodbit; try { s.read((char *) &leader_directory.mfn_, sizeof(ISIS_LONG)); s.read((char *) &leader_directory.mfrl_, sizeof(ISIS_INT)); s.read((char *) &leader_directory.mfbwb_, sizeof(ISIS_LONG)); s.read((char *) &leader_directory.mfbwp_, sizeof(ISIS_INT)); #ifdef UNIX_BIREME ISIS_INT dummy; s.read((char *) &dummy, sizeof(ISIS_INT)); #endif s.read((char *) &leader_directory.base_, sizeof(ISIS_INT)); s.read((char *) &leader_directory.nvf_, sizeof(ISIS_INT)); s.read((char *) &leader_directory.status_, sizeof(ISIS_INT)); if (!leader_directory.dir_.empty()) leader_directory.dir_.clear(); // Try to recover if nvf_ = 0 if (leader_directory.nvf_==0) leader_directory.nvf_ = (leader_directory.base_ - GetLeaderSize()) / GetDirEntrySize(); if (leader_directory.nvf_>0) { for(vector::size_type i=0; i!=leader_directory.nvf_; i++) { DirEntry de; s.read((char *) &de, GetDirEntrySize()); // Don't check integrity of directory entries here leader_directory.dir_.push_back(de); } } } catch(bad_alloc&) { err |= ios::badbit; ios::iostate exception_mask = s.exceptions(); if ( (exception_mask & ios::failbit) && !(exception_mask & ios::badbit)) { s.setstate(err); } else if (exception_mask & ios::badbit) { s.setstate(err); // try { s.setstate(err); } // catch( ios::failure& ) { } throw; } } catch(...) { err |= ios::failbit; ios::iostate exception_mask = s.exceptions(); if ( (exception_mask & ios::badbit) && (err & ios::badbit)) { s.setstate(err); } else if (exception_mask & ios::failbit) { s.setstate(err); // try { s.setstate(err); } // catch( ios::failure& ) { } throw; } } if (err) s.setstate(err); return s; } ////////////////////////////////////////////////////////////////////////////////// // // void MfRecord::Copy(UMfRecord& rhs) // { // Clear(); // pFdt_ = rhs.pFdt_; // state_ = Record_Created; // // 1 - Prepare the LeaderAndDirectory, directory, end data part // int n = 0; // int pos = 0; // cstring all_fields_mb; // leader_directory_.dir_.clear(); // all_fields_mb.erase(); // for (vector::size_type i=0; i!=rhs.tags_.size(); ++i) // { // bool bRep = false; // if (rhs.pFdt_) // { // if (rhs.pFdt_->GetEntryAt(i).rep) // bRep = true; // } // // Get the field, all occurences combined // int tag = rhs.tags_[i]; // awstring ws; // bool rc = rhs.GetField(tag, ws); // vector occ; // if (bRep) // vector occ = SplitOccurences(ws); // else // occ.push_back(ws); // // one entry per occurence // int nocc = occ.size(); // for (vector::size_type j=0; j!= nocc; ++j) // { // DirEntry de; // de.tag_ = tag; // de.pos_ = pos; // cstring cs; // For storing the unicode string // de.len_ = UnicodeToCodePage(occ[j], cs); // leader_directory_.dir_.push_back(de); // all_fields_mb += cs; // n++; // pos += occ[j].length(); // } // } // leader_directory_.nvf_ = n; // leader_directory_.base_ = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize(); // leader_directory_.mfrl_ = ComputeMfrl(); // // 2 - Make record // record_.erase(); // Empty the record // // Prepare the binary part, note that this part must be independent // // of the character set. // cstringstream ost(std::ios::out | std::ios::binary); // ost << leader_directory_; // Output the LeaderAndDirectory to a string // AddToRecord(ost.str().c_str(), ost.str().length()); // // Here comes the part which is dependent from the character set, // // the data itself. // AddToRecord((char*)all_fields_mb.c_str(), all_fields_mb.length()); // DecomposeRecord(); // } // MfRecord::MfRecord(const UMfRecord& rhs) // Copy constructor // { // Copy(rhs); // } // MfRecord& MfRecord::operator=(const UMfRecord& rhs) // Assignment // { // if (&leader_directory_ != &rhs.leader_directory_) // { // Copy(rhs); // } // return *this; // } ///////////////////////////////////////////////////////////////////////////////////////// // Accessors //////////////////////////////////////////////////////////////////////////////////////// // Methods working on the in memory image of the record //------------------------------------------------------------------------------- // bool MfRecord::GetField(int tag, string& s) // // This function takes as input a tag and will place the field into the string // s. It will return true if the field exists and false otherwise. //------------------------------------------------------------------------------- bool MfRecord::GetField(int tag, ustring& s) { PRECONDITION(tag>=0 && tag < SHRT_MAX); map::iterator it = fields_.find(tag); bool ret = false; if (it != fields_.end()) { s = it->second; ret = true; } return ret; } ////////////////////////////////////////////////////////////////////////////////////// // Modifiers, They synchronize the record structure with the internal structures //--------------------------------------------------------------------------------- // AddField --- Add a field to the master record structure. // //--------------------------------------------------------------------------------- bool MfRecord::AddField(int tag, ustring& s) { PRECONDITION(tag>=0 && tag < SHRT_MAX); map::iterator it = fields_.find(tag); bool ret = false; if (it == fields_.end()) { fields_.insert(make_pair(tag, s)); tags_.push_back(tag); sort(tags_.begin(), tags_.end()); ret = true; ComposeRecord(); } return ret; } //--------------------------------------------------------------------------------- // AddOccurence --- Add an occurence to an existing field. //--------------------------------------------------------------------------------- bool MfRecord::AddOccurence(int tag, ustring& o) { PRECONDITION(tag>=0 && tag < SHRT_MAX); map::iterator it = fields_.find(tag); bool ret = false; if (it != fields_.end()) { it->second += SYSRSEP; it->second += o; ret = true; ComposeRecord(); } return ret; } //----------------------------------------------------------------------------- // bool MfRecord::DeleteField(int tag) // //----------------------------------------------------------------------------- bool MfRecord::DeleteField(int tag) { PRECONDITION(tag>=0 && tag < SHRT_MAX); map::iterator it = fields_.find(tag); bool ret = false; if (it != fields_.end()) { fields_.erase(it); ret = true; vector::iterator j = find(tags_.begin(), tags_.end(), tag); if (j != tags_.end()) tags_.erase(j); ComposeRecord(); } return ret; } //------------------------------------------------------------------------------- // bool ReplaceField(int tag, string& s) // //------------------------------------------------------------------------------- bool MfRecord::ReplaceField(int tag, ustring& s) { PRECONDITION(tag>=0 && tag < SHRT_MAX); map::iterator it = fields_.find(tag); bool ret = false; if (it != fields_.end()) { it->second = s; ret = true; } else AddField(tag, s); ComposeRecord(); return ret; } ustring MfRecord::GetAllFields() { cstring all_fields; // As a string of ANSI characters all_fields.erase(); all_fields = record_.substr(GetBase(), GetFieldSize()); return ustring(all_fields); } void MfRecord::ConvertToAnsi() { /* int mfrl = GetMfrl(); int size1 = record_.length(); if (GetFieldSize()==0) return; cstring s = record_.substr(GetBase(), GetFieldSize()); CString cs(s.c_str()); cs.OemToAnsi(); TRACE("\nbase=%d GetFieldSize=%d",GetBase(),GetFieldSize()); record_.replace(GetBase(),GetBase()+GetFieldSize(), cs.GetBuffer(GetFieldSize())); int size2 = record_.length(); cs.ReleaseBuffer(); int padding = size1-size2; for (int i=0; i::size_type i=0; i!=tags_.size(); ++i) { int tag = tags_[i]; bool bRep = false; if (pFdt_) { if (pFdt_->GetEntryAt(i).rep) bRep = true; } vector occ; if (bRep) vector occ = SplitOccurences(fields_[tags_[i]]); else occ.push_back(fields_[tags_[i]]); // one entry per occurence int nocc = occ.size(); for (vector::size_type j=0; j!= nocc; ++j) { DirEntry de; de.tag_ = tag; de.pos_ = pos; de.len_ = occ[j].length(); leader_directory_.dir_.push_back(de); all_fields += occ[j]; n++; pos += occ[j].length(); } } leader_directory_.nvf_ = n; leader_directory_.base_ = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize(); leader_directory_.mfrl_ = ComputeMfrl(); // 2 - Make record record_.erase(); // Empty the record // Prepare the binary part, note that this part must be independent // of the character set. cstringstream ost(std::ios::out | std::ios::binary); ost << leader_directory_; // Output the LeaderAndDirectory to a string AddToRecord(ost.str().c_str(), ost.str().length()); // Here comes the part which is dependent from the character set, // the data itself. cstring all_fields_ansi(all_fields); AddToRecord(all_fields_ansi.c_str(), all_fields_ansi.length()); } //------------------------------- // Helper functions for decompose //------------------------------- bool MfRecord::CheckLeaderAndDirectory() { if (GetMfrl() < 0) // Negative mfrl { //VLOG("DecomposeRecord - Warning! Negative mfrl - mfn=%d", GetMfn()); SetMfrl(-GetMfrl()); } if (GetMfrl()<=GetBase()) { //VLOG("DecomposeRecord - Error! mfn=%d GetMfrl()=%d > GetBase()=%d", // GetMfn(), GetMfrl(), GetBase()); return false; } if (GetLeaderSize()>GetBase()) { //VLOG("DecomposeRecord - Error! mfn=%d GetLeaderSize()=%d > GetBase()=%d", // GetMfn(), GetLeaderSize(), GetBase()); return false; } if (GetNvf()==0) { // Null nvf //VLOG("DecomposeRecord - Warning! mfn=%d nvf=0", GetMfn()); //SetNvf((GetBase() - GetLeaderSize()) / GetDirEntrySize()); return false; } if (GetMfn()<=0 || GetMfrl()<=0 || GetBase()<0 || GetNvf()<0 || GetStatus()< 0) { //VLOG("DecomposeRecord - Error! mfn=%d GetMfrl()=%d GetLeaderSize()=%d GetBase()=%d GetNvf()=%d GetStatus()=%d", // GetMfn(), GetMfrl(), GetLeaderSize(), GetBase(), GetNvf(), GetStatus()); return false; } int base = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize(); if (record_.length() <= base) { //VLOG("DecomposeRecord - Error! mfn=%d record_.length()=%d < base=%d", // GetMfn(), record_.length(), base); return false; } int field_len = 0; for (int i=0; i!=GetNvf(); ++i) { if (GetFieldTag(i)<0 || GetFieldTag(i)>SHRT_MAX || GetFieldPos(i)<0 || GetFieldPos(i)>SHRT_MAX || GetFieldLen(i)<0 || GetFieldLen(i)>SHRT_MAX) { //VLOG("DecomposeRecord - Error! mfn=%d Bad dir entry i=%d tag=%d pos=%d len=%d", // GetMfn(), GetFieldTag(i), GetFieldPos(i), GetFieldLen(i)); return false; } field_len += GetFieldLen(i); } for (int j=0; j!=GetNvf(); ++j) { if (GetFieldPos(j)>=field_len || GetFieldPos(j)+GetFieldLen(j)>field_len) { //VLOG("DecomposeRecord - Error! mfn=%d Bad dir entry j=%d tag=%d pos=%d len=%d", // GetMfn(), GetFieldTag(j), GetFieldPos(j), GetFieldLen(j)); return false; } } // Check for bad values if (GetBase() != base) SetBase(base); if (record_.length() < base + field_len) { //VLOG("DecomposeRecord - Error! mfn=%d record_.length()=%d < base=%d + field_len=%d", //GetMfn(), record_.length(), base, field_len); return false; } return true; } void MfRecord::MakeTagToFieldMap() { cstring all_fields_ansi; all_fields_ansi.erase(); all_fields_ansi = record_.substr(leader_directory_.base_, GetFieldSize()); PRECONDITION(fields_.empty() && tags_.empty()); // Build the map from tags to fields for (int i=0; i!=GetNvf(); ++i) { //int all_len = all_fields.length(); //if (pos>all_len || pos+len>all_len) // return false; cstring field_ansi = all_fields_ansi.substr(GetFieldPos(i), GetFieldLen(i)); ustring field(field_ansi); map::iterator it = fields_.find(GetFieldTag(i)); if (it != fields_.end()) { // Repeatable field, several occ it->second += SYSRSEP; it->second += field; } else { fields_.insert(make_pair(GetFieldTag(i), field)); } } } void MfRecord::MakeTagVector() { // Build a vector of tags map::const_iterator it; for ( it = fields_.begin(); it != fields_.end(); ++it ) tags_.push_back(it->first); // Sort in ascending order sort(tags_.begin(), tags_.end()); } //-------------------------------------------------------------------------------------- // bool MfRecord::DecomposeRecord() // // Make a memory version of the record to facilitate manipulations. //-------------------------------------------------------------------------------------- bool MfRecord::DecomposeRecord() { PRECONDITION(!record_.empty()); if (record_.length() <= GetLeaderSize()) { //VLOG("DecomposeRecord - Error! record_.length()=%d < GetLeaderSize()=%d",record_.length(), GetLeaderSize()); return false; } // Input the LeaderAndDirectory from a string cstringstream ist(record_,cstringstream::in|cstringstream::binary); if (!(ist >> leader_directory_)) return false; if (!CheckLeaderAndDirectory()) { //VLOG("Record rejected mfn=%ld", GetMfn()); return false; } //VLOG("Record accepted mfn=%ld", GetMfn()); MakeTagToFieldMap(); MakeTagVector(); return true; } void MfRecord::ExtractSubLeader() { //PRECONDITION(!record_.empty() && record_.length()>=sizeof(leader_directory_.mfn_)+sizeof(leader_directory_.mfrl_)); leader_directory_.mfn_ = *(reinterpret_cast((char *) record_.c_str())); leader_directory_.mfrl_ = *(reinterpret_cast ((char *)(record_.c_str()+sizeof(ISIS_LONG)))); if (leader_directory_.mfrl_ < 0) leader_directory_.mfrl_ = -leader_directory_.mfrl_; // mfrl can be negative!!!! //POSTCONDITION(leader_directory_.mfn_>0 && leader_directory_.mfrl_>=0); } bool MfRecord::CheckLeader() { int leader_size = GetLeaderSize(); if (leader_directory_.mfn_<=0) return false; if (abs(leader_directory_.mfrl_)> leader_directory; if (leader_directory.mfrl_ < 0) // Negative mfrl { //VLOG("CheckRecord - Warning! Negative mfrl - mfn=%d", GetMfn()); } if (leader_directory.nvf_<=0) { //VLOG("CheckRecord - Warning! mfn=%d nvf=0", leader_directory.mfn_); } if (leader_directory.mfn_<=0 || leader_directory.mfrl_<=0 || leader_directory.base_<0 || leader_directory.nvf_ < 0 || leader_directory.status_ < 0) { //VLOG("CheckRecord - Corrupted record! leader_directory.mfn_=%d leader_directory.mfrl_=%d leader_directory.base_=%d leader_directory.nvf_=%d leader_directory.status_=%d", // leader_directory.mfn_, leader_directory.mfrl_, // leader_directory.base_, leader_directory.nvf_, // leader_directory.status_); return false; } int base = GetLeaderSize() + GetDirectorySize(); if (record_.length() < base) { //VLOG("CheckRecord - Corrupted record! mfn=%d record_.length()=%d base=%d", // leader_directory.mfn_, record_.length(), base); return false; } int field_len = 0; for (int i=0; i!=leader_directory.nvf_; ++i) { DirEntry de = leader_directory.dir_[i]; // if (de.tag_<0 || de.tag_>SHRT_MAX || de.pos_<0 || de.pos_>SHRT_MAX || de.len_<0 || de.len_>SHRT_MAX) // { // //VLOG("CheckRecord - Corrupted record! mfn=%d tag=%d pos=%d len=%d", // // leader_directory.mfn_, de.tag_, de.pos_, de.len_); // return false; // } if (i>0) { if(de.pos_ != leader_directory.dir_[i-1].pos_+leader_directory.dir_[i-1].len_) { //VLOG("CheckRecord - Position not consistent - mfn=%d", // leader_directory.mfn_); return false; } } field_len += de.len_; } // Check for bad values if (leader_directory.base_ != base) leader_directory.base_ = base; if (record_.length() < base + field_len) { //VLOG("CheckRecord - Corrupted record, record length < base+field_len - mfn=%ld", // leader_directory.mfn_); return false; } return true; } void MfRecord::ReadLeader(MfFile& f, long daddr) { int leader_size = GetLeaderSize(); char* buffer = new char[leader_size]; f.Fetch(buffer, leader_size, daddr); // Read record leader Clear(); AddToRecord(buffer, leader_size); delete[] buffer; } bool MfRecord::Read(MfFile& f, long mfb, int mfp) { //TRACE("\nMfFile::ReadMfRecord -- mfb=%ld mfp=%d", mfb, mfp); PRECONDITION(mfb>0 && mfb<=MAXMFB); long blk; int mfrr, offs, l; try { Clear(); // Save original mfb, mfp pair into m SetMfbRead(mfb); SetMfpRead(mfp); SetState(MfRecord::Record_Read); // Be sure that mfp is in range [0:MFBLKSIZE-1] mfp = mfp%MFBLKSIZE; assert(mfp>=0 && mfp (f.GetBlockSize()-(mfp+len))) // What remains to move ? (f.GetBlockSize()-(mfp+len)) : mfrr; // in this block offs = len; AddToRecord(m_buf+mfp+len, l); // Move-it mfrr -= l; while (mfrr>0) // Record continues on next block ? { f.ReadBlk(m_buf,++blk); // Yes read next block offs += l; l = (mfrr > f.GetBlockSize()) ? f.GetBlockSize() : mfrr; AddToRecord(m_buf, l); // Move data mfrr -= l; } //TRACE("\nMfFile::ReadMfRecord -- mfb=%ld mfp=%d nvf=%d", mfb, mfp, GetNvf()); } catch (CFileBaseException e) { throw CIsisDbException(ISIS_MF_READ_ERROR, __FILE__, __LINE__); } return DecomposeRecord(); } void MfRecord::Write(MfFile& f, long mfb, int mfp) { TRACE(_T("\nMfFile::writeMfRecord - mfb=%ld mfp=%d"), mfb, mfp); PRECONDITION(mfb>0 && mfb <= MAXMFB); // Be sure that mfp is in range [0:MFBLKSIZE-1] mfp = mfp%MFBLKSIZE; long hiblk = f.GetNextMfb(); // Highest block number in master file int s = 0; // Index in master file record [0:mfrl-1] int d = mfp; // Index in block buffer [0:bsize-1] long b = mfb; // Starting block number // Adjust record length int padding = GetMfrl() % MFALIGN; if (padding>0) { SetMfrl(GetMfrl() + padding); for (int i=0; i")); do { if (b <= hiblk) f.ReadBlk(m_buf, b); else ::memset(m_buf, ' ', MFBLKSIZE); while (d < MFBLKSIZE && s < mfrl) m_buf[d++] = record_.at(s++); if (d >= MFBLKSIZE) { TRACE(_T("MfFile::WriteMfRecord - Before WriteBlk b=%ld"), b); f.SetLastWrittenBlock(b); f.WriteBlk(m_buf, b++); // Reset m_buf pos d = 0; } } while (s < mfrl); // Write last block if (d == 0) ::memset(m_buf, ' ', MFBLKSIZE); // Should be an empty block f.WriteBlk(m_buf, b); f.SetLastWrittenBlock(b); } void IntToChar(int value, int width, std::string& s) { std::ostringstream ost; #ifdef _WIN32 ost.setf(std::ios_base::right, std::ios_base::adjustfield); #endif ost << std::setw(width) << std::setfill('0') << value; s = ost.str(); } //-------------------------------------------------------------------------------------- // void MfRecord::MakeISORecord(std::string& s) // // Build the record into continuous bytes for output //-------------------------------------------------------------------------------------- void MfRecord::MakeISORecord(std::string& s) { std::string tmp; MarcLeader l; // 1 - Complete the leader (base and record length), output the directory // to a string and prepare a string with the data fields int base = MARC_LEADER_LEN + GetNvf()*MARC_DIRENT_LEN + 1; IntToChar(base, 5, tmp); strncpy(l.base_ ,tmp.c_str(),5); DirectoryEntry mde; ustring all_fields; all_fields.erase(); ostringstream osd; // Output the directory to a string int pos = 0; for (int i=0; i!=GetNvf(); ++i) { IntToChar(GetFieldTag(i), 3, tmp); strncpy(mde.tag_,tmp.c_str(),3); int len = GetFieldLen(i)+1; // Include space for separator IntToChar(len, 4, tmp); strncpy(mde.len_, tmp.c_str(), 4); IntToChar(pos, 5, tmp); strncpy(mde.scp_, tmp.c_str(), 5); osd << mde; pos += len; cstring field = record_.substr(GetBase()+GetFieldPos(i), GetFieldLen(i)); all_fields += ustring(field); all_fields += FIELDTERM; } // (+2) ->Field sep at end of directory and record sep int reclen = MARC_LEADER_LEN + GetNvf()*MARC_DIRENT_LEN + pos +2; IntToChar(reclen, 5, tmp); strncpy(l.lreclen_,tmp.c_str(),5); ostringstream osl; // Output the Leader to a string osl << l; // 2 - Make record s.erase(); // Empty the record s += osl.str(); // Add the leader s += osd.str(); // Add the directory s += FIELDTERM; // Separator s += cstring(all_fields); // Data part s += RECTERM; }