/********************************************************************** * * Fdt.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. * *********************************************************************/ /////////////////////////////////////////////////////////////////////////// // fdt.cpp #include "stdafx.h" #include "Fdt.h" #include #include #include #include #include ////////////////////////////// CFdt::CFdt() // Constructor { InitData(); InitFields(); } ////////////////////////////// CFdt::~CFdt() { for (int i = 0; i < m_nFieldCount; i++) { #ifndef _WIN32 CFieldDef* p = (CFieldDef*) m_fieldArray[i]; #else CFieldDef* p = (CFieldDef*) m_fieldArray.at(i); #endif delete p; } m_fieldArray.clear(); Close(); } //////////////////////////// bool CFdt::Open(const _TCHAR *szFileName, bool readOnly) { if (!m_bIsEmpty) Close(); m_sFileName = szFileName; if (!Load(szFileName)) { Close(); return false; } m_bReadOnly = readOnly; return Seek(0); // } ////////////////////////////// void CFdt::InitData() { m_iCurrentRecord = -1; m_sFileName.erase(); m_bReadOnly = false; m_bIsEmpty = true; m_fdtEntry.Clear(); m_bDirty = false; m_aFdt.clear(); m_asPrelude.clear(); // Suppose the fdt is empty and we are // going to append m_bAppend = true; } ////////////////////////////// void CFdt::Close() { if (!m_bIsEmpty) DeleteContents(); InitData(); // Reset data members m_bIsEmpty = true; } //////////////////////////////////// void CFdt::DeleteContents() // Delete the fdt data structures { m_aFdt.clear(); } bool CFdt::Load(const _TCHAR *dbaseName) { std::ifstream in((const char*)dbaseName); if (!in) { //#ifdef _WIN32 // CString strMsg; // strMsg.Format(_T("Error opening %s for reading. "), dbaseName); // AfxMessageBox(strMsg, MB_OK | MB_ICONEXCLAMATION); //#else std::cout << _T("Error opening") << dbaseName << _T("for reading") << std::endl; //#endif return false; } std::string s; while (std::getline(in,s) && s.substr(0,3) != "***") { m_asPrelude.push_back(s); } while (std::getline(in,s)) { CFdtEntry e; strncpy(e.name, s.c_str(), FDT_NAME_LENG); e.name[FDT_NAME_LENG] = _T('\0'); for (int i=FDT_NAME_LENG-1; e.name[i]==_T(' '); e.name[i--]=_T('\0')) ; if (s[FDT_NAME_LENG] == _T(' ')) //no subfield delimiters spec. e.subfields[0] = _T('\0'); else { strncpy(e.subfields, s.c_str()+FDT_NAME_LENG, FDT_SFLD_LENG); e.subfields[FDT_SFLD_LENG] = _T('\0'); for (int i= FDT_SFLD_LENG-1; e.subfields[i]==_T(' '); e.subfields[i--]='\0') ; } sscanf(s.c_str() + FDT_NAME_LENG + FDT_SFLD_LENG, "%d %d %d %d", &e.tag, &e.len, &e.type, &e.rep); m_aFdt.push_back(e); } in.close(); return true; } // Define the fields used for the dictionary static CFieldDef fdtFields[7] = { {"Name", 'C', 30, 30, 0, 0, 30}, {"Subfields", 'C', 20, 20, 0, 30, 20}, {"Tag", 'N', 4, 4, 0,50, 4}, {"Len", 'N', 4, 4, 0,54, 4}, {"Type", 'N', 1, 1, 0,58, 4}, {"Rep", 'C', 1, 1, 0,62, 4}, {0, 0, 0, 0, 0, 0, 0} }; //+---------------------------------------------------------------- // // Member: Store(const char* fileName) // // Synopsis: Store dictionary tables on a file // // Parameters: // // fileName -- Full path of dictionary file // //----------------------------------------------------------------- void FormatFdtEntry(CFdtEntry &e, ustring &s) { #ifdef _WIN32 ustringstream ost; ost.setf(std::ios_base::left, std::ios_base::adjustfield); ost << std::setw(30) << e.name << std::setw(20) << e.subfields; ost.setf(std::ios_base::internal,std::ios_base::adjustfield); ost << " " << e.tag << " " << e.len << " " << e.type << " " << e.rep; s = ost.str(); #endif } void CFdt::Store(const char* fileName) { if (m_bDirty) { Flush(); m_bDirty = false; } std::ofstream out((const char *) fileName); TRACE(_T("\n fileName=%s"),fileName); for (int i=0; ii=%d after new",i); //TRACE("After SetAtGrow"); strcpy(fld->name, fdtFields[i].name); fld->type = fdtFields[i].type; fld->len = fdtFields[i].len; fld->width = fdtFields[i].width; fld->decimals = fdtFields[i].decimals; fld->offset = fdtFields[i].offset; fld->display_width = fdtFields[i].display_width; int l = strlen(fld->name); if (fld->width < l) fld->width = static_cast(l); m_fieldArray.push_back(fld); m_nFieldCount++; } //TRACE("\nInitField After loop"); return 1; } //////////////////////////////////////////////////////////////////// CFieldDef* CFdt::GetField(int n) const // Returns field info { ASSERT(n >= 0 && n <= m_nFieldCount); #ifndef _WIN32 return (CFieldDef*) m_fieldArray[n]; #else return (CFieldDef*) m_fieldArray.at(n); #endif } ///////////////////////////////////////////////////////////////////// // Methods for accessing and maintaining the list of CDictTRecords // pointers //////////////////////////// // First the List Accessors //////////////////////////// CFdtEntry CFdt::GetAt(int i) { #ifndef _WIN32 return m_aFdt[i]; #else return m_aFdt.at(i); #endif } ////////////////////////// const CFdtEntry CFdt::GetAt(int i) const { #ifndef _WIN32 return m_aFdt[i]; #else return m_aFdt.at(i); #endif } ////////////////////////// // And now the modifiers ////////////////////////// int CFdt::Append(CFdtEntry& e) { int n = m_aFdt.size(); m_aFdt.push_back(e); m_iCurrentRecord = -1; m_bIsEmpty = false; return m_aFdt.size(); } /**------------------------------------------------------------------- * RemoveAt(int i) * *-------------------------------------------------------------------- */ void CFdt::RemoveAt(int i) { m_aFdt.erase(m_aFdt.begin()+i); m_iCurrentRecord = -1; } /**------------------------------------------------------------------- * SetAt(int i, CFdtEntry& e) * *-------------------------------------------------------------------- */ void CFdt::SetAt(int i, CFdtEntry& e) { m_aFdt[i] = e; // Force reloading m_iCurrentRecord = -1; } ///////////////////////////////////////////////////////////////// // // We use a buffer "m_fdtEntry" to hold the content of the current // fdt entry. This buffer is filled by the "Seek" member function // as follow: // ////////////////////////////// bool CFdt::Seek(long iRecord) { // move to new record and flush changes of previous record if (iRecord < 0 || iRecord > GetRecordCount()) return false; else if (iRecord == m_iCurrentRecord) return true; if (m_iCurrentRecord != -1 && m_bDirty) Flush(); if (m_bDirty) /*AfxMessageBox(_T("Seek Alert Modification not saved"))*/; m_iCurrentRecord = iRecord; if (iRecord == GetRecordCount()) { m_fdtEntry.Clear(); m_bAppend = true; } else { TRACE(_T("\n Load iRecord=%d GetRecordCount()=%d"), iRecord, GetRecordCount()); m_fdtEntry = GetAt(iRecord); m_bAppend = false; } m_bDirty = false; return true; } //+------------------------------------------------------------------ // // Member: Flush() // // Synopsis: Moves the changes made to the current record from // the buffer to the dictionary data structure so that // they are effective. //------------------------------------------------------------------- void CFdt::Flush() { if (m_iCurrentRecord == GetRecordCount()) { Append(m_fdtEntry); } else { SetAt(m_iCurrentRecord, m_fdtEntry); } m_bDirty = false; } ////////////////////////////////////////////////////////////// // Get the value of field n for the current record // bool CFdt::GetValue(int n, std::string& result) // Read value from buffer { ASSERT(n >= 0 && n <= m_nFieldCount); ASSERT(m_iCurrentRecord >= 0 && m_iCurrentRecord <= GetRecordCount()); if (!(n >= 0 && n <= m_nFieldCount)) return false; result.erase(); std::ostringstream os; switch (n) { case 0: // Field Name os << m_fdtEntry.name; result = os.str(); break; case 1: // Subfields os << m_fdtEntry.subfields; result = os.str(); break; case 2: // Tag if (m_fdtEntry.tag == 0) result = ""; else { os << m_fdtEntry.tag; result = os.str(); } break; case 3: // length if (m_fdtEntry.len == 0) result = ""; else { os << m_fdtEntry.len; result = os.str(); } break; case 4: // type if (m_fdtEntry.type == 0) result = ""; else { os << m_fdtEntry.type; result = os.str(); } break; case 5: // Rep if (m_fdtEntry.rep == 0) result = ""; else { os << m_fdtEntry.rep; result = os.str(); } break; } return true; } ////////////////////////////// bool CFdt::SetValue(int n, const char* pszValue) // Write value to buffer { ASSERT(n >= 0 && n <= m_nFieldCount); ASSERT(m_iCurrentRecord >= 0 && m_iCurrentRecord <= GetRecordCount()); if (m_bReadOnly) return false; if (!(n >= 0 && n <= m_nFieldCount)) return false; bool bEmpty = true; switch (n) { case 0: // Name strcpy(m_fdtEntry.name,(const char*)pszValue); // TRACE("\nvalue=%s num=%d",pszValue,m_tRecord.num); break; case 1: // Subfields strcpy(m_fdtEntry.subfields,(const char*)pszValue); // TRACE("\nvalue=%s name=%d",pszValue,m_tRecord.name); break; case 2: // Tag m_fdtEntry.tag = _ttoi(pszValue); // TRACE("\nvalue=%s loc=%d",pszValue,m_tRecord.loc); break; case 3: // Len m_fdtEntry.len = _ttoi(pszValue); // TRACE("\nvalue=%s wid=%d",pszValue,m_tRecord.wid); break; case 4: // Type m_fdtEntry.type = _ttoi(pszValue); break; case 5: // Rep m_fdtEntry.type = _ttoi(pszValue); break; } m_bDirty = true; return true; }