1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/store/HTOOLS/PFSDUMP.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,861 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "PFSDUMP.H"
1.20 +
1.21 +// entry point
1.22 +
1.23 +int main(int argc,char *argv[])
1.24 + {
1.25 + if (TheProgram.ProcessCommandLine(argc,argv))
1.26 + {
1.27 + TheProgram.ExplainUsage();
1.28 + return 1;
1.29 + }
1.30 + TheProgram.Run();
1.31 + return 0;
1.32 + }
1.33 +
1.34 +// Class Program
1.35 +
1.36 +class Program TheProgram;
1.37 +
1.38 +Program::Program()
1.39 + : iFile(NULL),iOptions(0),iBin(&iBinBuf),iErrors(0)
1.40 + {
1.41 + cout << setfill('0');
1.42 + }
1.43 +
1.44 +void Program::Information()
1.45 + {
1.46 + if (!Option(quiet))
1.47 + cout << "\nEPOC PermanentFileStore Dump Utility Version " << MajorVersion << '.' \
1.48 + << setw(2) << MinorVersion << "(build " << setw(3) << setfill('0') << Build \
1.49 + << ")\nCopyright (c) Symbian Software Limited 1997-2004. All rights reserved.\n\n" << flush;
1.50 + cout << hex;
1.51 + cerr << hex;
1.52 + }
1.53 +
1.54 +void Program::ExplainUsage()
1.55 + {
1.56 + Information();
1.57 + cout << "Usage: PFSDUMP [options] storefile\n" \
1.58 + " -v verbose: dump contents\n" \
1.59 + " -f generate a frame dump\n" \
1.60 + " -r<n> use nth previous store revision\n" \
1.61 + " -c format output for comparison (not for frame dumps)\n"
1.62 + " -q quiet: suppress logo\n" << flush;
1.63 + }
1.64 +
1.65 +int Program::ProcessCommandLine(int argc,char ** argv)
1.66 + {
1.67 + if (argc<2)
1.68 + return 1;
1.69 +
1.70 + int options=0;
1.71 + while (--argc>0)
1.72 + {
1.73 + istrstream arg(*++argv);
1.74 + int c=arg.get();
1.75 + if (c=='/' || c=='-')
1.76 + {
1.77 + while ((c=arg.get())!=EOF)
1.78 + {
1.79 + switch (c)
1.80 + {
1.81 + case 'c': case 'C':
1.82 + options|=compare;
1.83 + break;
1.84 + case 'f': case 'F':
1.85 + options|=frame;
1.86 + break;
1.87 + case 'q': case 'Q':
1.88 + options|=quiet;
1.89 + break;
1.90 + case 'r': case 'R':
1.91 + arg >> iTocRevision;
1.92 + if (arg.fail() || iTocRevision<0)
1.93 + return 1;
1.94 + break;
1.95 + case 'v': case 'V':
1.96 + options|=verbose;
1.97 + break;
1.98 + default: // unrecognised option
1.99 + return 1;
1.100 + }
1.101 + }
1.102 + }
1.103 + else if (iFile!=NULL)
1.104 + return 1; // two filenames?
1.105 + else
1.106 + iFile=arg.str();
1.107 + }
1.108 + if (options&frame)
1.109 + options&=~compare;
1.110 + iOptions=options;
1.111 + return iFile==NULL;
1.112 + }
1.113 +
1.114 +void Program::Run()
1.115 +//
1.116 +// The main part of the program
1.117 +//
1.118 + {
1.119 + Information();
1.120 + StoreFile store(iFile);
1.121 + if (iErrors)
1.122 + cerr << endl;
1.123 + if (store.Empty())
1.124 + {
1.125 + cout << "Store is empty" << endl;
1.126 + return;
1.127 + }
1.128 + if (Option(frame))
1.129 + {
1.130 + store.EmitHeader();
1.131 + store.EmitFrames();
1.132 + }
1.133 + store.EmitToc();
1.134 + if (!Option(frame))
1.135 + store.EmitStreams();
1.136 + }
1.137 +
1.138 +void Program::Abort(char const* aMessage)
1.139 + {
1.140 + cerr << aMessage << endl;
1.141 + exit(3);
1.142 + }
1.143 +
1.144 +void Program::Corrupt(char const* aMessage)
1.145 +//
1.146 +// terminate after detecting a fatal corruption error
1.147 +//
1.148 + {
1.149 + cerr << "\nfatal error: " << aMessage << "\ncannot continue\n" << flush;
1.150 + exit(2);
1.151 + }
1.152 +
1.153 +ostream& Program::Error()
1.154 + {
1.155 + ++TheProgram.iErrors;
1.156 + return cerr << "error: ";
1.157 + }
1.158 +
1.159 +ostream& Program::Warning()
1.160 + {
1.161 + ++TheProgram.iErrors;
1.162 + return cerr << "warning: ";
1.163 + }
1.164 +
1.165 +// Bin stream buffer
1.166 +
1.167 +binbuf::binbuf()
1.168 + : streambuf()
1.169 + {}
1.170 +
1.171 +int binbuf::overflow(int)
1.172 + {return 0;}
1.173 +
1.174 +int binbuf::underflow()
1.175 + {return EOF;}
1.176 +
1.177 +// Class StoreFile
1.178 +
1.179 +int StoreFile::OutWidth;
1.180 +
1.181 +StoreFile::StoreFile(char const* aFile)
1.182 + {
1.183 +#ifdef __MSVCDOTNET__
1.184 + iFile.open(aFile, ios::binary);
1.185 +#else //!__MSVCDOTNET__
1.186 + iFile.open(aFile, ios::binary | ios::nocreate);
1.187 +#endif //__MSVCDOTNET__
1.188 + if (!iFile)
1.189 + Program::Abort("Unable to open file or file does not exist");
1.190 +//
1.191 + unsigned long uid;
1.192 + iFile.read((char*)&uid,sizeof(uid));
1.193 + iFile.seekg(0,ios::end);
1.194 + int size=iFile.tellg();
1.195 + if (size<FrameDes::First || uid!=PermanentFileStoreUid)
1.196 + Program::Abort("Not a permanent file store");
1.197 +//
1.198 + iSize=size;
1.199 + if (TheProgram.Option(Program::compare))
1.200 + OutWidth=7;
1.201 + else
1.202 + {
1.203 + int width=0;
1.204 + while (size)
1.205 + {
1.206 + ++width;
1.207 + size>>=4;
1.208 + }
1.209 + OutWidth=width;
1.210 + }
1.211 +//
1.212 + cout << "Dumping " << aFile << "\n\n";
1.213 +//
1.214 + iFile.seekg(Header::Offset,ios::beg);
1.215 + iFile.read((char*)&iHeader,Header::Size);
1.216 +//
1.217 + if (Empty())
1.218 + return;
1.219 + LoadFrames();
1.220 + LoadToc();
1.221 + }
1.222 +
1.223 +StoreFile::~StoreFile()
1.224 + {
1.225 + iFile.close();
1.226 + }
1.227 +
1.228 +void StoreFile::LoadFrames()
1.229 + {
1.230 + FrameDes frame;
1.231 + int offset=FrameDes::First;
1.232 + int full=FrameDes::First+FrameDes::Interval;
1.233 + int diff=FrameDes::First;
1.234 +
1.235 + while (offset-FrameDes::Size<iSize)
1.236 + {
1.237 + if (offset==full)
1.238 + {
1.239 + full+=FrameDes::Interval;
1.240 + diff+=FrameDes::Size;
1.241 + }
1.242 + if (offset>iSize)
1.243 + {
1.244 + Program::Warning() << "incomplete link at " << FramePos(offset-diff) << endl;
1.245 + break;
1.246 + }
1.247 + iFile.seekg(offset-FrameDes::Size,ios::beg);
1.248 + iFile >> frame;
1.249 + iFrames.Add(FramePos(offset-diff),frame);
1.250 + int length=frame.Length();
1.251 + if (length==0)
1.252 + {
1.253 + if (full>iSize && offset>iSize)
1.254 + Program::Warning() << "incomplete frame at " << FramePos(offset-diff) << endl;
1.255 + offset=full;
1.256 + }
1.257 + else
1.258 + {
1.259 + int newoffset=offset+length+FrameDes::Size;
1.260 + if (newoffset>=full || newoffset-FrameDes::Size>iSize)
1.261 + {
1.262 + Program::Error() << "bad link at " << FramePos(offset-diff) << ", skipping to next anchor link" << endl;
1.263 + offset=full;
1.264 + }
1.265 + else
1.266 + {
1.267 + offset=newoffset;
1.268 + if (full-offset<=FrameDes::Size)
1.269 + offset=full;
1.270 + }
1.271 + }
1.272 + }
1.273 + iFrames.Complete();
1.274 + }
1.275 +
1.276 +void StoreFile::LoadToc()
1.277 + {
1.278 + FramePos toc=iHeader.Toc();
1.279 + Stream stream(iFrames,toc);
1.280 + if (!stream.IsGood())
1.281 + {
1.282 + Program::Error() << "invalid toc address " << toc << endl;
1.283 + return;
1.284 + }
1.285 + if (stream.Type()!=FrameDes::Toc)
1.286 + {
1.287 + Program::Error() << "toc address " << toc << ": refers to non-toc frame"<< endl;
1.288 + return;
1.289 + }
1.290 +
1.291 +// find the requested store revision
1.292 + Frames::Iterator f=stream.Frame();
1.293 + Frames::Iterator const first=iFrames.Begin();
1.294 + for (int rev=TheProgram.TocRevision();rev;--rev)
1.295 + {
1.296 + do {
1.297 + if (--f<first)
1.298 + Program::Abort("Store revision not found");
1.299 + } while (f->iDes.Type()!=FrameDes::Toc);
1.300 + }
1.301 +
1.302 + iToc.Load(iFile,iFrames,f,iHeader.GetReloc());
1.303 +
1.304 +// verify the Toc stream references
1.305 + Toc::Iterator const end=iToc.End();
1.306 + for (Toc::Iterator iter=iToc.Begin();iter<end;++iter)
1.307 + {
1.308 + if (iter->iHandle.IsNull())
1.309 + Program::Error() << "missing entry in toc-delta for index " << (1+iter-iToc.Begin()) << endl;
1.310 + else if (!iter->iHandle.Avail() && iter->Pos().Pos()>=0)
1.311 + {
1.312 + f=iFrames.Find(iter->Pos());
1.313 + if (f==NULL)
1.314 + Program::Error() << "invalid stream reference in toc entry " << iter->iHandle << endl;
1.315 + else if (iter->Pos().Pos()>=toc.Pos())
1.316 + Program::Error() << "virtual stream reference in toc entry " << iter->iHandle << endl;
1.317 + else if (f->iDes.Type()!=FrameDes::Data)
1.318 + Program::Error() << "toc entry " << iter->iHandle << ": refers to non-data frame" << endl;
1.319 + }
1.320 + }
1.321 + }
1.322 +
1.323 +void StoreFile::EmitHeader()
1.324 + {
1.325 + cout << iHeader;
1.326 + }
1.327 +
1.328 +void StoreFile::EmitFrames()
1.329 + {
1.330 + int verbose=TheProgram.Option(Program::verbose);
1.331 + Frames::Iterator const end=iFrames.End();
1.332 + for (Frames::Iterator iter=iFrames.Begin();iter<end;++iter)
1.333 + {
1.334 + FramePos pos=iter->iPos;
1.335 + cout << "Frame at " << pos << ": " << iter->iDes << endl;
1.336 + if (!verbose)
1.337 + continue;
1.338 +
1.339 + // dump contents
1.340 + int length=iter->iDes.Length();
1.341 + if (length==0)
1.342 + { // full frame
1.343 + if (iter+1==end) // no more
1.344 + continue;
1.345 + length=iter[1].iPos.Pos()-pos.Pos();
1.346 + }
1.347 + HexDump hex;
1.348 + iFile.seekg(FileOffset(pos).Offset(),ios::beg);
1.349 + hex.Dump(iFile,length);
1.350 + hex.Flush();
1.351 + cout << endl;
1.352 + }
1.353 + cout << endl;
1.354 + }
1.355 +
1.356 +void StoreFile::EmitToc()
1.357 + {
1.358 + cout << iToc;
1.359 + }
1.360 +
1.361 +void StoreFile::EmitStreams()
1.362 + {
1.363 + int verbose=TheProgram.Option(Program::verbose);
1.364 + cout << endl;
1.365 + Toc::Iterator const end=iToc.End();
1.366 + for (Toc::Iterator iter=iToc.Begin();iter<end;++iter)
1.367 + {
1.368 + if (!iter->iHandle.Avail())
1.369 + {
1.370 + cout << "Stream " << iter->iHandle;
1.371 + if (iter->Pos().Pos()==-1)
1.372 + {
1.373 + cout << " is empty\n";
1.374 + continue;
1.375 + }
1.376 + if (!TheProgram.Option(Program::compare))
1.377 + cout << " at " << iter->Pos();
1.378 + Stream stream(iFrames,iter->Pos());
1.379 + if (!stream.IsGood() || stream.Type()!=FrameDes::Data)
1.380 + {
1.381 + cout << " is invalid\n";
1.382 + continue;
1.383 + }
1.384 + int len=stream.Length();
1.385 + cout << ", " << dec << len << hex << " byte" << (len==1 ? "\n" : "s\n");
1.386 + if (!verbose)
1.387 + continue;
1.388 +
1.389 + // dump contents
1.390 + HexDump hex;
1.391 + Frames::Iterator f=stream.Frame();
1.392 + do
1.393 + {
1.394 + FramePos pos=f->iPos;
1.395 + int len=f++->iDes.Length();
1.396 + if (len==0)
1.397 + len=f->iPos.Pos()-pos.Pos();
1.398 + iFile.seekg(FileOffset(pos).Offset(),ios::beg);
1.399 + hex.Dump(iFile,len);
1.400 + } while (f->iDes.Type()==FrameDes::Continuation);
1.401 + hex.Flush();
1.402 + cout << endl;
1.403 + }
1.404 + }
1.405 + }
1.406 +
1.407 +// Class HexDump
1.408 +
1.409 +HexDump::HexDump()
1.410 + : iPos(0),iByte(0)
1.411 + {
1.412 + Reset();
1.413 + }
1.414 +
1.415 +HexDump::~HexDump()
1.416 + {
1.417 + Flush();
1.418 + }
1.419 +
1.420 +void HexDump::Reset()
1.421 + {
1.422 + memset(iChar,' ',HexInterval+3);
1.423 + iChar[HexInterval+3]=0;
1.424 + iPtr=&iChar[2];
1.425 + }
1.426 +
1.427 +void HexDump::Dump(istream& aStream,int aBytes)
1.428 + {
1.429 + while (--aBytes>=0 && !aStream.eof())
1.430 + {
1.431 + if (iByte==0)
1.432 + cout << Margin << FileOffset(iPos) << ':';
1.433 + int c=aStream.get();
1.434 + cout << ' ' << setw(2) << c;
1.435 + *iPtr++=char(isprint(c) ? c : '.');
1.436 + if (++iByte==HexInterval/2)
1.437 + {
1.438 + cout << ' ';
1.439 + ++iPtr;
1.440 + }
1.441 + else if (iByte==HexInterval)
1.442 + Flush();
1.443 + }
1.444 + }
1.445 +
1.446 +void HexDump::Flush()
1.447 + {
1.448 + if (iByte)
1.449 + {
1.450 + for (int ii=iByte;ii<HexInterval;++ii)
1.451 + cout << " ";
1.452 + if (iByte<HexInterval/2)
1.453 + cout << ' ';
1.454 + cout << iChar << endl;
1.455 + iPos+=iByte;
1.456 + iByte=0;
1.457 + Reset();
1.458 + }
1.459 + }
1.460 +
1.461 +// Toc
1.462 +
1.463 +Toc::Toc()
1.464 + : iPos(0), iRep(NULL), iAvail(0)
1.465 + {
1.466 + memset(&iHeader,0,sizeof(iHeader));
1.467 + }
1.468 +
1.469 +Toc::~Toc()
1.470 + {
1.471 + free(iRep);
1.472 + }
1.473 +
1.474 +
1.475 +void Toc::Base(const char* aPtr,int aCount)
1.476 + {
1.477 + Entry* e=iRep;
1.478 + for (int i=1;i<=aCount;++e,++i)
1.479 + {
1.480 + e->iHandle=i; // set the index part
1.481 + memcpy((char*)e+Entry::BaseRedundant,aPtr,Entry::BaseSize);
1.482 + aPtr+=Entry::BaseSize;
1.483 + }
1.484 + }
1.485 +
1.486 +void Toc::Load(istream& aStream,Frames const& aFrames,Frames::Iterator aFrame,Header::Reloc const* aReloc)
1.487 + {
1.488 + iPos = aFrame->iPos;
1.489 +
1.490 + Stream toc1(aFrame);
1.491 + void* toc = toc1.Load(aStream);
1.492 + const char* p = reinterpret_cast<char*>(toc);
1.493 + memcpy(&iHeader,p,Head::Size);
1.494 + p+=Head::Size;
1.495 + int n = iHeader.iCount;
1.496 + if (n < 0)
1.497 + {
1.498 + memset(&iHeader,0,Head::Size);
1.499 + Program::Error() << "corrupt toc" << endl;
1.500 + return;
1.501 + }
1.502 + iRep=static_cast<Entry*>(malloc(n*sizeof(Entry)));
1.503 + if (iRep==NULL)
1.504 + Program::Abort("Out of memory");
1.505 +
1.506 + if (iHeader.IsDelta())
1.507 + {
1.508 + // verify the delta header
1.509 + memcpy(&iDelta,p,DeltaHead::Size);
1.510 + p+=DeltaHead::Size;
1.511 + int dn = iDelta.iCount;
1.512 + if (toc1.Length() != Head::Size + DeltaHead::Size + dn * Entry::DeltaSize)
1.513 + {
1.514 + memset(&iHeader,0,Head::Size);
1.515 + Program::Error() << "incomplete toc" << endl;
1.516 + return;
1.517 + }
1.518 +
1.519 + // find the toc-base
1.520 + FramePos tocbase(iDelta.iBase + Header::tocoffset);
1.521 + if (aReloc && aReloc->iHandle.IsTocBase())
1.522 + tocbase = aReloc->iPos;
1.523 + Stream toc2(aFrames,tocbase);
1.524 + if (!toc2.IsGood())
1.525 + {
1.526 + memset(&iHeader,0,Head::Size);
1.527 + Program::Error() << "invalid toc-base address " << tocbase << endl;
1.528 + return;
1.529 + }
1.530 + if (toc2.Type()!=FrameDes::Toc)
1.531 + {
1.532 + memset(&iHeader,0,Head::Size);
1.533 + Program::Error() << "toc-base address " << tocbase << ": refers to non-toc frame"<< endl;
1.534 + return;
1.535 + }
1.536 +
1.537 + // validate and load the toc-base
1.538 + void* tocb = toc2.Load(aStream);
1.539 + const char* p2 = reinterpret_cast<char*>(tocb);
1.540 + Head headbase;
1.541 + memcpy(&headbase,p2,Head::Size);
1.542 + p2+=Head::Size;
1.543 + if (headbase.IsDelta())
1.544 + {
1.545 + memset(&iHeader,0,Head::Size);
1.546 + Program::Error() << "toc-base is a toc-delta"<< endl;
1.547 + return;
1.548 + }
1.549 + int bn = headbase.iCount;
1.550 + if (bn > n)
1.551 + {
1.552 + memset(&iHeader,0,Head::Size);
1.553 + Program::Error() << "toc-base is larger than toc"<< endl;
1.554 + return;
1.555 + }
1.556 + Base(p2,bn);
1.557 + free(tocb);
1.558 +
1.559 + // validate and update with the toc-delta
1.560 + int last = 0;
1.561 + while (--dn>=0)
1.562 + {
1.563 + Entry e;
1.564 + memcpy(&e,p,Entry::DeltaSize);
1.565 + p+=Entry::DeltaSize;
1.566 + int ix = e.iHandle.Index();
1.567 + if (ix<=0 || ix > n)
1.568 + {
1.569 + memset(&iHeader,0,Head::Size);
1.570 + Program::Error() << "toc-delta entry " << e.iHandle << " is outside toc"<< endl;
1.571 + return;
1.572 + }
1.573 + if (ix <= last)
1.574 + {
1.575 + memset(&iHeader,0,Head::Size);
1.576 + Program::Error() << "toc-delta entry " << e.iHandle << " is out of order"<< endl;
1.577 + return;
1.578 + }
1.579 + iRep[ix-1] = e;
1.580 + last = ix;
1.581 + }
1.582 + }
1.583 + else
1.584 + {
1.585 + if (toc1.Length() != Head::Size + n * Entry::BaseSize)
1.586 + {
1.587 + memset(&iHeader,0,Head::Size);
1.588 + Program::Error() << "incomplete toc" << endl;
1.589 + return;
1.590 + }
1.591 + Base(p,n);
1.592 + }
1.593 + free(toc);
1.594 +
1.595 + // apply the relocation
1.596 + if (aReloc && !aReloc->iHandle.IsTocBase())
1.597 + {
1.598 + int ix=aReloc->iHandle.Index();
1.599 + if (ix<=0 || ix>n)
1.600 + Program::Corrupt("invalid index in relocation patch");
1.601 +
1.602 + Entry& e=iRep[ix-1];
1.603 + if (e.iHandle.Generation()!=aReloc->iHandle.Generation())
1.604 + Program::Corrupt("incorrect generation in relocation patch");
1.605 + e.iPos=aReloc->iPos.Pos();
1.606 + }
1.607 +
1.608 + // count the available entries
1.609 + int avail=0;
1.610 + for (int i=0;i<n;++i)
1.611 + {
1.612 + if (iRep[i].iHandle.Avail())
1.613 + ++avail;
1.614 + }
1.615 + iAvail=avail;
1.616 +
1.617 +// verify the available list
1.618 + Handle link=iHeader.iAvail;
1.619 + if (!link.IsNull())
1.620 + {
1.621 + int ix=link.Index();
1.622 + if (!link.Avail() || ix<=0 || ix >iHeader.iCount)
1.623 + {
1.624 +eAvail: Program::Error() << "corrupt available link in toc header " << link << endl;
1.625 + return;
1.626 + }
1.627 + Entry const* en=&(*this)[ix];
1.628 + if (en->iHandle!=link)
1.629 + goto eAvail;
1.630 + for (;;)
1.631 + {
1.632 + if (--avail<0)
1.633 + {
1.634 + Program::Error() << "corrupt available list, possible circular reference" << endl;
1.635 + return;
1.636 + }
1.637 + Handle next=en->Link();
1.638 + if (next.IsNull())
1.639 + break;
1.640 + ix=next.Index();
1.641 + if (!next.Avail() || ix<=0 || ix >iHeader.iCount)
1.642 + {
1.643 +eLink: Program::Error() << "corrupt link in toc entry " << link << endl;
1.644 + return;
1.645 + }
1.646 + en=&(*this)[ix];
1.647 + if (en->iHandle!=next)
1.648 + goto eLink;
1.649 + link=next;
1.650 + }
1.651 + }
1.652 + if (avail!=0)
1.653 + Program::Error() << "corrupt available list: free index leakage" << endl;
1.654 + }
1.655 +
1.656 +ostream& operator<<(ostream& aStream,Toc const& aToc)
1.657 + {
1.658 + int all=TheProgram.Option(Program::frame);
1.659 +
1.660 + Toc::Head const& head=aToc.iHeader;
1.661 + if (TheProgram.Option(Program::compare))
1.662 + aStream << "Toc: ";
1.663 + else
1.664 + aStream << "Toc at " << aToc.iPos << " with ";
1.665 + aStream << dec << head.iCount << (head.iCount==1 ? " entry: " : " entries: ") \
1.666 + << head.iCount-aToc.iAvail << " allocated, " << aToc.iAvail << " free\n" << hex;
1.667 + if (!all)
1.668 + aStream << "root is " << head.Root() << '\n';
1.669 + else
1.670 + {
1.671 + aStream << "first available is " << head.iAvail << '\n';
1.672 + Toc::Iterator const end=aToc.End();
1.673 + for (Toc::Iterator iter=aToc.Begin();iter<end;++iter)
1.674 + {
1.675 + aStream << (iter->iHandle==head.Root() ? "* " : Margin) << iter->iHandle;
1.676 + if (iter->iHandle.Avail())
1.677 + aStream << " free -> " << iter->Link() << '\n';
1.678 + else if (iter->Pos().Pos()==-1)
1.679 + aStream << " empty\n";
1.680 + else
1.681 + aStream << " alloc at " << iter->Pos() << '\n';
1.682 + }
1.683 + }
1.684 + return aStream << flush;
1.685 + }
1.686 +
1.687 +// Class Stream
1.688 +
1.689 +int Stream::Length() const
1.690 + {
1.691 + int total=0;
1.692 + Frames::Iterator f=iFrame;
1.693 + do {
1.694 + int len=f->iDes.Length();
1.695 + if (len==0)
1.696 + len=f[1].iPos.Pos()-f[0].iPos.Pos();
1.697 + total+=len;
1.698 + } while ((++f)->iDes.Type()==FrameDes::Continuation);
1.699 + return total;
1.700 + }
1.701 +
1.702 +void* Stream::Load(istream& aStream) const
1.703 + {
1.704 + int size = Length();
1.705 + void* data = malloc(size);
1.706 + if (data==NULL)
1.707 + Program::Abort("Out of memory");
1.708 +
1.709 + char* read=reinterpret_cast<char*>(data);
1.710 + Frames::Iterator f = iFrame;
1.711 + do
1.712 + {
1.713 + FramePos pos=f->iPos;
1.714 + int len=f++->iDes.Length();
1.715 + if (len==0)
1.716 + len=f->iPos.Pos()-pos.Pos();
1.717 + aStream.seekg(FileOffset(pos).Offset(),ios::beg);
1.718 + aStream.read(read,len);
1.719 + read+=len;
1.720 + } while (f->iDes.Type()==FrameDes::Continuation);
1.721 +
1.722 + return data;
1.723 + }
1.724 +
1.725 +// Class Frames
1.726 +
1.727 +Frames::Frames()
1.728 + : iSize(0),iElements(0),iRep(NULL)
1.729 + {}
1.730 +
1.731 +Frames::~Frames()
1.732 + {
1.733 + free(iRep);
1.734 + }
1.735 +
1.736 +void Frames::Add(FramePos aPos,FrameDes aDes)
1.737 + {
1.738 + if (iElements==iSize)
1.739 + {
1.740 + iSize=iSize==0 ? 128 : iSize+iSize;
1.741 + void* rep=realloc(iRep,iSize*sizeof(*iRep));
1.742 + if (rep==NULL)
1.743 + Program::Abort("Out of memory");
1.744 + iRep=(Element*)rep;
1.745 + }
1.746 + Element& element=iRep[iElements++];
1.747 + element.iPos=aPos;
1.748 + element.iDes=aDes;
1.749 + }
1.750 +
1.751 +void Frames::Complete()
1.752 +//
1.753 +// add a terminating entry
1.754 +//
1.755 + {
1.756 + Add(0,0);
1.757 + --iElements;
1.758 + }
1.759 +
1.760 +Frames::Iterator Frames::Find(FramePos aPos) const
1.761 + {
1.762 + return (Element const*)bsearch(&aPos,iRep,iElements,sizeof(*iRep),Compare);
1.763 + }
1.764 +
1.765 +int Frames::Compare(void const* aLeft,void const* aRight)
1.766 + {
1.767 + int left=static_cast<FramePos const*>(aLeft)->Pos();
1.768 + int right=static_cast<Element const*>(aRight)->iPos.Pos();
1.769 + if (left<right)
1.770 + return -1;
1.771 + if (left>right)
1.772 + return 1;
1.773 + return 0;
1.774 + }
1.775 +
1.776 +// Header
1.777 +
1.778 +FramePos Header::Toc() const
1.779 + {
1.780 + return tocoffset+(!Dirty() && iToc.iZero==0 ? iToc.iPos : iBackupToc>>backupshift);
1.781 + }
1.782 +
1.783 +Header::Reloc const* Header::GetReloc() const
1.784 + {
1.785 + return (Dirty() || iToc.iZero==0) ? NULL : reinterpret_cast<Reloc const*>(&iReloc);
1.786 + }
1.787 +
1.788 +ostream& operator<<(ostream& aStream,Header const& aHeader)
1.789 + {
1.790 + aStream << "Header is " << (aHeader.Dirty() ? "dirty" : "clean");
1.791 + Header::Reloc const* reloc=aHeader.GetReloc();
1.792 + if (reloc!=NULL)
1.793 + {
1.794 + aStream << "\npending relocation of ";
1.795 + if (reloc->iHandle.IsTocBase())
1.796 + aStream << "toc-base";
1.797 + else
1.798 + aStream << "stream " << StreamId(reloc->iHandle);
1.799 + aStream << " to " << reloc->iPos;
1.800 + }
1.801 + return aStream << "\n\n" << flush;
1.802 + }
1.803 +
1.804 +// FileOffset
1.805 +
1.806 +FileOffset::FileOffset(FramePos aPos)
1.807 +// calculate the file offset for a streampos
1.808 + {
1.809 + int pos=aPos.Pos();
1.810 + int n=pos>>FrameDes::FullShift;
1.811 + pos+=FrameDes::Size*n+FrameDes::First;
1.812 + iValue=pos;
1.813 + }
1.814 +
1.815 +FileOffset::operator FramePos() const
1.816 + {
1.817 + int pos=iValue-FrameDes::First;
1.818 + int n=pos/FrameDes::Interval;
1.819 + pos-=n*FrameDes::Size;
1.820 + return FramePos(pos);
1.821 + }
1.822 +
1.823 +ostream& operator<<(ostream& aStream,FileOffset anOffset)
1.824 + {
1.825 + return aStream << setw(StoreFile::OutWidth) << anOffset.iValue;
1.826 + }
1.827 +
1.828 +// Handle
1.829 +
1.830 +ostream& operator<<(ostream& aStream,Handle aHandle)
1.831 + {
1.832 + if (aHandle.IsNull())
1.833 + aStream << "Null";
1.834 + else
1.835 + aStream << setw(6) << aHandle.Index() << ':' << aHandle.Generation();
1.836 + return aStream;
1.837 + }
1.838 +
1.839 +// FramePos
1.840 +
1.841 +ostream& operator<<(ostream& aStream,FramePos aPos)
1.842 + {
1.843 + return aStream << setw(StoreFile::OutWidth) << aPos.iValue << '[' << FileOffset(aPos) << ']';
1.844 + }
1.845 +
1.846 +// FrameDes
1.847 +
1.848 +istream& operator>>(istream& aStream,FrameDes& aFrame)
1.849 + {
1.850 + return aStream.read((char*)&aFrame,FrameDes::Size);
1.851 + }
1.852 +
1.853 +ostream& operator<<(ostream& aStream,FrameDes aFrame)
1.854 + {
1.855 + static char const* FrameType[]={"free","data","toc","continuation"};
1.856 + aStream << FrameType[aFrame.Type()] << " (";
1.857 + int length=aFrame.Length();
1.858 + if (length==0)
1.859 + aStream << "full";
1.860 + else
1.861 + aStream << dec << length << hex;
1.862 + return aStream << ')';
1.863 + }
1.864 +