aboutsummaryrefslogtreecommitdiff
path: root/src/stable/myriad.cpp
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2012-11-05 22:41:51 +0000
committerMike Buland <eichlan@xagasoft.com>2012-11-05 22:41:51 +0000
commitec05778d5718a7912e506764d443a78d6a6179e3 (patch)
tree78a9a01532180030c095acefc45763f07c14edb8 /src/stable/myriad.cpp
parentb20414ac1fe80a71a90601f4cd1767fa7014a9ba (diff)
downloadlibbu++-ec05778d5718a7912e506764d443a78d6a6179e3.tar.gz
libbu++-ec05778d5718a7912e506764d443a78d6a6179e3.tar.bz2
libbu++-ec05778d5718a7912e506764d443a78d6a6179e3.tar.xz
libbu++-ec05778d5718a7912e506764d443a78d6a6179e3.zip
Converted tabs to spaces with tabconv.
Diffstat (limited to '')
-rw-r--r--src/stable/myriad.cpp1130
1 files changed, 565 insertions, 565 deletions
diff --git a/src/stable/myriad.cpp b/src/stable/myriad.cpp
index 4be82f0..2a6a725 100644
--- a/src/stable/myriad.cpp
+++ b/src/stable/myriad.cpp
@@ -16,720 +16,720 @@
16using Bu::sio; 16using Bu::sio;
17using Bu::Fmt; 17using Bu::Fmt;
18 18
19#define Myriad_MAGIC_CODE ((unsigned char *)"\x0a\xd3\xfa\x84") 19#define Myriad_MAGIC_CODE ((unsigned char *)"\x0a\xd3\xfa\x84")
20 20
21namespace Bu 21namespace Bu
22{ 22{
23 subExceptionDef( MyriadException ) 23 subExceptionDef( MyriadException )
24 template<typename t> t blkDiv( t total, t block ) { 24 template<typename t> t blkDiv( t total, t block ) {
25 return (total/block)+((total%block==0)?(0):(1)); 25 return (total/block)+((total%block==0)?(0):(1));
26 } 26 }
27} 27}
28 28
29Bu::Myriad::Myriad( Bu::Stream &sStore, int iBlockSize, int iPreallocate ) : 29Bu::Myriad::Myriad( Bu::Stream &sStore, int iBlockSize, int iPreallocate ) :
30 sStore( sStore ), 30 sStore( sStore ),
31 iBlockSize( iBlockSize ), 31 iBlockSize( iBlockSize ),
32 iBlocks( 0 ), 32 iBlocks( 0 ),
33 iUsed( 0 ), 33 iUsed( 0 ),
34 bHeaderChanged( false ) 34 bHeaderChanged( false )
35{ 35{
36 try 36 try
37 { 37 {
38 initialize(); 38 initialize();
39 } 39 }
40 catch( Bu::MyriadException &e ) 40 catch( Bu::MyriadException &e )
41 { 41 {
42 if( e.getErrorCode() == MyriadException::emptyStream ) 42 if( e.getErrorCode() == MyriadException::emptyStream )
43 { 43 {
44 initialize( iBlockSize, iPreallocate ); 44 initialize( iBlockSize, iPreallocate );
45 } 45 }
46 else 46 else
47 { 47 {
48 throw; 48 throw;
49 } 49 }
50 } 50 }
51} 51}
52 52
53Bu::Myriad::~Myriad() 53Bu::Myriad::~Myriad()
54{ 54{
55 mActiveBlocks.lock(); 55 mActiveBlocks.lock();
56 if( !hActiveBlocks.isEmpty() ) 56 if( !hActiveBlocks.isEmpty() )
57 { 57 {
58 sio << "Bu::Myriad::~Myriad(): Error: There are " 58 sio << "Bu::Myriad::~Myriad(): Error: There are "
59 << hActiveBlocks.getSize() << " unsynced blocks!" << sio.nl; 59 << hActiveBlocks.getSize() << " unsynced blocks!" << sio.nl;
60 } 60 }
61 mActiveBlocks.unlock(); 61 mActiveBlocks.unlock();
62 sync(); 62 sync();
63 63
64 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 64 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
65 { 65 {
66 delete *i; 66 delete *i;
67 } 67 }
68} 68}
69 69
70void Bu::Myriad::sync() 70void Bu::Myriad::sync()
71{ 71{
72 updateHeader(); 72 updateHeader();
73 73
74 mActiveBlocks.lock(); 74 mActiveBlocks.lock();
75 for( BlockHash::iterator i = hActiveBlocks.begin(); i; i++ ) 75 for( BlockHash::iterator i = hActiveBlocks.begin(); i; i++ )
76 { 76 {
77 if( (*i)->bChanged ) 77 if( (*i)->bChanged )
78 { 78 {
79 syncBlock( *i ); 79 syncBlock( *i );
80 } 80 }
81 } 81 }
82 mActiveBlocks.unlock(); 82 mActiveBlocks.unlock();
83} 83}
84 84
85void Bu::Myriad::initialize() 85void Bu::Myriad::initialize()
86{ 86{
87 MutexLocker mLock( mHeader ); 87 MutexLocker mLock( mHeader );
88 lFreeBlocks.clear(); 88 lFreeBlocks.clear();
89 sStore.setPosEnd( 0 ); 89 sStore.setPosEnd( 0 );
90 Bu::size iSize = sStore.tell(); 90 Bu::size iSize = sStore.tell();
91 sStore.setPos( 0 ); 91 sStore.setPos( 0 );
92 92
93 unsigned char buf[4]; 93 unsigned char buf[4];
94 if( sStore.read( buf, 4 ) < 4 ) 94 if( sStore.read( buf, 4 ) < 4 )
95 throw MyriadException( MyriadException::emptyStream, 95 throw MyriadException( MyriadException::emptyStream,
96 "Input stream appears to be empty."); 96 "Input stream appears to be empty.");
97 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) ) 97 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) )
98 { 98 {
99 throw MyriadException( MyriadException::invalidFormat, 99 throw MyriadException( MyriadException::invalidFormat,
100 "Stream does not appear to be a valid Myriad format."); 100 "Stream does not appear to be a valid Myriad format.");
101 } 101 }
102 sStore.read( buf, 2 ); 102 sStore.read( buf, 2 );
103 if( buf[0] != 1 ) 103 if( buf[0] != 1 )
104 throw MyriadException( MyriadException::badVersion, 104 throw MyriadException( MyriadException::badVersion,
105 "We can only handle version 1 for now."); 105 "We can only handle version 1 for now.");
106 if( buf[1] != 32 ) 106 if( buf[1] != 32 )
107 throw MyriadException( MyriadException::invalidWordSize, 107 throw MyriadException( MyriadException::invalidWordSize,
108 "We can only handle 32-bit words at the moment."); 108 "We can only handle 32-bit words at the moment.");
109 sStore.read( &iBlockSize, 4 ); 109 sStore.read( &iBlockSize, 4 );
110 int iStreams; 110 int iStreams;
111 sStore.read( &iStreams, 4 ); 111 sStore.read( &iStreams, 4 );
112 112
113 iBlocks = iSize/iBlockSize; 113 iBlocks = iSize/iBlockSize;
114 //sio << "Myriad: iSize=" << iSize << ", iBlockSize=" << iBlockSize 114 //sio << "Myriad: iSize=" << iSize << ", iBlockSize=" << iBlockSize
115 // << ", iBlocks=" << iBlocks << ", iStreams=" << iStreams << sio.nl; 115 // << ", iBlocks=" << iBlocks << ", iStreams=" << iStreams << sio.nl;
116 116
117 int iHeaderSize = 14 + 8 + 4; 117 int iHeaderSize = 14 + 8 + 4;
118 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize ); 118 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize );
119 119
120 while( iHeaderSize > iHeaderBlocks*iBlockSize ) 120 while( iHeaderSize > iHeaderBlocks*iBlockSize )
121 { 121 {
122 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize ); 122 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
123 iHeaderSize = 14 + 8 + 4*iHeaderBlocks; 123 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
124 } 124 }
125 125
126 //sio << "Myriad: iHeaderSize=" << iHeaderSize 126 //sio << "Myriad: iHeaderSize=" << iHeaderSize
127 // << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl; 127 // << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
128 128
129 Stream *pFakeHdr = new Stream; 129 Stream *pFakeHdr = new Stream;
130 pFakeHdr->iId = 0; 130 pFakeHdr->iId = 0;
131 pFakeHdr->iSize = iHeaderSize; 131 pFakeHdr->iSize = iHeaderSize;
132 for( int j = 0; j < iHeaderBlocks; j++ ) 132 for( int j = 0; j < iHeaderBlocks; j++ )
133 { 133 {
134 pFakeHdr->aBlocks.append( j ); 134 pFakeHdr->aBlocks.append( j );
135 } 135 }
136 136
137// sio << "Blocks: " << iBlocks << " (size = " << iSize << "/" << iBlockSize 137// sio << "Blocks: " << iBlocks << " (size = " << iSize << "/" << iBlockSize
138// << ")" << sio.nl; 138// << ")" << sio.nl;
139 Bu::BitString bsBlockUsed( iBlocks, false ); 139 Bu::BitString bsBlockUsed( iBlocks, false );
140 bsBlockUsed.clear(); 140 bsBlockUsed.clear();
141 141
142// bool bCanSkip = false; // Can skip around, post initial header stream i/o 142// bool bCanSkip = false; // Can skip around, post initial header stream i/o
143 MyriadStream *pIn = new MyriadStream( *this, pFakeHdr ); 143 MyriadStream *pIn = new MyriadStream( *this, pFakeHdr );
144 pIn->setPos( sStore.tell() ); 144 pIn->setPos( sStore.tell() );
145 for( int j = 0; j < iStreams; j++ ) 145 for( int j = 0; j < iStreams; j++ )
146 { 146 {
147 aStreams.append( new Stream() ); 147 aStreams.append( new Stream() );
148 Stream &s = *aStreams[j]; 148 Stream &s = *aStreams[j];
149 pIn->read( &s.iId, 4 ); 149 pIn->read( &s.iId, 4 );
150 pIn->read( &s.iSize, 4 ); 150 pIn->read( &s.iSize, 4 );
151 int iSBlocks = blkDiv(s.iSize, iBlockSize); 151 int iSBlocks = blkDiv(s.iSize, iBlockSize);
152 // sio << "Myriad: - Stream::iId=" << s.iId 152 // sio << "Myriad: - Stream::iId=" << s.iId
153 // << ", Stream::iSize=" << s.iSize 153 // << ", Stream::iSize=" << s.iSize
154 // << ", Stream::aBlocks=" << iSBlocks 154 // << ", Stream::aBlocks=" << iSBlocks
155 // << ", pIn->tell()=" << pIn->tell() << sio.nl; 155 // << ", pIn->tell()=" << pIn->tell() << sio.nl;
156 for( int k = 0; k < iSBlocks; k++ ) 156 for( int k = 0; k < iSBlocks; k++ )
157 { 157 {
158 int iBId; 158 int iBId;
159 pIn->read( &iBId, 4 ); 159 pIn->read( &iBId, 4 );
160 // sio << "Myriad: - iBId=" << iBId 160 // sio << "Myriad: - iBId=" << iBId
161 // << ", iStartPos=" << iBId*iBlockSize 161 // << ", iStartPos=" << iBId*iBlockSize
162 // << ", pIn->tell()=" << pIn->tell() << sio.nl; 162 // << ", pIn->tell()=" << pIn->tell() << sio.nl;
163 s.aBlocks.append( iBId ); 163 s.aBlocks.append( iBId );
164 bsBlockUsed.setBit( iBId ); 164 bsBlockUsed.setBit( iBId );
165 iUsed++; 165 iUsed++;
166 if( (j == 0 && k == iHeaderBlocks-1) ) 166 if( (j == 0 && k == iHeaderBlocks-1) )
167 { 167 {
168 // sio << "Myriad: - End of prepartition, unlocking skipping." 168 // sio << "Myriad: - End of prepartition, unlocking skipping."
169 // << sio.nl; 169 // << sio.nl;
170// bCanSkip = true; 170// bCanSkip = true;
171 MyriadStream *pTmp = new MyriadStream( *this, aStreams[0] ); 171 MyriadStream *pTmp = new MyriadStream( *this, aStreams[0] );
172 // sio << "Myriad - Position = " << pIn->tell() << sio.nl; 172 // sio << "Myriad - Position = " << pIn->tell() << sio.nl;
173 pTmp->setPos( pIn->tell() ); 173 pTmp->setPos( pIn->tell() );
174 delete pIn; 174 delete pIn;
175 delete pFakeHdr; 175 delete pFakeHdr;
176 pIn = pTmp; 176 pIn = pTmp;
177 } 177 }
178 } 178 }
179 } 179 }
180 delete pIn; 180 delete pIn;
181 181
182 for( int j = 0; j < iBlocks; j++ ) 182 for( int j = 0; j < iBlocks; j++ )
183 { 183 {
184 if( bsBlockUsed.getBit( j ) == false ) 184 if( bsBlockUsed.getBit( j ) == false )
185 { 185 {
186// sio << "Preinitialized block " << j << " is free." << sio.nl; 186// sio << "Preinitialized block " << j << " is free." << sio.nl;
187 lFreeBlocks.append( j ); 187 lFreeBlocks.append( j );
188 } 188 }
189 } 189 }
190// sio << "Myriad: Blocks used: " << bsBlockUsed.toString() << sio.nl; 190// sio << "Myriad: Blocks used: " << bsBlockUsed.toString() << sio.nl;
191} 191}
192 192
193void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate ) 193void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate )
194{ 194{
195 MutexLocker mLock( mHeader ); 195 MutexLocker mLock( mHeader );
196 lFreeBlocks.clear(); 196 lFreeBlocks.clear();
197 197
198 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 198 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
199 { 199 {
200 delete *i; 200 delete *i;
201 } 201 }
202 aStreams.clear(); 202 aStreams.clear();
203 iUsed = 0; 203 iUsed = 0;
204 204
205 int iHeaderSize = 14 + 8 + 4; 205 int iHeaderSize = 14 + 8 + 4;
206 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize ); 206 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize );
207 char cBuf = 1; 207 char cBuf = 1;
208 int iBuf = 0; 208 int iBuf = 0;
209 209
210 Stream *pStr = new Stream; 210 Stream *pStr = new Stream;
211 pStr->iId = 0; 211 pStr->iId = 0;
212 212
213 while( iHeaderSize > iHeaderBlocks*iBlockSize ) 213 while( iHeaderSize > iHeaderBlocks*iBlockSize )
214 { 214 {
215 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize ); 215 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
216 iHeaderSize = 14 + 8 + 4*iHeaderBlocks; 216 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
217 } 217 }
218 218
219 iPreAllocate += iHeaderBlocks; 219 iPreAllocate += iHeaderBlocks;
220 220
221 //sio << "Myriad: iHeaderSize=" << iHeaderSize << ", iBlockSize=" 221 //sio << "Myriad: iHeaderSize=" << iHeaderSize << ", iBlockSize="
222 // << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl; 222 // << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
223 223
224// bsBlockUsed.setSize( iPreAllocate, true ); 224// bsBlockUsed.setSize( iPreAllocate, true );
225 iUsed++; 225 iUsed++;
226 226
227 char *pBlock = new char[iBlockSize]; 227 char *pBlock = new char[iBlockSize];
228 memset( pBlock, 0, iBlockSize ); 228 memset( pBlock, 0, iBlockSize );
229 for( int j = 0; j < iPreAllocate; j++ ) 229 for( int j = 0; j < iPreAllocate; j++ )
230 { 230 {
231 sStore.write( pBlock, iBlockSize ); 231 sStore.write( pBlock, iBlockSize );
232 } 232 }
233 delete[] (char *)pBlock; 233 delete[] (char *)pBlock;
234 234
235 sStore.setPos( 0 ); 235 sStore.setPos( 0 );
236 236
237 // Magic number 237 // Magic number
238 sStore.write( Myriad_MAGIC_CODE, 4 ); 238 sStore.write( Myriad_MAGIC_CODE, 4 );
239 239
240 // Version (0) 240 // Version (0)
241 sStore.write( &cBuf, 1 ); 241 sStore.write( &cBuf, 1 );
242 242
243 // Bits per int 243 // Bits per int
244 cBuf = 32; 244 cBuf = 32;
245 sStore.write( &cBuf, 1 ); 245 sStore.write( &cBuf, 1 );
246 246
247 // The size of each block 247 // The size of each block
248 sStore.write( &iBlockSize, 4 ); 248 sStore.write( &iBlockSize, 4 );
249 249
250 iBuf = 1; 250 iBuf = 1;
251 // The number of streams 251 // The number of streams
252 sStore.write( &iBuf, 4 ); 252 sStore.write( &iBuf, 4 );
253 253
254 // Stream header 254 // Stream header
255 iBuf = 0; 255 iBuf = 0;
256 sStore.write( &iBuf, 4 ); 256 sStore.write( &iBuf, 4 );
257 sStore.write( &iHeaderSize, 4 ); 257 sStore.write( &iHeaderSize, 4 );
258 for( iBuf = 0; iBuf < iHeaderBlocks; iBuf++ ) 258 for( iBuf = 0; iBuf < iHeaderBlocks; iBuf++ )
259 { 259 {
260 sStore.write( &iBuf, 4 ); 260 sStore.write( &iBuf, 4 );
261 } 261 }
262 262
263 this->iBlockSize = iBlockSize; 263 this->iBlockSize = iBlockSize;
264 this->iBlocks = iPreAllocate; 264 this->iBlocks = iPreAllocate;
265 265
266 pStr->iSize = sStore.tell(); 266 pStr->iSize = sStore.tell();
267// sio << "Myriad: Actual end of header stream = " << pStr->iSize << sio.nl; 267// sio << "Myriad: Actual end of header stream = " << pStr->iSize << sio.nl;
268 268
269 pStr->iSize = iHeaderSize; 269 pStr->iSize = iHeaderSize;
270 for( int j = 0; j < iHeaderBlocks; j++ ) 270 for( int j = 0; j < iHeaderBlocks; j++ )
271 { 271 {
272// sio << "Started block " << j << " is header." << sio.nl; 272// sio << "Started block " << j << " is header." << sio.nl;
273 pStr->aBlocks.append( j ); 273 pStr->aBlocks.append( j );
274// bsBlockUsed.setBit( j ); 274// bsBlockUsed.setBit( j );
275 iUsed++; 275 iUsed++;
276 } 276 }
277 for( int j = iHeaderBlocks; j < this->iBlocks; j++ ) 277 for( int j = iHeaderBlocks; j < this->iBlocks; j++ )
278 { 278 {
279// sio << "Started block " << j << " is free." << sio.nl; 279// sio << "Started block " << j << " is free." << sio.nl;
280 lFreeBlocks.append( j ); 280 lFreeBlocks.append( j );
281 } 281 }
282 282
283 aStreams.append( pStr ); 283 aStreams.append( pStr );
284 284
285 //sio << bsBlockUsed.toString() << " - " << pStr->aBlocks << sio.nl; 285 //sio << bsBlockUsed.toString() << " - " << pStr->aBlocks << sio.nl;
286 286
287 bHeaderChanged = true; 287 bHeaderChanged = true;
288 //hStreams.insert( 0, BlockArray( 0 ) ); 288 //hStreams.insert( 0, BlockArray( 0 ) );
289} 289}
290 290
291void Bu::Myriad::updateHeader() 291void Bu::Myriad::updateHeader()
292{ 292{
293 MutexLocker mLock( mHeader ); 293 MutexLocker mLock( mHeader );
294 294
295 if( bHeaderChanged == false ) 295 if( bHeaderChanged == false )
296 return; 296 return;
297 if( !sStore.canWrite() ) 297 if( !sStore.canWrite() )
298 return; 298 return;
299 299
300 char cBuf; 300 char cBuf;
301 int iBuf; 301 int iBuf;
302 302
303 //for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 303 //for( StreamArray::iterator i = aStreams.begin(); i; i++ )
304 //{ 304 //{
305 // sio << "Myriad: Stream " << Fmt(4) << (*i)->iId << ": " << (*i)->aBlocks << sio.nl; 305 // sio << "Myriad: Stream " << Fmt(4) << (*i)->iId << ": " << (*i)->aBlocks << sio.nl;
306 //} 306 //}
307 307
308 // Compute the new size of the header. 308 // Compute the new size of the header.
309 int iHeaderSize = 14 + 8*aStreams.getSize(); 309 int iHeaderSize = 14 + 8*aStreams.getSize();
310// sio << "Myriad: updateHeader: aStreams.getSize() = " << aStreams.getSize() 310// sio << "Myriad: updateHeader: aStreams.getSize() = " << aStreams.getSize()
311// << sio.nl; 311// << sio.nl;
312 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 312 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
313 { 313 {
314 iHeaderSize += 4*(*i)->aBlocks.getSize(); 314 iHeaderSize += 4*(*i)->aBlocks.getSize();
315// sio << "Myriad: updateHeader: (*i)->aBlocks.getSize() = " 315// sio << "Myriad: updateHeader: (*i)->aBlocks.getSize() = "
316// << (*i)->aBlocks.getSize() << sio.nl; 316// << (*i)->aBlocks.getSize() << sio.nl;
317 } 317 }
318 int iNewBlocks = blkDiv( iHeaderSize, iBlockSize ); 318 int iNewBlocks = blkDiv( iHeaderSize, iBlockSize );
319 while( iNewBlocks > aStreams[0]->aBlocks.getSize() ) 319 while( iNewBlocks > aStreams[0]->aBlocks.getSize() )
320 { 320 {
321 int iBlock = findEmptyBlock(); 321 int iBlock = findEmptyBlock();
322// sio << "Myriad: updateHeader: Appending block " << iBlock 322// sio << "Myriad: updateHeader: Appending block " << iBlock
323// << " to header." << sio.nl; 323// << " to header." << sio.nl;
324 aStreams[0]->aBlocks.append( iBlock ); 324 aStreams[0]->aBlocks.append( iBlock );
325// bsBlockUsed.setBit( iBlock ); 325// bsBlockUsed.setBit( iBlock );
326 iUsed++; 326 iUsed++;
327 iHeaderSize += 4; 327 iHeaderSize += 4;
328 iNewBlocks = blkDiv( iHeaderSize, iBlockSize ); 328 iNewBlocks = blkDiv( iHeaderSize, iBlockSize );
329 } 329 }
330 aStreams[0]->iSize = iHeaderSize; 330 aStreams[0]->iSize = iHeaderSize;
331// sio << "Myriad: updateHeader: iHeaderSize=" << iHeaderSize 331// sio << "Myriad: updateHeader: iHeaderSize=" << iHeaderSize
332// << ", iNewBlocks=" << iNewBlocks << ", curBlocks=" 332// << ", iNewBlocks=" << iNewBlocks << ", curBlocks="
333// << aStreams[0]->aBlocks.getSize() << sio.nl; 333// << aStreams[0]->aBlocks.getSize() << sio.nl;
334 334
335 MyriadStream sHdr( *this, aStreams[0] ); 335 MyriadStream sHdr( *this, aStreams[0] );
336 sHdr.write( Myriad_MAGIC_CODE, 4 ); 336 sHdr.write( Myriad_MAGIC_CODE, 4 );
337 337
338 // Version (1) 338 // Version (1)
339 cBuf = 1; 339 cBuf = 1;
340 sHdr.write( &cBuf, 1 ); 340 sHdr.write( &cBuf, 1 );
341 341
342 // Bits per int 342 // Bits per int
343 cBuf = 32; 343 cBuf = 32;
344 sHdr.write( &cBuf, 1 ); 344 sHdr.write( &cBuf, 1 );
345 345
346 // The size of each block 346 // The size of each block
347 sHdr.write( &iBlockSize, 4 ); 347 sHdr.write( &iBlockSize, 4 );
348 348
349 iBuf = aStreams.getSize(); 349 iBuf = aStreams.getSize();
350 // The number of streams 350 // The number of streams
351 sHdr.write( &iBuf, 4 ); 351 sHdr.write( &iBuf, 4 );
352 352
353 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 353 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
354 { 354 {
355 sHdr.write( &(*i)->iId, 4 ); 355 sHdr.write( &(*i)->iId, 4 );
356 sHdr.write( &(*i)->iSize, 4 ); 356 sHdr.write( &(*i)->iSize, 4 );
357 int iUsedBlocks = blkDiv( (*i)->iSize, iBlockSize ); 357 int iUsedBlocks = blkDiv( (*i)->iSize, iBlockSize );
358// for( BlockArray::iterator j = (*i)->aBlocks.begin(); j; j++ ) 358// for( BlockArray::iterator j = (*i)->aBlocks.begin(); j; j++ )
359 for( int j = 0; j < iUsedBlocks; j++ ) 359 for( int j = 0; j < iUsedBlocks; j++ )
360 { 360 {
361 sHdr.write( &(*i)->aBlocks[j], 4 ); 361 sHdr.write( &(*i)->aBlocks[j], 4 );
362 } 362 }
363 } 363 }
364 364
365 bHeaderChanged = false; 365 bHeaderChanged = false;
366} 366}
367 367
368int Bu::Myriad::createStream( int iPreAllocate ) 368int Bu::Myriad::createStream( int iPreAllocate )
369{ 369{
370 MutexLocker mLock( mHeader ); 370 MutexLocker mLock( mHeader );
371 371
372 Stream *pStr = new Stream(); 372 Stream *pStr = new Stream();
373 pStr->iId = aStreams.last()->iId+1; 373 pStr->iId = aStreams.last()->iId+1;
374 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate=" 374 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate="
375 // << iPreAllocate << sio.nl; 375 // << iPreAllocate << sio.nl;
376 pStr->iSize = 0; 376 pStr->iSize = 0;
377 aStreams.append( pStr ); 377 aStreams.append( pStr );
378 378
379 for( int j = 0; j < iPreAllocate; j++ ) 379 for( int j = 0; j < iPreAllocate; j++ )
380 { 380 {
381 int iFreeBlock = findEmptyBlock(); 381 int iFreeBlock = findEmptyBlock();
382// sio << "Myriad: Adding block " << iFreeBlock << sio.nl; 382// sio << "Myriad: Adding block " << iFreeBlock << sio.nl;
383 pStr->aBlocks.append( iFreeBlock ); 383 pStr->aBlocks.append( iFreeBlock );
384// bsBlockUsed.setBit( iFreeBlock ); 384// bsBlockUsed.setBit( iFreeBlock );
385 iUsed++; 385 iUsed++;
386 } 386 }
387 387
388 bHeaderChanged = true; 388 bHeaderChanged = true;
389 389
390 return pStr->iId; 390 return pStr->iId;
391} 391}
392 392
393int Bu::Myriad::createStreamWithId( int iId, int iPreAllocate ) 393int Bu::Myriad::createStreamWithId( int iId, int iPreAllocate )
394{ 394{
395 MutexLocker mLock( mHeader ); 395 MutexLocker mLock( mHeader );
396 396
397 try 397 try
398 { 398 {
399 findStream( iId ); 399 findStream( iId );
400 throw MyriadException( MyriadException::streamExists, 400 throw MyriadException( MyriadException::streamExists,
401 "There is already a stream with the given id."); 401 "There is already a stream with the given id.");
402 } 402 }
403 catch( MyriadException &e ) 403 catch( MyriadException &e )
404 { 404 {
405 Stream *pStr = new Stream(); 405 Stream *pStr = new Stream();
406 pStr->iId = iId; 406 pStr->iId = iId;
407 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate=" 407 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate="
408 // << iPreAllocate << sio.nl; 408 // << iPreAllocate << sio.nl;
409 pStr->iSize = 0; 409 pStr->iSize = 0;
410 if( aStreams.last()->iId < iId ) 410 if( aStreams.last()->iId < iId )
411 { 411 {
412 aStreams.append( pStr ); 412 aStreams.append( pStr );
413 } 413 }
414 else 414 else
415 { 415 {
416 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 416 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
417 { 417 {
418 if( (*i)->iId > iId ) 418 if( (*i)->iId > iId )
419 { 419 {
420 aStreams.insert( i, pStr ); 420 aStreams.insert( i, pStr );
421 break; 421 break;
422 } 422 }
423 } 423 }
424 } 424 }
425 425
426 for( int j = 0; j < iPreAllocate; j++ ) 426 for( int j = 0; j < iPreAllocate; j++ )
427 { 427 {
428 int iFreeBlock = findEmptyBlock(); 428 int iFreeBlock = findEmptyBlock();
429 // sio << "Myriad: Adding block " << iFreeBlock << sio.nl; 429 // sio << "Myriad: Adding block " << iFreeBlock << sio.nl;
430 pStr->aBlocks.append( iFreeBlock ); 430 pStr->aBlocks.append( iFreeBlock );
431// bsBlockUsed.setBit( iFreeBlock ); 431// bsBlockUsed.setBit( iFreeBlock );
432 iUsed++; 432 iUsed++;
433 } 433 }
434 434
435 bHeaderChanged = true; 435 bHeaderChanged = true;
436 436
437 return pStr->iId; 437 return pStr->iId;
438 } 438 }
439} 439}
440 440
441int Bu::Myriad::findEmptyBlock() 441int Bu::Myriad::findEmptyBlock()
442{ 442{
443 bHeaderChanged = true; 443 bHeaderChanged = true;
444 444
445 if( lFreeBlocks.isEmpty() ) 445 if( lFreeBlocks.isEmpty() )
446 { 446 {
447 sStore.setSize( (iBlocks+1)*(Bu::size)iBlockSize ); 447 sStore.setSize( (iBlocks+1)*(Bu::size)iBlockSize );
448 return iBlocks++; 448 return iBlocks++;
449 } 449 }
450 else 450 else
451 { 451 {
452 return lFreeBlocks.dequeue(); 452 return lFreeBlocks.dequeue();
453 } 453 }
454} 454}
455 455
456void Bu::Myriad::deleteStream( int iId ) 456void Bu::Myriad::deleteStream( int iId )
457{ 457{
458 MutexLocker mLock( mHeader ); 458 MutexLocker mLock( mHeader );
459 459
460 if( iId < 0 ) 460 if( iId < 0 )
461 throw MyriadException( MyriadException::invalidStreamId, 461 throw MyriadException( MyriadException::invalidStreamId,
462 "Invalid stream id."); 462 "Invalid stream id.");
463 if( iId == 0 ) 463 if( iId == 0 )
464 throw MyriadException( MyriadException::protectedStream, 464 throw MyriadException( MyriadException::protectedStream,
465 "You cannot delete stream zero, it is protected."); 465 "You cannot delete stream zero, it is protected.");
466 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 466 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
467 { 467 {
468 if( (*i)->iId == iId ) 468 if( (*i)->iId == iId )
469 { 469 {
470 Stream *pStream = *i; 470 Stream *pStream = *i;
471 for( BlockArray::iterator j = pStream->aBlocks.begin(); j; j++ ) 471 for( BlockArray::iterator j = pStream->aBlocks.begin(); j; j++ )
472 { 472 {
473 lFreeBlocks.append( *j ); 473 lFreeBlocks.append( *j );
474// bsBlockUsed.setBit( *j, false ); 474// bsBlockUsed.setBit( *j, false );
475 iUsed--; 475 iUsed--;
476 } 476 }
477 aStreams.erase( i ); 477 aStreams.erase( i );
478 bHeaderChanged = true; 478 bHeaderChanged = true;
479 delete pStream; 479 delete pStream;
480 return; 480 return;
481 } 481 }
482 } 482 }
483} 483}
484 484
485Bu::Array<int> Bu::Myriad::getStreamIds() 485Bu::Array<int> Bu::Myriad::getStreamIds()
486{ 486{
487 MutexLocker mLock( mHeader ); 487 MutexLocker mLock( mHeader );
488 488
489 Bu::Array<int> aRet( aStreams.getSize() ); 489 Bu::Array<int> aRet( aStreams.getSize() );
490 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 490 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
491 { 491 {
492 aRet.append( (*i)->iId ); 492 aRet.append( (*i)->iId );
493 } 493 }
494 494
495 return aRet; 495 return aRet;
496} 496}
497 497
498int Bu::Myriad::getStreamSize( int iId ) 498int Bu::Myriad::getStreamSize( int iId )
499{ 499{
500 MutexLocker mLock( mHeader ); 500 MutexLocker mLock( mHeader );
501 501
502 return findStream( iId )->iSize; 502 return findStream( iId )->iSize;
503} 503}
504 504
505bool Bu::Myriad::hasStream( int iId ) 505bool Bu::Myriad::hasStream( int iId )
506{ 506{
507 MutexLocker mLock( mHeader ); 507 MutexLocker mLock( mHeader );
508 508
509 try 509 try
510 { 510 {
511 findStream( iId ); 511 findStream( iId );
512 return true; 512 return true;
513 }catch(...) 513 }catch(...)
514 { 514 {
515 return false; 515 return false;
516 } 516 }
517} 517}
518 518
519Bu::MyriadStream Bu::Myriad::openStream( int iId ) 519Bu::MyriadStream Bu::Myriad::openStream( int iId )
520{ 520{
521 MutexLocker mLock( mHeader ); 521 MutexLocker mLock( mHeader );
522 522
523 //sio << "Myriad: Request to open stream: " << iId << sio.nl; 523 //sio << "Myriad: Request to open stream: " << iId << sio.nl;
524 return MyriadStream( *this, findStream( iId ) ); 524 return MyriadStream( *this, findStream( iId ) );
525} 525}
526 526
527int Bu::Myriad::getNumStreams() 527int Bu::Myriad::getNumStreams()
528{ 528{
529 MutexLocker mLock( mHeader ); 529 MutexLocker mLock( mHeader );
530 530
531 return aStreams.getSize(); 531 return aStreams.getSize();
532} 532}
533 533
534int Bu::Myriad::getBlockSize() 534int Bu::Myriad::getBlockSize()
535{ 535{
536 return iBlockSize; 536 return iBlockSize;
537} 537}
538 538
539int Bu::Myriad::getNumBlocks() 539int Bu::Myriad::getNumBlocks()
540{ 540{
541 return iBlocks; 541 return iBlocks;
542} 542}
543 543
544int Bu::Myriad::getNumUsedBlocks() 544int Bu::Myriad::getNumUsedBlocks()
545{ 545{
546 return iUsed; 546 return iUsed;
547} 547}
548 548
549Bu::size Bu::Myriad::getTotalUsedBytes() 549Bu::size Bu::Myriad::getTotalUsedBytes()
550{ 550{
551 MutexLocker mLock( mHeader ); 551 MutexLocker mLock( mHeader );
552 552
553 Bu::size iTotalSize = 0; 553 Bu::size iTotalSize = 0;
554 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 554 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
555 { 555 {
556 iTotalSize += (*i)->iSize; 556 iTotalSize += (*i)->iSize;
557 } 557 }
558 return iTotalSize; 558 return iTotalSize;
559} 559}
560 560
561Bu::size Bu::Myriad::getTotalUnusedBytes() 561Bu::size Bu::Myriad::getTotalUnusedBytes()
562{ 562{
563 MutexLocker mLock( mHeader ); 563 MutexLocker mLock( mHeader );
564 564
565 Bu::size iTotalSize = (iBlocks-iUsed)*iBlockSize; 565 Bu::size iTotalSize = (iBlocks-iUsed)*iBlockSize;
566 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 566 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
567 { 567 {
568 iTotalSize += iBlockSize - ((Bu::size)(*i)->iSize%iBlockSize); 568 iTotalSize += iBlockSize - ((Bu::size)(*i)->iSize%iBlockSize);
569 } 569 }
570 return iTotalSize; 570 return iTotalSize;
571} 571}
572 572
573Bu::size Bu::Myriad::getTotalUnusedBytes( int iFakeBlockSize ) 573Bu::size Bu::Myriad::getTotalUnusedBytes( int iFakeBlockSize )
574{ 574{
575 MutexLocker mLock( mHeader ); 575 MutexLocker mLock( mHeader );
576 576
577 Bu::size iTotalSize = (iBlocks-iUsed)*iFakeBlockSize; 577 Bu::size iTotalSize = (iBlocks-iUsed)*iFakeBlockSize;
578 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 578 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
579 { 579 {
580 iTotalSize += iFakeBlockSize - ((*i)->iSize%iFakeBlockSize); 580 iTotalSize += iFakeBlockSize - ((*i)->iSize%iFakeBlockSize);
581 } 581 }
582 return iTotalSize; 582 return iTotalSize;
583} 583}
584 584
585Bu::Myriad::Stream *Bu::Myriad::findStream( int iId ) 585Bu::Myriad::Stream *Bu::Myriad::findStream( int iId )
586{ 586{
587 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 587 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
588 { 588 {
589 if( (*i)->iId == iId ) 589 if( (*i)->iId == iId )
590 return *i; 590 return *i;
591 } 591 }
592 592
593 throw MyriadException( MyriadException::noSuchStream, 593 throw MyriadException( MyriadException::noSuchStream,
594 "The requested stream doesn't exist and cannot be opened." ); 594 "The requested stream doesn't exist and cannot be opened." );
595 595
596 return NULL; 596 return NULL;
597} 597}
598 598
599Bu::Myriad::Block *Bu::Myriad::getBlock( int iBlock ) 599Bu::Myriad::Block *Bu::Myriad::getBlock( int iBlock )
600{ 600{
601// sio << "Myriad: Reading block " << iBlock << ", bytes " 601// sio << "Myriad: Reading block " << iBlock << ", bytes "
602// << iBlockSize*iBlock << "-" << iBlockSize*(iBlock+1) << sio.nl; 602// << iBlockSize*iBlock << "-" << iBlockSize*(iBlock+1) << sio.nl;
603 Block *pBlock = new Block; 603 Block *pBlock = new Block;
604 pBlock->pData = new char[iBlockSize]; 604 pBlock->pData = new char[iBlockSize];
605 sStore.setPos( iBlockSize * (Bu::size)iBlock ); 605 sStore.setPos( iBlockSize * (Bu::size)iBlock );
606 sStore.read( pBlock->pData, iBlockSize ); 606 sStore.read( pBlock->pData, iBlockSize );
607 pBlock->bChanged = false; 607 pBlock->bChanged = false;
608 pBlock->iBlockIndex = iBlock; 608 pBlock->iBlockIndex = iBlock;
609 609
610 mActiveBlocks.lock(); 610 mActiveBlocks.lock();
611 hActiveBlocks.insert( iBlock, pBlock ); 611 hActiveBlocks.insert( iBlock, pBlock );
612 mActiveBlocks.unlock(); 612 mActiveBlocks.unlock();
613 613
614 return pBlock; 614 return pBlock;
615} 615}
616 616
617void Bu::Myriad::releaseBlock( Bu::Myriad::Block *pBlock ) 617void Bu::Myriad::releaseBlock( Bu::Myriad::Block *pBlock )
618{ 618{
619 if( pBlock == NULL ) 619 if( pBlock == NULL )
620 return; 620 return;
621// sio << "Myriad: Releasing block " << pBlock->iBlockIndex << sio.nl; 621// sio << "Myriad: Releasing block " << pBlock->iBlockIndex << sio.nl;
622 syncBlock( pBlock ); 622 syncBlock( pBlock );
623 mActiveBlocks.lock(); 623 mActiveBlocks.lock();
624 hActiveBlocks.erase( pBlock->iBlockIndex ); 624 hActiveBlocks.erase( pBlock->iBlockIndex );
625 mActiveBlocks.unlock(); 625 mActiveBlocks.unlock();
626 626
627 delete[] pBlock->pData; 627 delete[] pBlock->pData;
628 delete pBlock; 628 delete pBlock;
629} 629}
630 630
631void Bu::Myriad::syncBlock( Block *pBlock ) 631void Bu::Myriad::syncBlock( Block *pBlock )
632{ 632{
633 if( pBlock->bChanged ) 633 if( pBlock->bChanged )
634 { 634 {
635// sio << "Myriad: - Block changed, writing back to stream." << sio.nl; 635// sio << "Myriad: - Block changed, writing back to stream." << sio.nl;
636 sStore.setPos( iBlockSize * (Bu::size)pBlock->iBlockIndex ); 636 sStore.setPos( iBlockSize * (Bu::size)pBlock->iBlockIndex );
637 sStore.write( pBlock->pData, iBlockSize ); 637 sStore.write( pBlock->pData, iBlockSize );
638 pBlock->bChanged = false; 638 pBlock->bChanged = false;
639 } 639 }
640} 640}
641 641
642int Bu::Myriad::streamAddBlock( Stream *pStream ) 642int Bu::Myriad::streamAddBlock( Stream *pStream )
643{ 643{
644 MutexLocker mLock( mHeader ); 644 MutexLocker mLock( mHeader );
645 645
646 int iBlock = findEmptyBlock(); 646 int iBlock = findEmptyBlock();
647 pStream->aBlocks.append( iBlock ); 647 pStream->aBlocks.append( iBlock );
648// bsBlockUsed.setBit( iBlock ); 648// bsBlockUsed.setBit( iBlock );
649// bHeaderChanged = true; 649// bHeaderChanged = true;
650 iUsed++; 650 iUsed++;
651 return iBlock; 651 return iBlock;
652} 652}
653 653
654void Bu::Myriad::setStreamSize( Stream *pStream, long iSize ) 654void Bu::Myriad::setStreamSize( Stream *pStream, long iSize )
655{ 655{
656 MutexLocker mLock( mHeader ); 656 MutexLocker mLock( mHeader );
657 657
658 if( pStream->iSize == iSize ) 658 if( pStream->iSize == iSize )
659 { 659 {
660 return; 660 return;
661 } 661 }
662 else if( pStream->iSize > iSize ) 662 else if( pStream->iSize > iSize )
663 { 663 {
664 // Shrink 664 // Shrink
665 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize; 665 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize;
666 iNewSize-iBlockSize > iSize; iNewSize -= iBlockSize ) 666 iNewSize-iBlockSize > iSize; iNewSize -= iBlockSize )
667 { 667 {
668// if( bsBlockUsed.getBit( pStream->aBlocks.last() ) ) 668// if( bsBlockUsed.getBit( pStream->aBlocks.last() ) )
669 iUsed--; 669 iUsed--;
670// else 670// else
671// sio << "Unused block used in stream? " << pStream->aBlocks.last() << sio.nl; 671// sio << "Unused block used in stream? " << pStream->aBlocks.last() << sio.nl;
672 lFreeBlocks.enqueue( pStream->aBlocks.last() ); 672 lFreeBlocks.enqueue( pStream->aBlocks.last() );
673// bsBlockUsed.setBit( pStream->aBlocks.last(), false ); 673// bsBlockUsed.setBit( pStream->aBlocks.last(), false );
674 pStream->aBlocks.eraseLast(); 674 pStream->aBlocks.eraseLast();
675 } 675 }
676 pStream->iSize = iSize; 676 pStream->iSize = iSize;
677 bHeaderChanged = true; 677 bHeaderChanged = true;
678 } 678 }
679 else 679 else
680 { 680 {
681 // Grow 681 // Grow
682 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize; 682 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize;
683 iNewSize < iSize; iNewSize += iBlockSize ) 683 iNewSize < iSize; iNewSize += iBlockSize )
684 { 684 {
685 //streamAddBlock( pStream ); 685 //streamAddBlock( pStream );
686 int iBlock = findEmptyBlock(); 686 int iBlock = findEmptyBlock();
687 pStream->aBlocks.append( iBlock ); 687 pStream->aBlocks.append( iBlock );
688// bsBlockUsed.setBit( iBlock ); 688// bsBlockUsed.setBit( iBlock );
689// bHeaderChanged = true; 689// bHeaderChanged = true;
690 iUsed++; 690 iUsed++;
691 } 691 }
692 pStream->iSize = iSize; 692 pStream->iSize = iSize;
693 bHeaderChanged = true; 693 bHeaderChanged = true;
694 } 694 }
695} 695}
696 696
697void Bu::Myriad::headerChanged() 697void Bu::Myriad::headerChanged()
698{ 698{
699 bHeaderChanged = true; 699 bHeaderChanged = true;
700} 700}
701 701
702bool Bu::Myriad::isMyriad( Bu::Stream &sStore ) 702bool Bu::Myriad::isMyriad( Bu::Stream &sStore )
703{ 703{
704 uint8_t uTmp; 704 uint8_t uTmp;
705 705
706 return isMyriad( sStore, uTmp ); 706 return isMyriad( sStore, uTmp );
707} 707}
708 708
709bool Bu::Myriad::isMyriad( Bu::Stream &sStore, uint8_t &uTmp ) 709bool Bu::Myriad::isMyriad( Bu::Stream &sStore, uint8_t &uTmp )
710{ 710{
711 sStore.setPos( 0 ); 711 sStore.setPos( 0 );
712 712
713 unsigned char buf[4]; 713 unsigned char buf[4];
714 if( sStore.read( buf, 4 ) < 4 ) 714 if( sStore.read( buf, 4 ) < 4 )
715 throw MyriadException( MyriadException::emptyStream, 715 throw MyriadException( MyriadException::emptyStream,
716 "Input stream appears to be empty."); 716 "Input stream appears to be empty.");
717 sStore.read( &uTmp, 1 ); 717 sStore.read( &uTmp, 1 );
718 sStore.setPos( 0 ); 718 sStore.setPos( 0 );
719 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) ) 719 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) )
720 { 720 {
721 return false; 721 return false;
722 } 722 }
723 return true; 723 return true;
724} 724}
725 725
726const Bu::BitString Bu::Myriad::getBlocksUsed() const 726const Bu::BitString Bu::Myriad::getBlocksUsed() const
727{ 727{
728 Bu::BitString bs( iBlocks, false ); 728 Bu::BitString bs( iBlocks, false );
729 for( int j = 0; j < iBlocks; j++ ) 729 for( int j = 0; j < iBlocks; j++ )
730 bs.setBit( j ); 730 bs.setBit( j );
731 for( IndexList::const_iterator i = lFreeBlocks.begin(); i; i++ ) 731 for( IndexList::const_iterator i = lFreeBlocks.begin(); i; i++ )
732 bs.setBit( *i, false ); 732 bs.setBit( *i, false );
733 return bs; 733 return bs;
734} 734}
735 735