source: trunk/gsdl/packages/isis-gdl/Fdt.cpp@ 6127

Last change on this file since 6127 was 6127, checked in by mdewsnip, 17 years ago

IsisGdl package for reading CDS/ISIS databases. Provided by Jean-Claude Dauphin at UNESCO, and modified slightly to compile and run under Linux.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/**********************************************************************
2 *
3 * Fdt.cpp
4 * Copyright (C) 2003 UNESCO
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26///////////////////////////////////////////////////////////////////////////
27// fdt.cpp
28
29#include "stdafx.h"
30#include "Fdt.h"
31#include <iostream>
32#include <iomanip>
33#include <fstream>
34#include <sstream>
35#include <stdio.h>
36
37//////////////////////////////
38
39CFdt::CFdt()
40// Constructor
41{
42 InitData();
43 InitFields();
44}
45
46//////////////////////////////
47
48CFdt::~CFdt()
49{
50 for (int i = 0; i < m_nFieldCount; i++)
51 {
52#ifndef _WIN32
53 CFieldDef* p = (CFieldDef*) m_fieldArray[i];
54#else
55 CFieldDef* p = (CFieldDef*) m_fieldArray.at(i);
56#endif
57 delete p;
58 }
59 m_fieldArray.clear();
60
61 Close();
62}
63
64////////////////////////////
65
66bool CFdt::Open(const _TCHAR *szFileName, bool readOnly)
67{
68 if (!m_bIsEmpty)
69 Close();
70 m_sFileName = szFileName;
71 if (!Load(szFileName))
72 {
73 Close();
74 return false;
75 }
76
77 m_bReadOnly = readOnly;
78 return Seek(0); //
79}
80
81
82
83
84//////////////////////////////
85
86void CFdt::InitData()
87{
88 m_iCurrentRecord = -1;
89 m_sFileName.erase();
90
91 m_bReadOnly = false;
92 m_bIsEmpty = true;
93 m_fdtEntry.Clear();
94 m_bDirty = false;
95 m_aFdt.clear();
96 m_asPrelude.clear();
97 // Suppose the fdt is empty and we are
98 // going to append
99 m_bAppend = true;
100}
101
102//////////////////////////////
103
104void CFdt::Close()
105{
106 if (!m_bIsEmpty)
107 DeleteContents();
108
109 InitData(); // Reset data members
110 m_bIsEmpty = true;
111}
112
113////////////////////////////////////
114
115void CFdt::DeleteContents()
116// Delete the fdt data structures
117{
118 m_aFdt.clear();
119
120}
121
122
123
124bool CFdt::Load(const _TCHAR *dbaseName)
125{
126 std::ifstream in((const char*)dbaseName);
127 if (!in)
128 {
129//#ifdef _WIN32
130// CString strMsg;
131// strMsg.Format(_T("Error opening %s for reading. "), dbaseName);
132// AfxMessageBox(strMsg, MB_OK | MB_ICONEXCLAMATION);
133//#else
134 std::cout << _T("Error opening") << dbaseName << _T("for reading") << std::endl;
135//#endif
136 return false;
137 }
138
139
140 std::string s;
141
142 while (std::getline(in,s) && s.substr(0,3) != "***")
143 {
144 m_asPrelude.push_back(s);
145 }
146
147 while (std::getline(in,s))
148 {
149 CFdtEntry e;
150 strncpy(e.name, s.c_str(), FDT_NAME_LENG);
151 e.name[FDT_NAME_LENG] = _T('\0');
152 for (int i=FDT_NAME_LENG-1; e.name[i]==_T(' '); e.name[i--]=_T('\0'))
153 ;
154 if (s[FDT_NAME_LENG] == _T(' ')) //no subfield delimiters spec.
155 e.subfields[0] = _T('\0');
156 else
157 {
158 strncpy(e.subfields, s.c_str()+FDT_NAME_LENG, FDT_SFLD_LENG);
159 e.subfields[FDT_SFLD_LENG] = _T('\0');
160 for (int i= FDT_SFLD_LENG-1; e.subfields[i]==_T(' '); e.subfields[i--]='\0')
161 ;
162 }
163 sscanf(s.c_str() + FDT_NAME_LENG + FDT_SFLD_LENG, "%d %d %d %d",
164 &e.tag, &e.len, &e.type, &e.rep);
165 m_aFdt.push_back(e);
166 }
167 in.close();
168 return true;
169}
170
171
172
173
174
175
176// Define the fields used for the dictionary
177
178static CFieldDef fdtFields[7] = {
179 {"Name", 'C', 30, 30, 0, 0, 30},
180 {"Subfields", 'C', 20, 20, 0, 30, 20},
181 {"Tag", 'N', 4, 4, 0,50, 4},
182 {"Len", 'N', 4, 4, 0,54, 4},
183 {"Type", 'N', 1, 1, 0,58, 4},
184 {"Rep", 'C', 1, 1, 0,62, 4},
185 {0, 0, 0, 0, 0, 0, 0}
186};
187
188
189
190
191
192
193//+----------------------------------------------------------------
194//
195// Member: Store(const char* fileName)
196//
197// Synopsis: Store dictionary tables on a file
198//
199// Parameters:
200//
201// fileName -- Full path of dictionary file
202//
203//-----------------------------------------------------------------
204
205void FormatFdtEntry(CFdtEntry &e, ustring &s)
206{
207#ifdef _WIN32
208 ustringstream ost;
209
210 ost.setf(std::ios_base::left, std::ios_base::adjustfield);
211 ost << std::setw(30) << e.name << std::setw(20) << e.subfields;
212 ost.setf(std::ios_base::internal,std::ios_base::adjustfield);
213 ost << " " << e.tag << " " << e.len << " " << e.type << " " << e.rep;
214 s = ost.str();
215#endif
216}
217
218void CFdt::Store(const char* fileName)
219{
220 if (m_bDirty)
221 {
222 Flush();
223 m_bDirty = false;
224 }
225
226 std::ofstream out((const char *) fileName);
227 TRACE(_T("\n<CFdt::Store> fileName=%s"),fileName);
228 for (int i=0; i<m_asPrelude.size(); i++)
229 out << m_asPrelude[i] << std::endl;
230
231 out << "***" << std::endl;
232
233 ustring s;
234#ifdef _WIN32
235 for (i=0; i< m_aFdt.size(); i++)
236#else
237 for (int i=0; i< m_aFdt.size(); i++)
238#endif
239 {
240 FormatFdtEntry(m_aFdt[i], s);
241 out << s << std::endl;
242 }
243 out.close();
244
245}
246
247//////////////////////////////
248
249int CFdt::InitFields ()
250{
251 m_nFieldCount = 0;
252
253 for (int i = 0; fdtFields[i].width != 0; i++)
254 {
255 CFieldDef* fld = (CFieldDef*) new CFieldDef();
256 //TRACE("\n<CFdt::InitFields>i=%d after new",i);
257 //TRACE("<CFdt::InitFields>After SetAtGrow");
258 strcpy(fld->name, fdtFields[i].name);
259 fld->type = fdtFields[i].type;
260 fld->len = fdtFields[i].len;
261 fld->width = fdtFields[i].width;
262 fld->decimals = fdtFields[i].decimals;
263 fld->offset = fdtFields[i].offset;
264 fld->display_width = fdtFields[i].display_width;
265
266 int l = strlen(fld->name);
267 if (fld->width < l)
268 fld->width = static_cast<short>(l);
269
270 m_fieldArray.push_back(fld);
271 m_nFieldCount++;
272 }
273 //TRACE("\n<CFdt::InitFields>InitField After loop");
274 return 1;
275}
276
277////////////////////////////////////////////////////////////////////
278
279CFieldDef* CFdt::GetField(int n) const
280// Returns field info
281{
282 ASSERT(n >= 0 && n <= m_nFieldCount);
283#ifndef _WIN32
284 return (CFieldDef*) m_fieldArray[n];
285#else
286 return (CFieldDef*) m_fieldArray.at(n);
287#endif
288}
289
290/////////////////////////////////////////////////////////////////////
291// Methods for accessing and maintaining the list of CDictTRecords
292// pointers
293
294////////////////////////////
295// First the List Accessors
296////////////////////////////
297
298CFdtEntry CFdt::GetAt(int i)
299{
300#ifndef _WIN32
301 return m_aFdt[i];
302#else
303 return m_aFdt.at(i);
304#endif
305
306}
307
308
309//////////////////////////
310
311const CFdtEntry CFdt::GetAt(int i) const
312{
313#ifndef _WIN32
314 return m_aFdt[i];
315#else
316 return m_aFdt.at(i);
317#endif
318}
319
320//////////////////////////
321// And now the modifiers
322//////////////////////////
323
324int CFdt::Append(CFdtEntry& e)
325{
326 int n = m_aFdt.size();
327 m_aFdt.push_back(e);
328 m_iCurrentRecord = -1;
329 m_bIsEmpty = false;
330
331 return m_aFdt.size();
332}
333
334
335/**-------------------------------------------------------------------
336 * RemoveAt(int i)
337 *
338 *--------------------------------------------------------------------
339 */
340void CFdt::RemoveAt(int i)
341{
342
343 m_aFdt.erase(m_aFdt.begin()+i);
344 m_iCurrentRecord = -1;
345}
346
347/**-------------------------------------------------------------------
348 * SetAt(int i, CFdtEntry& e)
349 *
350 *--------------------------------------------------------------------
351 */
352void CFdt::SetAt(int i, CFdtEntry& e)
353{
354
355 m_aFdt[i] = e;
356 // Force reloading
357 m_iCurrentRecord = -1;
358}
359
360/////////////////////////////////////////////////////////////////
361//
362// We use a buffer "m_fdtEntry" to hold the content of the current
363// fdt entry. This buffer is filled by the "Seek" member function
364// as follow:
365//
366
367//////////////////////////////
368
369bool CFdt::Seek(long iRecord)
370{
371
372 // move to new record and flush changes of previous record
373 if (iRecord < 0 || iRecord > GetRecordCount())
374 return false;
375 else if (iRecord == m_iCurrentRecord)
376 return true;
377
378 if (m_iCurrentRecord != -1 && m_bDirty)
379 Flush();
380 if (m_bDirty)
381 /*AfxMessageBox(_T("Seek Alert Modification not saved"))*/;
382 m_iCurrentRecord = iRecord;
383
384 if (iRecord == GetRecordCount())
385 {
386 m_fdtEntry.Clear();
387 m_bAppend = true;
388 }
389 else
390 {
391 TRACE(_T("\n<CFdt::Seek> Load iRecord=%d GetRecordCount()=%d"), iRecord, GetRecordCount());
392 m_fdtEntry = GetAt(iRecord);
393 m_bAppend = false;
394 }
395 m_bDirty = false;
396 return true;
397}
398
399
400
401//+------------------------------------------------------------------
402//
403// Member: Flush()
404//
405// Synopsis: Moves the changes made to the current record from
406// the buffer to the dictionary data structure so that
407// they are effective.
408//-------------------------------------------------------------------
409
410void CFdt::Flush()
411{
412 if (m_iCurrentRecord == GetRecordCount())
413 {
414 Append(m_fdtEntry);
415 }
416 else
417 {
418 SetAt(m_iCurrentRecord, m_fdtEntry);
419 }
420 m_bDirty = false;
421}
422
423//////////////////////////////////////////////////////////////
424// Get the value of field n for the current record
425//
426
427bool CFdt::GetValue(int n, std::string& result)
428// Read value from buffer
429{
430 ASSERT(n >= 0 && n <= m_nFieldCount);
431 ASSERT(m_iCurrentRecord >= 0 && m_iCurrentRecord <= GetRecordCount());
432
433 if (!(n >= 0 && n <= m_nFieldCount))
434 return false;
435
436 result.erase();
437
438 std::ostringstream os;
439 switch (n)
440 {
441 case 0: // Field Name
442 os << m_fdtEntry.name;
443 result = os.str();
444 break;
445 case 1: // Subfields
446 os << m_fdtEntry.subfields;
447 result = os.str();
448 break;
449 case 2: // Tag
450 if (m_fdtEntry.tag == 0)
451 result = "";
452 else
453 {
454 os << m_fdtEntry.tag;
455 result = os.str();
456 }
457 break;
458 case 3: // length
459 if (m_fdtEntry.len == 0)
460 result = "";
461 else
462 {
463 os << m_fdtEntry.len;
464 result = os.str();
465 }
466 break;
467 case 4: // type
468 if (m_fdtEntry.type == 0)
469 result = "";
470 else
471 {
472 os << m_fdtEntry.type;
473 result = os.str();
474 }
475 break;
476 case 5: // Rep
477 if (m_fdtEntry.rep == 0)
478 result = "";
479 else
480 {
481 os << m_fdtEntry.rep;
482 result = os.str();
483 }
484 break;
485 }
486 return true;
487}
488
489
490//////////////////////////////
491
492bool CFdt::SetValue(int n, const char* pszValue)
493// Write value to buffer
494{
495 ASSERT(n >= 0 && n <= m_nFieldCount);
496 ASSERT(m_iCurrentRecord >= 0 && m_iCurrentRecord <= GetRecordCount());
497
498 if (m_bReadOnly)
499 return false;
500
501 if (!(n >= 0 && n <= m_nFieldCount))
502 return false;
503
504 bool bEmpty = true;
505
506
507 switch (n)
508 {
509 case 0: // Name
510 strcpy(m_fdtEntry.name,(const char*)pszValue);
511 // TRACE("\nvalue=%s num=%d",pszValue,m_tRecord.num);
512 break;
513 case 1: // Subfields
514 strcpy(m_fdtEntry.subfields,(const char*)pszValue);
515 // TRACE("\nvalue=%s name=%d",pszValue,m_tRecord.name);
516 break;
517 case 2: // Tag
518 m_fdtEntry.tag = _ttoi(pszValue);
519 // TRACE("\nvalue=%s loc=%d",pszValue,m_tRecord.loc);
520 break;
521 case 3: // Len
522 m_fdtEntry.len = _ttoi(pszValue);
523 // TRACE("\nvalue=%s wid=%d",pszValue,m_tRecord.wid);
524 break;
525 case 4: // Type
526 m_fdtEntry.type = _ttoi(pszValue);
527 break;
528 case 5: // Rep
529 m_fdtEntry.type = _ttoi(pszValue);
530 break;
531 }
532 m_bDirty = true;
533
534 return true;
535}
536
Note: See TracBrowser for help on using the repository browser.