source: trunk/gsdl/packages/isis-gdl/Master.cpp@ 7135

Last change on this file since 7135 was 7135, checked in by mdewsnip, 20 years ago

Changed the name of a variable to prevent a stupid compilation error with Visual C++.

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