00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "vstpresetfile.h"
00037
00038 namespace Steinberg {
00039 namespace Vst {
00040
00041
00042
00043
00044 static const ChunkID commonChunks[kNumPresetChunks] =
00045 {
00046 {'V', 'S', 'T', '3'},
00047 {'C', 'o', 'm', 'p'},
00048 {'C', 'o', 'n', 't'},
00049 {'P', 'r', 'o', 'g'},
00050 {'I', 'n', 'f', 'o'},
00051 {'L', 'i', 's', 't'}
00052 };
00053
00054
00055
00056 static const int32 kFormatVersion = 1;
00057 static const int32 kClassIDSize = 32;
00058 static const int32 kHeaderSize = sizeof (ChunkID) + sizeof (int32) + kClassIDSize + sizeof (TSize);
00059 static const int32 kListOffsetPos = kHeaderSize - sizeof (TSize);
00060
00061
00062 const ChunkID& getChunkID (ChunkType type)
00063 {
00064 return commonChunks[type];
00065 }
00066
00067 #ifdef verify
00068 #undef verify
00069 #endif
00070
00071
00072 inline bool verify (tresult result)
00073 {
00074 return result == kResultOk || result == kNotImplemented;
00075 }
00076
00077
00078
00079
00080 bool PresetFile::savePreset (IBStream* stream, const FUID& classID,
00081 IComponent* component, IEditController* editController,
00082 const char* xmlBuffer, int32 xmlSize)
00083 {
00084 PresetFile pf (stream);
00085 pf.setClassID (classID);
00086 if (!pf.writeHeader ())
00087 return false;
00088
00089 if (!pf.storeComponentState (component))
00090 return false;
00091
00092 if (editController && !pf.storeControllerState (editController))
00093 return false;
00094
00095 if (xmlBuffer && !pf.writeMetaInfo (xmlBuffer, xmlSize))
00096 return false;
00097
00098 return pf.writeChunkList ();
00099 }
00100
00101
00102 bool PresetFile::loadPreset (IBStream* stream, const FUID& classID, IComponent* component, IEditController* editController)
00103 {
00104 PresetFile pf (stream);
00105 if (!pf.readChunkList ())
00106 return false;
00107
00108 if (pf.getClassID () != classID)
00109 return false;
00110
00111 if (!pf.restoreComponentState (component))
00112 return false;
00113
00114 if (editController)
00115 {
00116
00117 if (!pf.restoreComponentState (editController))
00118 return false;
00119
00120
00121 if (pf.contains (kControllerState) && !pf.restoreControllerState (editController))
00122 return false;
00123 }
00124 return true;
00125 }
00126
00127
00128 PresetFile::PresetFile (IBStream* stream)
00129 : stream (stream)
00130 , entryCount (0)
00131 {
00132 memset (entries, 0, sizeof (entries));
00133
00134 if (stream)
00135 stream->addRef ();
00136 }
00137
00138
00139 PresetFile::~PresetFile ()
00140 {
00141 if (stream)
00142 stream->release ();
00143 }
00144
00145
00146 const PresetFile::Entry* PresetFile::getEntry (ChunkType which) const
00147 {
00148 const ChunkID& id = getChunkID (which);
00149 for (int32 i = 0; i < entryCount; i++)
00150 if (isEqualID (entries[i].id, id))
00151 return &entries[i];
00152 return 0;
00153 }
00154
00155
00156 const PresetFile::Entry* PresetFile::getLastEntry () const
00157 {
00158 return entryCount > 0 ? &entries[entryCount-1] : 0;
00159 }
00160
00161
00162 bool PresetFile::readID (ChunkID id)
00163 {
00164 int32 numBytesRead = 0;
00165 stream->read (id, sizeof (ChunkID), &numBytesRead);
00166 return numBytesRead == sizeof (ChunkID);
00167 }
00168
00169
00170 bool PresetFile::writeID (const ChunkID id)
00171 {
00172 int32 numBytesWritten = 0;
00173 stream->write ((void*)id, sizeof (ChunkID), &numBytesWritten);
00174 return numBytesWritten == sizeof (ChunkID);
00175 }
00176
00177
00178 bool PresetFile::readEqualID (const ChunkID id)
00179 {
00180 ChunkID temp = {0};
00181 return readID (temp) && isEqualID (temp, id);
00182 }
00183
00184
00185 bool PresetFile::readSize (TSize& size)
00186 {
00187 int32 numBytesRead = 0;
00188 stream->read (&size, sizeof (TSize), &numBytesRead);
00189 #if BYTEORDER == kBigEndian
00190 SWAP_64 (size)
00191 #endif
00192 return numBytesRead == sizeof (TSize);
00193 }
00194
00195
00196 bool PresetFile::writeSize (TSize size)
00197 {
00198 #if BYTEORDER == kBigEndian
00199 SWAP_64 (size)
00200 #endif
00201 int32 numBytesWritten = 0;
00202 stream->write (&size, sizeof (TSize), &numBytesWritten);
00203 return numBytesWritten == sizeof (TSize);
00204 }
00205
00206
00207 bool PresetFile::readInt32 (int32& value)
00208 {
00209 int32 numBytesRead = 0;
00210 stream->read (&value, sizeof (int32), &numBytesRead);
00211 #if BYTEORDER == kBigEndian
00212 SWAP_32 (value)
00213 #endif
00214 return numBytesRead == sizeof (int32);
00215 }
00216
00217
00218 bool PresetFile::writeInt32 (int32 value)
00219 {
00220 #if BYTEORDER == kBigEndian
00221 SWAP_32 (value)
00222 #endif
00223 int32 numBytesWritten = 0;
00224 stream->write (&value, sizeof (int32), &numBytesWritten);
00225 return numBytesWritten == sizeof (int32);
00226 }
00227
00228
00229 bool PresetFile::seekTo (TSize offset)
00230 {
00231 int64 result = -1;
00232 stream->seek (offset, IBStream::kIBSeekSet, &result);
00233 return result == offset;
00234 }
00235
00236
00237 bool PresetFile::readChunkList ()
00238 {
00239 seekTo (0);
00240 entryCount = 0;
00241
00242 char classString[kClassIDSize + 1] = {0};
00243
00244
00245 int32 version = 0;
00246 TSize listOffset = 0;
00247 if (!(readEqualID (getChunkID (kHeader)) &&
00248 readInt32 (version) &&
00249 verify (stream->read (classString, kClassIDSize)) &&
00250 readSize (listOffset) &&
00251 listOffset > 0 &&
00252 seekTo (listOffset)))
00253 return false;
00254
00255 classID.fromString (classString);
00256
00257
00258 int32 count = 0;
00259 if (!readEqualID (getChunkID (kChunkList)))
00260 return false;
00261 if (!readInt32 (count))
00262 return false;
00263
00264 if (count > kMaxEntries)
00265 count = kMaxEntries;
00266
00267 for (int32 i = 0; i < count; i++)
00268 {
00269 Entry& e = entries[i];
00270 if (!(readID (e.id) &&
00271 readSize (e.offset) &&
00272 readSize (e.size)))
00273 break;
00274
00275 entryCount++;
00276 }
00277
00278 return entryCount > 0;
00279 }
00280
00281
00282 bool PresetFile::writeHeader ()
00283 {
00284
00285
00286 char classString[kClassIDSize + 1] = {0};
00287 classID.toString (classString);
00288
00289 return seekTo (0) &&
00290 writeID (getChunkID (kHeader)) &&
00291 writeInt32 (kFormatVersion) &&
00292 verify (stream->write (classString, kClassIDSize)) &&
00293 writeSize (0);
00294 }
00295
00296
00297 bool PresetFile::writeChunkList ()
00298 {
00299
00300 TSize pos = 0;
00301 stream->tell (&pos);
00302 if (!(seekTo (kListOffsetPos) &&
00303 writeSize (pos) &&
00304 seekTo (pos)))
00305 return false;
00306
00307
00308 if (!writeID (getChunkID (kChunkList)))
00309 return false;
00310 if (!writeInt32 (entryCount))
00311 return false;
00312
00313 for (int32 i = 0; i < entryCount; i++)
00314 {
00315 Entry& e = entries[i];
00316 if (!(writeID (e.id) &&
00317 writeSize (e.offset) &&
00318 writeSize (e.size)))
00319 return false;
00320 }
00321 return true;
00322 }
00323
00324
00325 bool PresetFile::beginChunk (Entry& e, ChunkType which)
00326 {
00327 if (entryCount >= kMaxEntries)
00328 return false;
00329
00330 const ChunkID& id = getChunkID (which);
00331 memcpy (e.id, &id, sizeof (ChunkID));
00332 stream->tell (&e.offset);
00333 e.size = 0;
00334 return true;
00335 }
00336
00337
00338 bool PresetFile::endChunk (Entry& e)
00339 {
00340 if (entryCount >= kMaxEntries)
00341 return false;
00342
00343 TSize pos = 0;
00344 stream->tell (&pos);
00345 e.size = pos - e.offset;
00346 entries[entryCount++] = e;
00347 return true;
00348 }
00349
00350
00351 bool PresetFile::readMetaInfo (char* xmlBuffer, int32& size)
00352 {
00353 bool result = false;
00354 const Entry* e = getEntry (kMetaInfo);
00355 if (e)
00356 {
00357 if (xmlBuffer)
00358 {
00359 result = seekTo (e->offset) &&
00360 verify (stream->read (xmlBuffer, size, &size));
00361 }
00362 else
00363 {
00364 size = (int32)e->size;
00365 result = size > 0;
00366 }
00367 }
00368 return result;
00369 }
00370
00371
00372 bool PresetFile::writeMetaInfo (const char* xmlBuffer, int32 size)
00373 {
00374 if (contains (kMetaInfo))
00375 return false;
00376
00377 if (size == -1)
00378 size = (int32)strlen (xmlBuffer);
00379
00380 Entry e = {0};
00381 return beginChunk (e, kMetaInfo) &&
00382 verify (stream->write ((void*)xmlBuffer, size)) &&
00383 endChunk (e);
00384 }
00385
00386
00387 bool PresetFile::prepareMetaInfoUpdate ()
00388 {
00389 TSize writePos = 0;
00390 const Entry* e = getEntry (kMetaInfo);
00391 if (e)
00392 {
00393
00394 if (e != getLastEntry ())
00395 return false;
00396
00397 writePos = e->offset;
00398 entryCount--;
00399 }
00400 else
00401 {
00402
00403 e = getLastEntry ();
00404 writePos = e ? e->offset + e->size : kHeaderSize;
00405 }
00406
00407 return seekTo (writePos);
00408 }
00409
00410
00411 bool PresetFile::writeChunk (const void* data, int32 size, ChunkType which)
00412 {
00413 if (contains (which))
00414 return false;
00415
00416 Entry e = {0};
00417 return beginChunk (e, which) &&
00418 verify (stream->write ((void*)data, size)) &&
00419 endChunk (e);
00420 }
00421
00422
00423 bool PresetFile::storeComponentState (IComponent* component)
00424 {
00425 if (contains (kComponentState))
00426 return false;
00427
00428 Entry e = {0};
00429 return beginChunk (e, kComponentState) &&
00430 verify (component->getState (stream)) &&
00431 endChunk (e);
00432 }
00433
00434
00435 bool PresetFile::restoreComponentState (IComponent* component)
00436 {
00437 const Entry* e = getEntry (kComponentState);
00438 return e && seekTo (e->offset) &&
00439 verify (component->setState (stream));
00440 }
00441
00442
00443 bool PresetFile::restoreComponentState (IEditController* editController)
00444 {
00445 const Entry* e = getEntry (kComponentState);
00446 return e && seekTo (e->offset) &&
00447 verify (editController->setComponentState (stream));
00448 }
00449
00450
00451 bool PresetFile::storeControllerState (IEditController* editController)
00452 {
00453 if (contains (kControllerState))
00454 return false;
00455
00456 Entry e = {0};
00457 return beginChunk (e, kControllerState) &&
00458 verify (editController->getState (stream)) &&
00459 endChunk (e);
00460 }
00461
00462
00463 bool PresetFile::restoreControllerState (IEditController* editController)
00464 {
00465 const Entry* e = getEntry (kControllerState);
00466 return e && seekTo (e->offset) &&
00467 verify (editController->setState (stream));
00468 }
00469
00470
00471 bool PresetFile::storeProgramData (IBStream* inStream, ProgramListID listID, int32 programIndex)
00472 {
00473 if (contains (kProgramData))
00474 return false;
00475
00476 Entry e = {0};
00477 if (beginChunk (e, kProgramData))
00478 {
00479 if (writeInt32 (listID))
00480 {
00481 int8 buffer[128];
00482 int32 read = 0;
00483 int32 written = 0;
00484 while (inStream->read (buffer, 128, &read) == kResultTrue && read > 0)
00485 {
00486 if (stream->write (buffer, read, &written) != kResultTrue)
00487 {
00488 return false;
00489 }
00490 }
00491 return endChunk (e);
00492 }
00493 }
00494 return false;
00495 }
00496
00497
00498 bool PresetFile::storeProgramData (IUnitData* unitData, ProgramListID listID, int32 programIndex)
00499 {
00500 if (contains (kProgramData))
00501 return false;
00502
00503 Entry e = {0};
00504 return beginChunk (e, kProgramData) &&
00505 writeInt32 (listID) &&
00506 verify (unitData->getProgramData (listID, programIndex, stream)) &&
00507 endChunk (e);
00508 }
00509
00510
00511 bool PresetFile::restoreProgramData (IUnitData* unitData, ProgramListID* listID, int32 programIndex)
00512 {
00513 const Entry* e = getEntry (kProgramData);
00514 ProgramListID savedListID = -1;
00515 if (e && seekTo (e->offset))
00516 {
00517 if (readInt32 (savedListID))
00518 {
00519 if (listID && *listID != savedListID)
00520 return false;
00521 return verify (unitData->setProgramData (savedListID, programIndex, stream));
00522 }
00523 }
00524 return false;
00525 }
00526
00527
00528 bool PresetFile::restoreProgramData (IUnitInfo* unitInfo, ProgramListID listID, int32 programIndex)
00529 {
00530 const Entry* e = getEntry (kProgramData);
00531 ProgramListID savedListID = -1;
00532 return e && seekTo (e->offset) &&
00533 readInt32 (savedListID) &&
00534 listID == savedListID &&
00535 verify (unitInfo->setUnitProgramData (listID, programIndex, stream));
00536 }
00537
00538
00539
00540
00541 IBStream* FileStream::open (const char* filename, const char* mode)
00542 {
00543 FILE* file = fopen (filename, mode);
00544 return file ? new FileStream (file) : 0;
00545 }
00546
00547
00548 FileStream::FileStream (FILE* file)
00549 : file (file)
00550 {
00551 FUNKNOWN_CTOR
00552 }
00553
00554
00555 FileStream::~FileStream ()
00556 {
00557 fclose (file);
00558 FUNKNOWN_DTOR
00559 }
00560
00561
00562 IMPLEMENT_FUNKNOWN_METHODS (FileStream, IBStream, IBStream::iid)
00563
00564
00565 tresult PLUGIN_API FileStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
00566 {
00567 size_t result = fread (buffer, 1, numBytes, file);
00568 if (numBytesRead)
00569 *numBytesRead = (int32)result;
00570 return result == numBytes ? kResultOk : kResultFalse;
00571 }
00572
00573
00574 tresult PLUGIN_API FileStream::write (void* buffer, int32 numBytes, int32* numBytesWritten)
00575 {
00576 size_t result = fwrite (buffer, 1, numBytes, file);
00577 if (numBytesWritten)
00578 *numBytesWritten = (int32)result;
00579 return result == numBytes ? kResultOk : kResultFalse;
00580 }
00581
00582
00583 tresult PLUGIN_API FileStream::seek (int64 pos, int32 mode, int64* result)
00584 {
00585 if (fseek (file, (int32)pos, mode) == 0)
00586 {
00587 if (result)
00588 *result = ftell (file);
00589 return kResultOk;
00590 }
00591 return kResultFalse;
00592 }
00593
00594
00595 tresult PLUGIN_API FileStream::tell (int64* pos)
00596 {
00597 if (pos)
00598 *pos = ftell (file);
00599 return kResultOk;
00600 }
00601
00602
00603 }}