summaryrefslogtreecommitdiff
path: root/src/myriad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/myriad.cpp')
-rw-r--r--src/myriad.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/myriad.cpp b/src/myriad.cpp
new file mode 100644
index 0000000..64c8d20
--- /dev/null
+++ b/src/myriad.cpp
@@ -0,0 +1,284 @@
1/*
2 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/myriad.h"
9#include "bu/stream.h"
10#include "bu/myriadstream.h"
11#include <stdio.h>
12
13#include "bu/sio.h"
14using Bu::sio;
15using Bu::Fmt;
16
17#define Myriad_MAGIC_CODE ((unsigned char *)"\xFF\xC3\x99\xBD")
18
19namespace Bu
20{
21 subExceptionDef( MyriadException )
22 template<typename t> t blkDiv( t total, t block ) {
23 return (total/block)+((total%block==0)?(0):(1));
24 }
25}
26
27Bu::Myriad::Myriad( Bu::Stream &sStore ) :
28 sStore( sStore ),
29 iBlockSize( 0 ),
30 iBlocks( 0 ),
31 iUsed( 0 )
32{
33}
34
35Bu::Myriad::~Myriad()
36{
37 updateHeader();
38
39 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
40 {
41 delete *i;
42 }
43}
44
45void Bu::Myriad::sync()
46{
47 updateHeader();
48
49 // Later, also flush all caches.
50}
51
52void Bu::Myriad::initialize()
53{
54 sStore.setPosEnd( 0 );
55 int iSize = sStore.tell();
56 sStore.setPos( 0 );
57
58 unsigned char buf[4];
59 if( sStore.read( buf, 4 ) < 4 )
60 throw MyriadException("Input stream appears to be empty.");
61 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) )
62 {
63 throw MyriadException(
64 "Stream does not appear to be a valid Myriad format.");
65 }
66 sStore.read( buf, 2 );
67 if( buf[0] != 1 )
68 throw MyriadException(
69 "We can only handle version 1 for now.");
70 if( buf[1] != 32 )
71 throw MyriadException(
72 "We can only handle 32-bit words at the moment.");
73 sStore.read( &iBlockSize, 4 );
74 int iStreams;
75 sStore.read( &iStreams, 4 );
76
77 iBlocks = iSize/iBlockSize;
78 sio << "Myriad: iSize=" << iSize << ", iBlockSize=" << iBlockSize
79 << ", iBlocks=" << iBlocks << ", iStreams=" << iStreams << sio.nl;
80
81 int iHeaderSize = 14 + 8 + 4;
82 int iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
83
84 while( iHeaderSize > iHeaderBlocks*iBlockSize )
85 {
86 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
87 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
88 }
89
90 sio << "Myriad: iHeaderSize=" << iHeaderSize
91 << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
92
93 bsBlockUsed.setSize( iBlocks, true );
94
95 bool bCanSkip = false; // Can skip around, post initial header stream i/o
96 for( int j = 0; j < iStreams; j++ )
97 {
98 int iHdrBlock = 0;
99 int iCurBlock = 0;
100 aStreams.append( new Stream() );
101 Stream &s = *aStreams[j];
102 sStore.read( &s.iId, 4 );
103 sStore.read( &s.iSize, 4 );
104 int iSBlocks = blkDiv(s.iSize, iBlockSize);
105 sio << "Myriad: - Stream::iId=" << s.iId << ", Stream::iSize=" << s.iSize
106 << ", Stream::aBlocks=" << iSBlocks
107 << ", sStore.tell()=" << sStore.tell() << sio.nl;
108 for( int k = 0; k < iSBlocks; k++ )
109 {
110 int iBId;
111 sStore.read( &iBId, 4 );
112 sio << "Myriad: - iBId=" << iBId
113 << ", iStartPos=" << iBId*iBlockSize
114 << ", sStore.tell()=" << sStore.tell() << sio.nl;
115 s.aBlocks.append( iBId );
116 bsBlockUsed.setBit( iBId );
117 if( (j == 0 && k == iHeaderBlocks-1) )
118 {
119 sio << "Myriad: - End of prepartition, unlocking skipping."
120 << sio.nl;
121 bCanSkip = true;
122 iCurBlock = blkDiv( (int)sStore.tell(), iBlockSize );
123 }
124 if( bCanSkip && sStore.tell() >= iCurBlock*iBlockSize+iBlockSize )
125 {
126 iHdrBlock++;
127 iCurBlock = aStreams[0]->aBlocks[iHdrBlock];
128 sio << "Myriad: Ran out of data in block, finding next header "
129 "block: " << iHdrBlock << " = " << iCurBlock << " ("
130 << iCurBlock*iBlockSize << "b)" << sio.nl;
131 sStore.setPos( iCurBlock*iBlockSize );
132 }
133 }
134 }
135
136 sio << bsBlockUsed.toString() << sio.nl;
137
138 //printf("%d blocks, %db each, %db block offset\n",
139 // iBlocks, iBlockSize, iBlockStart );
140
141}
142
143void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate )
144{
145 int iHeaderSize = 14 + 8 + 4;
146 int iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
147 char cBuf = 1;
148 int iBuf = 0;
149
150 Stream *pStr = new Stream;
151 pStr->iId = 0;
152
153 while( iHeaderSize > iHeaderBlocks*iBlockSize )
154 {
155 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
156 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
157 }
158
159 iPreAllocate += iHeaderBlocks;
160
161 sio << "Myriad: iHeaderSize=" << iHeaderSize << ", iBlockSize="
162 << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
163
164 bsBlockUsed.setSize( iPreAllocate, true );
165
166 char *pBlock = new char[iBlockSize];
167 memset( pBlock, 0, iBlockSize );
168 for( int j = 0; j < iPreAllocate; j++ )
169 {
170 sStore.write( pBlock, iBlockSize );
171 pStr->aBlocks.append( j );
172 }
173 delete[] (char *)pBlock;
174
175 sStore.setPos( 0 );
176
177 // Magic number
178 sStore.write( Myriad_MAGIC_CODE, 4 );
179
180 // Version (0)
181 sStore.write( &cBuf, 1 );
182
183 // Bits per int
184 cBuf = 32;
185 sStore.write( &cBuf, 1 );
186
187 // The size of each block
188 sStore.write( &iBlockSize, 4 );
189
190 iBuf = 1;
191 // The number of streams
192 sStore.write( &iBuf, 4 );
193
194 // Stream header
195 iBuf = 0;
196 sStore.write( &iBuf, 4 );
197 sStore.write( &iHeaderSize, 4 );
198 for( iBuf = 0; iBuf < iHeaderBlocks; iBuf++ )
199 {
200 sStore.write( &iBuf, 4 );
201 }
202
203 this->iBlockSize = iBlockSize;
204 this->iBlocks = iPreAllocate;
205
206 pStr->iSize = sStore.tell();
207
208 //hStreams.insert( 0, BlockArray( 0 ) );
209}
210
211void Bu::Myriad::updateHeader()
212{
213 if( !sStore.canWrite() )
214 return;
215
216
217
218 // TODO: Use the stream class to access this really smoothly, I hope :)
219}
220
221int Bu::Myriad::createStream( int iPreAllocate )
222{
223 Stream *pStr = new Stream();
224 pStr->iId = aStreams.last()->iId+1;
225 sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate="
226 << iPreAllocate << sio.nl;
227 pStr->iSize = 0;
228
229 for( int j = 0; j < iPreAllocate; j++ )
230 {
231 int iFreeBlock = findEmptyBlock();
232 sio << "Myriad: Adding block " << j << sio.nl;
233 pStr->aBlocks.append( j );
234 bsBlockUsed.setBit( j );
235 }
236
237 return 0;
238}
239
240int Bu::Myriad::findEmptyBlock()
241{
242 for( int j = 0; j < bsBlockUsed.getSize(); j++ )
243 {
244 if( bsBlockUsed.getBit( j ) == false )
245 return j;
246 }
247 sio << "Myriad: findEmptyBlock(): No empty blocks, adding new one." << sio.nl;
248
249 bsBlockUsed.setSize( bsBlockUsed.getSize()+1, false );
250 sStore.setPos( iBlockSize*iBlocks );
251
252 char *pBlock = new char[iBlockSize];
253 memset( pBlock, 0, iBlockSize );
254 sStore.write( pBlock, iBlockSize );
255 delete pBlock;
256
257 return iBlockSize++;
258}
259
260void Bu::Myriad::deleteStream( int /*iID*/ )
261{
262}
263
264Bu::MyriadStream Bu::Myriad::openStream( int iID )
265{
266 return MyriadStream( *this, iID );
267}
268
269int Bu::Myriad::getBlockSize()
270{
271 return iBlockSize;
272}
273
274int Bu::Myriad::getNumBlocks()
275{
276 return iBlocks;
277}
278
279int Bu::Myriad::getNumUsedBlocks()
280{
281 return iUsed;
282}
283
284