source: main/trunk/greenstone2/build-src/packages/isis-gdl/Master.cpp@ 26670

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

Running this on a big-endian machine would fail to read little-endian CDS/ISIS files. I've assumed most (all?) CDS/ISIS files are little-endian, and added code to convert the values into the right endianness on big-endian machines.

  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1/**********************************************************************
2 *
3 * Master.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// MASTER.CPP: Master file record object methods
28//
29////////////////////////////////////////////////////////////
30#include "stdafx.h"
31#include <iomanip>
32#include "XRFFile.h"
33#include "IsisUtil.h"
34#include "Master.h"
35#include "MFFile.h"
36#include "IsisDb.h"
37#include "Unimarc.h"
38#include <algorithm>
39
40
41using namespace std;
42
43
44
45char MfRecord::m_buf[MFBLKSIZE]; // Buffer to hold 1 File block
46
47
48
49/////////////////////////////////////////////////////////////////////
50// LeaderAndDirectory methods
51
52int LeaderAndDirectory::GetFieldSize()
53{
54 int field_len = 0;
55 for (int i=0; i!=nvf_; ++i)
56 field_len += dir_[i].len_;
57 return field_len;
58}
59
60bool LeaderAndDirectory::operator==(const LeaderAndDirectory& rhs) const
61{
62 if (mfn_ != rhs.mfn_) // Master file number
63 return false;
64 if (mfrl_ != rhs.mfrl_) // Record length
65 return false;
66 if (mfbwb_ != rhs.mfbwb_) // Backward pointer block number
67 return false;
68 if (mfbwp_ != rhs.mfbwp_) // Backward pointer offset
69 return false;
70 if (base_ != rhs.base_) // Offset to begining of variable fields
71 return false;
72 if (nvf_ != rhs.nvf_) // Number of directory entries
73 return false;
74 if (status_ != rhs.status_) // 1 = DELETED
75 return false;
76 for(std::vector<DirEntry>::size_type i=0; i!=nvf_; i++) // Directory
77 {
78 if (dir_[i]!=rhs.dir_[i])
79 return false;
80 }
81 return true;
82}
83
84bool LeaderAndDirectory::operator!=(const LeaderAndDirectory& rhs) const
85{
86 if (mfn_ != rhs.mfn_) // Master file number
87 return true;
88 if (mfrl_ != rhs.mfrl_) // Record length
89 return true;
90 if (mfbwb_ != rhs.mfbwb_) // Backward pointer block number
91 return true;
92 if (mfbwp_ != rhs.mfbwp_) // Backward pointer offset
93 return true;
94 if (base_ != rhs.base_) // Offset to begining of variable fields
95 return true;
96 if (nvf_ != rhs.nvf_) // Number of directory entries
97 return true;
98 if (status_ != rhs.status_) // 1 = DELETED
99 return true;
100 for(std::vector<DirEntry>::size_type i=0; i!=nvf_; i++) // Directory
101 {
102 if (dir_[i]!=rhs.dir_[i])
103 return true;
104 }
105 return false;
106}
107//-------------------------------------------------------------------------------
108// ostream& operator<<(ostream& s, const LeaderAndDirectory& leader_directory)
109//
110// Overloaded instance of the output operator for LeaderAndDirectory objects
111//---------------------------------------------------------------------------------
112cstringstream& operator<<(cstringstream& s, const LeaderAndDirectory& leader_directory)
113{
114 s.write((char *) &leader_directory.mfn_, sizeof(ISIS_LONG));
115 s.write((char *) &leader_directory.mfrl_, sizeof(ISIS_INT));
116 s.write((char *) &leader_directory.mfbwb_, sizeof(ISIS_LONG));
117 s.write((char *) &leader_directory.mfbwp_, sizeof(ISIS_INT));
118#ifdef UNIX_BIREME
119 ISIS_INT dummy = 0;
120 s.write((char *) &dummy, sizeof(ISIS_INT));
121#endif
122
123 s.write((char *) &leader_directory.base_, sizeof(ISIS_INT));
124 s.write((char *) &leader_directory.nvf_, sizeof(ISIS_INT));
125 s.write((char *) &leader_directory.status_, sizeof(ISIS_INT));
126
127 int n = leader_directory.dir_.size();
128 assert(n==leader_directory.nvf_);
129 for(vector<DirEntry>::size_type i=0; i!=leader_directory.dir_.size(); i++)
130 {
131 assert(leader_directory.dir_[i].tag_>0 && leader_directory.dir_[i].tag_<SHRT_MAX);
132 DirEntry de = leader_directory.dir_[i];
133 s.write((char *) &de, GetDirEntrySize());
134 }
135
136 return s;
137}
138
139//----------------------------------------------------------------------------------
140// istream& operator>>(istream& s, LeaderAndDirectory& leader_directory)
141//
142// Overloaded instance of the input operator for LeaderAndDirectory objects
143//----------------------------------------------------------------------------------
144cstringstream& operator>>(cstringstream& s, LeaderAndDirectory& leader_directory)
145{
146 if (!s.good()) return s;
147
148 ios::iostate err = ios::goodbit;
149 try
150 {
151 s.read((char *) &leader_directory.mfn_, sizeof(ISIS_LONG));
152 s.read((char *) &leader_directory.mfrl_, sizeof(ISIS_INT));
153 s.read((char *) &leader_directory.mfbwb_, sizeof(ISIS_LONG));
154 s.read((char *) &leader_directory.mfbwp_, sizeof(ISIS_INT));
155#ifdef UNIX_BIREME
156 ISIS_INT dummy;
157 s.read((char *) &dummy, sizeof(ISIS_INT));
158#endif
159 s.read((char *) &leader_directory.base_, sizeof(ISIS_INT));
160 s.read((char *) &leader_directory.nvf_, sizeof(ISIS_INT));
161 s.read((char *) &leader_directory.status_, sizeof(ISIS_INT));
162
163 fix_endianness(leader_directory.mfn_);
164 fix_endianness(leader_directory.mfrl_);
165 fix_endianness(leader_directory.mfbwb_);
166 fix_endianness(leader_directory.mfbwp_);
167 fix_endianness(leader_directory.base_);
168 fix_endianness(leader_directory.nvf_);
169 fix_endianness(leader_directory.status_);
170
171 if (!leader_directory.dir_.empty())
172 leader_directory.dir_.clear();
173
174 // Try to recover if nvf_ = 0
175 if (leader_directory.nvf_==0)
176 leader_directory.nvf_ = (leader_directory.base_ - GetLeaderSize()) / GetDirEntrySize();
177
178 if (leader_directory.nvf_>0)
179 {
180 for(vector<DirEntry>::size_type i=0; i!=leader_directory.nvf_; i++)
181 {
182 DirEntry de;
183 s.read((char *) &de, GetDirEntrySize());
184 fix_endianness(de.tag_);
185 fix_endianness(de.pos_);
186 fix_endianness(de.len_);
187 // Don't check integrity of directory entries here
188 leader_directory.dir_.push_back(de);
189 }
190
191 }
192 }
193 catch(bad_alloc&)
194 {
195 err |= ios::badbit;
196 ios::iostate exception_mask = s.exceptions();
197 if ( (exception_mask & ios::failbit) &&
198 !(exception_mask & ios::badbit))
199 {
200 s.setstate(err);
201 }
202 else if (exception_mask & ios::badbit)
203 {
204 s.setstate(err);
205 // try { s.setstate(err); }
206 // catch( ios::failure& ) { }
207 throw;
208
209 }
210 }
211 catch(...)
212 {
213 err |= ios::failbit;
214 ios::iostate exception_mask = s.exceptions();
215 if ( (exception_mask & ios::badbit) &&
216 (err & ios::badbit))
217 {
218 s.setstate(err);
219 }
220 else if (exception_mask & ios::failbit)
221 {
222 s.setstate(err);
223 // try { s.setstate(err); }
224 // catch( ios::failure& ) { }
225 throw;
226
227 }
228 }
229
230 if (err) s.setstate(err);
231 return s;
232}
233
234
235//////////////////////////////////////////////////////////////////////////////////
236//
237
238// void MfRecord::Copy(UMfRecord& rhs)
239// {
240// Clear();
241// pFdt_ = rhs.pFdt_;
242// state_ = Record_Created;
243
244// // 1 - Prepare the LeaderAndDirectory, directory, end data part
245// int n = 0;
246// int pos = 0;
247
248// cstring all_fields_mb;
249// leader_directory_.dir_.clear();
250// all_fields_mb.erase();
251// for (vector<int>::size_type i=0; i!=rhs.tags_.size(); ++i)
252// {
253// bool bRep = false;
254// if (rhs.pFdt_)
255// {
256// if (rhs.pFdt_->GetEntryAt(i).rep)
257// bRep = true;
258// }
259// // Get the field, all occurences combined
260// int tag = rhs.tags_[i];
261// awstring ws;
262// bool rc = rhs.GetField(tag, ws);
263// vector<awstring> occ;
264// if (bRep)
265// vector<awstring> occ = SplitOccurences(ws);
266// else
267// occ.push_back(ws);
268// // one entry per occurence
269// int nocc = occ.size();
270// for (vector<awstring>::size_type j=0; j!= nocc; ++j)
271// {
272// DirEntry de;
273// de.tag_ = tag;
274// de.pos_ = pos;
275// cstring cs; // For storing the unicode string
276// de.len_ = UnicodeToCodePage(occ[j], cs);
277// leader_directory_.dir_.push_back(de);
278// all_fields_mb += cs;
279// n++;
280// pos += occ[j].length();
281
282// }
283// }
284
285// leader_directory_.nvf_ = n;
286// leader_directory_.base_ = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize();
287// leader_directory_.mfrl_ = ComputeMfrl();
288
289// // 2 - Make record
290
291// record_.erase(); // Empty the record
292
293// // Prepare the binary part, note that this part must be independent
294// // of the character set.
295
296// cstringstream ost(std::ios::out | std::ios::binary);
297// ost << leader_directory_; // Output the LeaderAndDirectory to a string
298
299
300// AddToRecord(ost.str().c_str(), ost.str().length());
301
302// // Here comes the part which is dependent from the character set,
303// // the data itself.
304// AddToRecord((char*)all_fields_mb.c_str(), all_fields_mb.length());
305
306// DecomposeRecord();
307// }
308
309// MfRecord::MfRecord(const UMfRecord& rhs) // Copy constructor
310// {
311// Copy(rhs);
312// }
313
314// MfRecord& MfRecord::operator=(const UMfRecord& rhs) // Assignment
315// {
316// if (&leader_directory_ != &rhs.leader_directory_)
317// {
318// Copy(rhs);
319// }
320// return *this;
321// }
322
323/////////////////////////////////////////////////////////////////////////////////////////
324// Accessors
325
326
327
328////////////////////////////////////////////////////////////////////////////////////////
329// Methods working on the in memory image of the record
330
331//-------------------------------------------------------------------------------
332// bool MfRecord::GetField(int tag, string& s)
333//
334// This function takes as input a tag and will place the field into the string
335// s. It will return true if the field exists and false otherwise.
336//-------------------------------------------------------------------------------
337bool MfRecord::GetField(int tag, ustring& s)
338{
339 PRECONDITION(tag>=0 && tag < SHRT_MAX);
340
341 map<int, ustring>::iterator it = fields_.find(tag);
342
343 bool ret = false;
344 if (it != fields_.end())
345 {
346 s = it->second;
347 ret = true;
348 }
349 return ret;
350}
351
352//////////////////////////////////////////////////////////////////////////////////////
353// Modifiers, They synchronize the record structure with the internal structures
354
355
356//---------------------------------------------------------------------------------
357// AddField --- Add a field to the master record structure.
358//
359//---------------------------------------------------------------------------------
360bool MfRecord::AddField(int tag, ustring& s)
361{
362 PRECONDITION(tag>=0 && tag < SHRT_MAX);
363
364 map<int, ustring>::iterator it = fields_.find(tag);
365
366 bool ret = false;
367 if (it == fields_.end())
368 {
369 fields_.insert(make_pair(tag, s));
370 tags_.push_back(tag);
371 sort(tags_.begin(), tags_.end());
372 ret = true;
373 ComposeRecord();
374 }
375 return ret;
376}
377//---------------------------------------------------------------------------------
378// AddOccurence --- Add an occurence to an existing field.
379//---------------------------------------------------------------------------------
380bool MfRecord::AddOccurence(int tag, ustring& o)
381{
382 PRECONDITION(tag>=0 && tag < SHRT_MAX);
383
384 map<int, ustring>::iterator it = fields_.find(tag);
385
386 bool ret = false;
387 if (it != fields_.end())
388 {
389 it->second += SYSRSEP;
390 it->second += o;
391 ret = true;
392 ComposeRecord();
393 }
394 return ret;
395}
396
397//-----------------------------------------------------------------------------
398// bool MfRecord::DeleteField(int tag)
399//
400//-----------------------------------------------------------------------------
401bool MfRecord::DeleteField(int tag)
402{
403 PRECONDITION(tag>=0 && tag < SHRT_MAX);
404
405 map<int, ustring>::iterator it = fields_.find(tag);
406
407 bool ret = false;
408 if (it != fields_.end())
409 {
410 fields_.erase(it);
411 ret = true;
412 vector<int>::iterator j = find(tags_.begin(), tags_.end(), tag);
413 if (j != tags_.end())
414 tags_.erase(j);
415 ComposeRecord();
416 }
417 return ret;
418}
419
420//-------------------------------------------------------------------------------
421// bool ReplaceField(int tag, string& s)
422//
423//-------------------------------------------------------------------------------
424bool MfRecord::ReplaceField(int tag, ustring& s)
425{
426
427 PRECONDITION(tag>=0 && tag < SHRT_MAX);
428
429 map<int, ustring>::iterator it = fields_.find(tag);
430
431 bool ret = false;
432 if (it != fields_.end())
433 {
434 it->second = s;
435 ret = true;
436 }
437 else
438 AddField(tag, s);
439 ComposeRecord();
440
441 return ret;
442}
443
444ustring MfRecord::GetAllFields()
445{
446 cstring all_fields; // As a string of ANSI characters
447 all_fields.erase();
448 all_fields = record_.substr(GetBase(), GetFieldSize());
449 return ustring(all_fields);
450}
451
452void MfRecord::ConvertToAnsi()
453{
454 /*
455 int mfrl = GetMfrl();
456 int size1 = record_.length();
457 if (GetFieldSize()==0)
458 return;
459 cstring s = record_.substr(GetBase(), GetFieldSize());
460 CString cs(s.c_str());
461 cs.OemToAnsi();
462 TRACE("\nbase=%d GetFieldSize=%d",GetBase(),GetFieldSize());
463 record_.replace(GetBase(),GetBase()+GetFieldSize(),
464 cs.GetBuffer(GetFieldSize()));
465 int size2 = record_.length();
466 cs.ReleaseBuffer();
467 int padding = size1-size2;
468 for (int i=0; i<padding; i++)
469 record_ += " ";
470*/
471}
472
473long MfRecord::GetDirectorySize()
474{
475 return (GetNvf()*GetDirEntrySize());
476}
477
478long MfRecord::ComputeMfrl()
479{
480 return (GetLeaderSize() + GetDirectorySize() + GetFieldSize());
481}
482
483//--------------------------------------------------------------------------------------
484// void MfRecord::ComposeRecord()
485//
486// Build the record into continuous bytes for output
487//--------------------------------------------------------------------------------------
488void MfRecord::ComposeRecord()
489{
490 PRECONDITION(tags_.size() == fields_.size());
491
492 // 1 - Prepare the LeaderAndDirectory, directory, end data part
493 int n = 0;
494 int pos = 0;
495
496 ustring all_fields;
497 leader_directory_.dir_.clear();
498 all_fields.erase();
499 for (vector<int>::size_type i=0; i!=tags_.size(); ++i)
500 {
501 int tag = tags_[i];
502 bool bRep = false;
503 if (pFdt_)
504 {
505 if (pFdt_->GetEntryAt(i).rep)
506 bRep = true;
507 }
508 vector<ustring> occ;
509 if (bRep)
510 vector<ustring> occ = SplitOccurences(fields_[tags_[i]]);
511 else
512 occ.push_back(fields_[tags_[i]]);
513 // one entry per occurence
514 int nocc = occ.size();
515 for (vector<ustring>::size_type j=0; j!= nocc; ++j)
516 {
517 DirEntry de;
518 de.tag_ = tag;
519 de.pos_ = pos;
520 de.len_ = occ[j].length();
521 leader_directory_.dir_.push_back(de);
522 all_fields += occ[j];
523 n++;
524 pos += occ[j].length();
525
526 }
527 }
528
529 leader_directory_.nvf_ = n;
530 leader_directory_.base_ = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize();
531 leader_directory_.mfrl_ = ComputeMfrl();
532
533 // 2 - Make record
534
535 record_.erase(); // Empty the record
536
537 // Prepare the binary part, note that this part must be independent
538 // of the character set.
539
540 cstringstream ost(std::ios::out | std::ios::binary);
541 ost << leader_directory_; // Output the LeaderAndDirectory to a string
542
543
544 AddToRecord(ost.str().c_str(), ost.str().length());
545
546 // Here comes the part which is dependent from the character set,
547 // the data itself.
548 cstring all_fields_ansi(all_fields);
549 AddToRecord(all_fields_ansi.c_str(), all_fields_ansi.length());
550
551}
552
553//-------------------------------
554// Helper functions for decompose
555//-------------------------------
556
557bool MfRecord::CheckLeaderAndDirectory()
558{
559 if (GetMfrl() < 0) // Negative mfrl
560 {
561 //VLOG("DecomposeRecord - Warning! Negative mfrl - mfn=%d", GetMfn());
562 SetMfrl(-GetMfrl());
563 }
564
565 if (GetMfrl()<=GetBase())
566 {
567 //VLOG("DecomposeRecord - Error! mfn=%d GetMfrl()=%d > GetBase()=%d",
568 // GetMfn(), GetMfrl(), GetBase());
569 return false;
570 }
571
572
573
574 if (GetLeaderSize()>GetBase())
575 {
576 //VLOG("DecomposeRecord - Error! mfn=%d GetLeaderSize()=%d > GetBase()=%d",
577 // GetMfn(), GetLeaderSize(), GetBase());
578 return false;
579 }
580 if (GetNvf()==0)
581 {
582 // Null nvf
583 //VLOG("DecomposeRecord - Warning! mfn=%d nvf=0", GetMfn());
584 //SetNvf((GetBase() - GetLeaderSize()) / GetDirEntrySize());
585 return false;
586 }
587
588 if (GetMfn()<=0 || GetMfrl()<=0 || GetBase()<0 || GetNvf()<0 || GetStatus()< 0)
589 {
590 //VLOG("DecomposeRecord - Error! mfn=%d GetMfrl()=%d GetLeaderSize()=%d GetBase()=%d GetNvf()=%d GetStatus()=%d",
591 // GetMfn(), GetMfrl(), GetLeaderSize(), GetBase(), GetNvf(), GetStatus());
592 return false;
593 }
594
595
596 int base = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize();
597
598 if (record_.length() <= base)
599 {
600 //VLOG("DecomposeRecord - Error! mfn=%d record_.length()=%d < base=%d",
601 // GetMfn(), record_.length(), base);
602 return false;
603 }
604
605 int field_len = 0;
606 for (int i=0; i!=GetNvf(); ++i)
607 {
608 if (GetFieldTag(i)<0 || GetFieldTag(i)>SHRT_MAX ||
609 GetFieldPos(i)<0 || GetFieldPos(i)>SHRT_MAX ||
610 GetFieldLen(i)<0 || GetFieldLen(i)>SHRT_MAX)
611 {
612 //VLOG("DecomposeRecord - Error! mfn=%d Bad dir entry i=%d tag=%d pos=%d len=%d",
613 // GetMfn(), GetFieldTag(i), GetFieldPos(i), GetFieldLen(i));
614 return false;
615 }
616 field_len += GetFieldLen(i);
617 }
618
619 for (int j=0; j!=GetNvf(); ++j)
620 {
621 if (GetFieldPos(j)>=field_len || GetFieldPos(j)+GetFieldLen(j)>field_len)
622 {
623 //VLOG("DecomposeRecord - Error! mfn=%d Bad dir entry j=%d tag=%d pos=%d len=%d",
624 // GetMfn(), GetFieldTag(j), GetFieldPos(j), GetFieldLen(j));
625 return false;
626 }
627 }
628 // Check for bad values
629 if (GetBase() != base)
630 SetBase(base);
631
632 if (record_.length() < base + field_len)
633 {
634 //VLOG("DecomposeRecord - Error! mfn=%d record_.length()=%d < base=%d + field_len=%d",
635 //GetMfn(), record_.length(), base, field_len);
636 return false;
637 }
638 return true;
639}
640
641void MfRecord::MakeTagToFieldMap()
642{
643 cstring all_fields_ansi;
644 all_fields_ansi.erase();
645 all_fields_ansi = record_.substr(leader_directory_.base_, GetFieldSize());
646 PRECONDITION(fields_.empty() && tags_.empty());
647
648
649 // Build the map from tags to fields
650 for (int i=0; i!=GetNvf(); ++i)
651 {
652 //int all_len = all_fields.length();
653 //if (pos>all_len || pos+len>all_len)
654 // return false;
655 cstring field_ansi =
656 all_fields_ansi.substr(GetFieldPos(i), GetFieldLen(i));
657 ustring field(field_ansi);
658 map<int, ustring>::iterator it = fields_.find(GetFieldTag(i));
659 if (it != fields_.end())
660 {
661 // Repeatable field, several occ
662 it->second += SYSRSEP;
663 it->second += field;
664 }
665 else
666 {
667 fields_.insert(make_pair(GetFieldTag(i), field));
668
669 }
670
671 }
672}
673void MfRecord::MakeTagVector()
674{
675 // Build a vector of tags
676 map<int, ustring>::const_iterator it;
677 for ( it = fields_.begin(); it != fields_.end(); ++it )
678 tags_.push_back(it->first);
679
680 // Sort in ascending order
681 sort(tags_.begin(), tags_.end());
682}
683
684
685//--------------------------------------------------------------------------------------
686// bool MfRecord::DecomposeRecord()
687//
688// Make a memory version of the record to facilitate manipulations.
689//--------------------------------------------------------------------------------------
690bool MfRecord::DecomposeRecord()
691{
692 PRECONDITION(!record_.empty());
693
694 if (record_.length() <= GetLeaderSize())
695 {
696 //VLOG("DecomposeRecord - Error! record_.length()=%d < GetLeaderSize()=%d",record_.length(), GetLeaderSize());
697 return false;
698 }
699
700 // Input the LeaderAndDirectory from a string
701 cstringstream ist(record_,cstringstream::in|cstringstream::binary);
702 if (!(ist >> leader_directory_))
703 return false;
704
705 if (!CheckLeaderAndDirectory())
706 {
707 //VLOG("Record rejected mfn=%ld", GetMfn());
708 return false;
709 }
710
711 //VLOG("Record accepted mfn=%ld", GetMfn());
712
713 MakeTagToFieldMap();
714 MakeTagVector();
715
716 return true;
717}
718
719
720
721void MfRecord::ExtractSubLeader()
722{
723 //PRECONDITION(!record_.empty() && record_.length()>=sizeof(leader_directory_.mfn_)+sizeof(leader_directory_.mfrl_));
724
725 leader_directory_.mfn_ = *(reinterpret_cast<ISIS_LONG*>((char *) record_.c_str()));
726 leader_directory_.mfrl_ = *(reinterpret_cast<ISIS_INT*> ((char *)(record_.c_str()+sizeof(ISIS_LONG))));
727 fix_endianness(leader_directory_.mfn_);
728 fix_endianness(leader_directory_.mfrl_);
729 if (leader_directory_.mfrl_ < 0) leader_directory_.mfrl_ = -leader_directory_.mfrl_; // mfrl can be negative!!!!
730
731 //POSTCONDITION(leader_directory_.mfn_>0 && leader_directory_.mfrl_>=0);
732}
733
734bool MfRecord::CheckLeader()
735{
736 int leader_size = GetLeaderSize();
737 if (leader_directory_.mfn_<=0)
738 return false;
739 if (abs(leader_directory_.mfrl_)<leader_size)
740 return false;
741 return true;
742}
743
744
745bool MfRecord::CheckIntegrity()
746{
747 int leader_size = GetLeaderSize();
748 if (leader_directory_.mfn_<=0)
749 return false;
750 if (abs(leader_directory_.mfrl_)<leader_size)
751 return false;
752 if (leader_directory_.nvf_<0)
753 return false;
754 //if (leader_directory_.base_ != leader_directory_size + leader_directory_.nvf_*sizeof(MAXDIRL))
755 // return false;
756 if (leader_directory_.status_ == 1)
757 return true;
758 else if (leader_directory_.status_ == 0)
759 return true;
760 else
761 return false;
762
763 return true;
764}
765
766
767void MfRecord::Dump()
768{
769
770 ustringstream os;
771 os.str("");
772
773
774 os << "\n================= entry in MfRecord::Dump==============";
775 os << "\n MFN " << GetMfn();
776 os << "\n MFRL " << GetMfrl();
777 os << "\n MFBWB " << GetMfbwb();
778 os << "\n MFBWP " << GetMfbwp();
779 os << "\n BASE " << GetBase();
780 os << "\n NVF " << GetNvf();
781 os << "\n STATUS " << GetStatus();
782 //TRACE(os.str().c_str());
783
784
785 for (int i=0; i<GetNvf(); i++)
786 {
787 ustring stemp;
788 bool rc = GetField(GetDirEntry(i).tag_, stemp);
789 int len;
790 if (rc)
791 {
792 len = 50;
793 if (stemp.length()<len)
794 len = stemp.length();
795 }
796 ustring fld = (rc==false) ? _T("Empty") : stemp.substr(0,len);
797 os.str("");
798 os << _T(" tag=") << ISIS_INT(GetDirEntry(i).tag_)
799 << _T(" pos=") << ISIS_INT(GetDirEntry(i).pos_)
800 << _T(" len=") << ISIS_INT(GetDirEntry(i).len_)
801 << _T(" ") << fld.c_str() << std::endl;
802 TRACE(_T("\n%s"),os.str().c_str());
803 }
804
805 TRACE("\n---------------- exit in MfRecord::Dump-------------");
806}
807
808
809
810
811bool MfRecord::CheckRecord()
812{
813 PRECONDITION(!record_.empty());
814
815 if (record_.length() < GetLeaderSize())
816 {
817 TRACE(_T("\nWrong LeaderAndDirectory in record!"));
818 return false;
819 }
820
821 cstringstream ist(record_,cstringstream::in|cstringstream::binary);
822
823 LeaderAndDirectory leader_directory;
824 ist >> leader_directory;
825
826 if (leader_directory.mfrl_ < 0) // Negative mfrl
827 {
828 //VLOG("CheckRecord - Warning! Negative mfrl - mfn=%d", GetMfn());
829 }
830
831 if (leader_directory.nvf_<=0)
832 {
833 //VLOG("CheckRecord - Warning! mfn=%d nvf=0", leader_directory.mfn_);
834 }
835
836 if (leader_directory.mfn_<=0 || leader_directory.mfrl_<=0 ||
837 leader_directory.base_<0 || leader_directory.nvf_ < 0 ||
838 leader_directory.status_ < 0)
839 {
840 //VLOG("CheckRecord - Corrupted record! leader_directory.mfn_=%d leader_directory.mfrl_=%d leader_directory.base_=%d leader_directory.nvf_=%d leader_directory.status_=%d",
841 // leader_directory.mfn_, leader_directory.mfrl_,
842 // leader_directory.base_, leader_directory.nvf_,
843 // leader_directory.status_);
844 return false;
845 }
846
847
848 int base = GetLeaderSize() + GetDirectorySize();
849
850 if (record_.length() < base)
851 {
852 //VLOG("CheckRecord - Corrupted record! mfn=%d record_.length()=%d base=%d",
853 // leader_directory.mfn_, record_.length(), base);
854 return false;
855 }
856
857 int field_len = 0;
858 for (int i=0; i!=leader_directory.nvf_; ++i)
859 {
860 DirEntry de = leader_directory.dir_[i];
861// if (de.tag_<0 || de.tag_>SHRT_MAX || de.pos_<0 || de.pos_>SHRT_MAX || de.len_<0 || de.len_>SHRT_MAX)
862// {
863// //VLOG("CheckRecord - Corrupted record! mfn=%d tag=%d pos=%d len=%d",
864// // leader_directory.mfn_, de.tag_, de.pos_, de.len_);
865// return false;
866// }
867 if (i>0)
868 {
869 if(de.pos_ != leader_directory.dir_[i-1].pos_+leader_directory.dir_[i-1].len_)
870 {
871 //VLOG("CheckRecord - Position not consistent - mfn=%d",
872 // leader_directory.mfn_);
873 return false;
874 }
875 }
876 field_len += de.len_;
877 }
878
879
880 // Check for bad values
881 if (leader_directory.base_ != base)
882 leader_directory.base_ = base;
883
884 if (record_.length() < base + field_len)
885 {
886 //VLOG("CheckRecord - Corrupted record, record length < base+field_len - mfn=%ld",
887 // leader_directory.mfn_);
888 return false;
889 }
890
891 return true;
892}
893
894void MfRecord::ReadLeader(MfFile& f, long daddr)
895{
896 int leader_size = GetLeaderSize();
897 char* buffer = new char[leader_size];
898 f.Fetch(buffer, leader_size, daddr); // Read record leader
899 Clear();
900 AddToRecord(buffer, leader_size);
901 delete[] buffer;
902}
903
904bool MfRecord::Read(MfFile& f, long mfb, int mfp)
905{
906 //TRACE("\nMfFile::ReadMfRecord -- mfb=%ld mfp=%d", mfb, mfp);
907 PRECONDITION(mfb>0 && mfb<=MAXMFB);
908 long blk;
909 int mfrr, offs, l;
910
911 try
912 {
913 Clear();
914 // Save original mfb, mfp pair into m
915 SetMfbRead(mfb);
916 SetMfpRead(mfp);
917 SetState(MfRecord::Record_Read);
918
919 // Be sure that mfp is in range [0:MFBLKSIZE-1]
920 mfp = mfp%MFBLKSIZE;
921 assert(mfp>=0 && mfp<MFBLKSIZE);
922 //TRACE("\nMfFile::ReadMfRecord - mfb=%ld mfp=%d", mfb, mfp);
923
924 // 1 - Read block where record starts
925 f.ReadBlk(m_buf,mfb);
926
927 blk = mfb;
928 // 2 - Extract the record leader (Mfn+Mfrl) from the block buffer, the
929 // record leader cannot be split on two consecutive blocks.
930 int len = GetSubLeaderSize(); // Mfn + Mfrl
931 ASSERT(mfp+len<MFBLKSIZE);
932
933 AddToRecord(m_buf+mfp, len); // Move 1st 6 bytes (Mfn+Mfrl)
934 ExtractSubLeader();
935
936 // 3 - Continue to transfer data for building the MfRecord object
937 int mflen = GetMfrl(); // Get record length
938 SetMflenRead(mflen); // Save it
939 //TRACE("\nMfFile::readMfRecord - After reading leader mfn=%ld mflen=%d",GetMfn(), mflen);
940 mfrr = mflen - len; // Not yet moved
941 l = (mfrr > (f.GetBlockSize()-(mfp+len))) // What remains to move
942 ? (f.GetBlockSize()-(mfp+len)) : mfrr; // in this block
943 offs = len;
944 AddToRecord(m_buf+mfp+len, l); // Move-it
945 mfrr -= l;
946 while (mfrr>0) // Record continues on next block ?
947 {
948 f.ReadBlk(m_buf,++blk); // Yes read next block
949 offs += l;
950 l = (mfrr > f.GetBlockSize()) ? f.GetBlockSize() : mfrr;
951 AddToRecord(m_buf, l); // Move data
952 mfrr -= l;
953 }
954 //TRACE("\nMfFile::ReadMfRecord -- mfb=%ld mfp=%d nvf=%d", mfb, mfp, GetNvf());
955 }
956 catch (CFileBaseException e)
957 {
958 throw CIsisDbException(ISIS_MF_READ_ERROR, __FILE__, __LINE__);
959 }
960
961 return DecomposeRecord();
962}
963
964
965void MfRecord::Write(MfFile& f, long mfb, int mfp)
966{
967 TRACE(_T("\nMfFile::writeMfRecord - mfb=%ld mfp=%d"), mfb, mfp);
968 PRECONDITION(mfb>0 && mfb <= MAXMFB);
969 // Be sure that mfp is in range [0:MFBLKSIZE-1]
970 mfp = mfp%MFBLKSIZE;
971
972 long hiblk = f.GetNextMfb(); // Highest block number in master file
973
974 int s = 0; // Index in master file record [0:mfrl-1]
975 int d = mfp; // Index in block buffer [0:bsize-1]
976 long b = mfb; // Starting block number
977
978 // Adjust record length
979 int padding = GetMfrl() % MFALIGN;
980 if (padding>0)
981 {
982 SetMfrl(GetMfrl() + padding);
983 for (int i=0; i<padding;i++)
984 AddToRecord(" ", 1);
985 }
986
987 int mfrl = GetMfrl();
988 TRACE(_T("\nMfFile::writeMfRecord - b=%ld d=%d mfrl=%ld hiblk=%ld"), b, d, mfrl, hiblk);
989 TRACE(_T("\nBefore writing->"));
990 do
991 {
992 if (b <= hiblk)
993 f.ReadBlk(m_buf, b);
994 else
995 ::memset(m_buf, ' ', MFBLKSIZE);
996
997 while (d < MFBLKSIZE && s < mfrl)
998 m_buf[d++] = record_.at(s++);
999 if (d >= MFBLKSIZE)
1000 {
1001 TRACE(_T("MfFile::WriteMfRecord - Before WriteBlk b=%ld"), b);
1002 f.SetLastWrittenBlock(b);
1003 f.WriteBlk(m_buf, b++);
1004 // Reset m_buf pos
1005 d = 0;
1006 }
1007 } while (s < mfrl);
1008
1009 // Write last block
1010 if (d == 0)
1011 ::memset(m_buf, ' ', MFBLKSIZE); // Should be an empty block
1012
1013 f.WriteBlk(m_buf, b);
1014 f.SetLastWrittenBlock(b);
1015}
1016
1017void IntToChar(int value, int width, std::string& s)
1018{
1019 std::ostringstream ost;
1020
1021#ifdef _WIN32
1022 ost.setf(std::ios_base::right, std::ios_base::adjustfield);
1023#endif
1024 ost << std::setw(width)
1025 << std::setfill('0')
1026 << value;
1027 s = ost.str();
1028}
1029//--------------------------------------------------------------------------------------
1030// void MfRecord::MakeISORecord(std::string& s)
1031//
1032// Build the record into continuous bytes for output
1033//--------------------------------------------------------------------------------------
1034void MfRecord::MakeISORecord(std::string& s)
1035{
1036 std::string tmp;
1037
1038 MarcLeader l;
1039
1040 // 1 - Complete the leader (base and record length), output the directory
1041 // to a string and prepare a string with the data fields
1042 int base = MARC_LEADER_LEN + GetNvf()*MARC_DIRENT_LEN + 1;
1043 IntToChar(base, 5, tmp);
1044 strncpy(l.base_ ,tmp.c_str(),5);
1045
1046 DirectoryEntry mde;
1047 ustring all_fields;
1048 all_fields.erase();
1049 ostringstream osd; // Output the directory to a string
1050 int pos = 0;
1051 for (int i=0; i!=GetNvf(); ++i)
1052 {
1053 IntToChar(GetFieldTag(i), 3, tmp);
1054 strncpy(mde.tag_,tmp.c_str(),3);
1055 int len = GetFieldLen(i)+1; // Include space for separator
1056 IntToChar(len, 4, tmp);
1057 strncpy(mde.len_, tmp.c_str(), 4);
1058 IntToChar(pos, 5, tmp);
1059 strncpy(mde.scp_, tmp.c_str(), 5);
1060 osd << mde;
1061 pos += len;
1062
1063 cstring field = record_.substr(GetBase()+GetFieldPos(i), GetFieldLen(i));
1064 all_fields += ustring(field);
1065 all_fields += FIELDTERM;
1066 }
1067 // (+2) ->Field sep at end of directory and record sep
1068 int reclen = MARC_LEADER_LEN + GetNvf()*MARC_DIRENT_LEN + pos +2;
1069 IntToChar(reclen, 5, tmp);
1070 strncpy(l.lreclen_,tmp.c_str(),5);
1071
1072
1073 ostringstream osl; // Output the Leader to a string
1074 osl << l;
1075
1076 // 2 - Make record
1077 s.erase(); // Empty the record
1078 s += osl.str(); // Add the leader
1079 s += osd.str(); // Add the directory
1080 s += FIELDTERM; // Separator
1081 s += cstring(all_fields); // Data part
1082 s += RECTERM;
1083
1084}
Note: See TracBrowser for help on using the repository browser.