Example #1
0
void StTranslations::setLanguage(const int32_t theNewLang) {
    if(size_t(theNewLang) >= params.language->getValues().size()) {
        return;
    }

    // save global setting
    const StString& aFolderName = myLangFolderList[theNewLang];
    StSettings aGlobalSettings(myResMgr, ST_GLOBAL_SETTINGS_GROUP);
    aGlobalSettings.saveString(ST_SETTING_LANGUAGE, aFolderName);

    updateLangCode(theNewLang);

    // reload translation file
    StLangMap::clear();

    const StString aResName = StString()
                            + "lang" ST_FILE_SPLITTER
                            + aFolderName  + SYS_FS_SPLITTER
                            + myModuleName + StTranslations::DEFAULT_SUFFIX;
    StHandle<StResource> aRes = myResMgr->getResource(aResName);
    if(!aRes.isNull()
    &&  aRes->read()) {
        const char* aSrc = (const char* )aRes->getData();
        const int   aLen = aRes->getSize();
        read(aSrc, aLen);
    }
    myWasReloaded = true;
}
Example #2
0
void StApplication::addAction(const int           theActionId,
                              StHandle<StAction>& theAction,
                              const unsigned int  theHotKey1,
                              const unsigned int  theHotKey2) {
    theAction->setDefaultHotKey1(theHotKey1);
    theAction->setDefaultHotKey2(theHotKey2);
    addAction(theActionId, theAction);
}
Example #3
0
void StImageFileCounter::createReference(StHandle<StBufferCounter>& theOther) const {
    StHandle<StImageFileCounter> anImgFileRef = StHandle<StImageFileCounter>::downcast(theOther);
    if(anImgFileRef.isNull()) {
        anImgFileRef = new StImageFileCounter();
        theOther = anImgFileRef;
    }
    anImgFileRef->myImageFile = myImageFile;
}
Example #4
0
void StTestEmbed::embedAppLoop() {
    StHandle<StApplication> anApp = new StApplication(new StResourceManager(), myParent);
    if(!anApp->open()) {
        return;
    }

    anApp->exec();
}
Example #5
0
void StActiveXCtrl::stWindowLoop() {
    // do not load plugin until it is placed on screen
    StWindow aParentWin(myResMgr, myParentWin);
    for(;;) {
        if(aParentWin.isParentOnScreen()) {
            break;
        }

        StThread::sleep(10);
        if(myToQuit) {
            return;
        }
    }

    myStApp = new StImageViewer(myResMgr, myParentWin, new StOpenInfo());
    if(!myStApp->open()) {
        myStApp.nullify();
        return;
    }

    bool isFullscreen = false;
    myIsActive = true;
    for(;;) {
        if(myStApp->closingDown()) {
            myStApp.nullify();
            myIsActive = false;
            return;
        }

        myIsActive = myStApp->isActive();
        if(myToQuit) {
            myStApp->exit(0);
        } else if(myOpenEvent.check()
               && myStApp->isActive()) {
            // load the image
            myStApp->open(myOpenInfo);
            myOpenEvent.reset();
        }

        StHandle<StWindow> aWin = myStApp->getMainWindow();
        if(myIsActive) {
            aWin->show();
        } else {
            aWin->hide();
        }
        myStApp->processEvents();

        if(aWin->isFullScreen()) {
            if(!isFullscreen) {
                PostMessage(WM_TIMER, 1);
                isFullscreen = true;
            }
        } else if(isFullscreen) {
            PostMessage(WM_TIMER, 0);
            isFullscreen = false;
        }
    }
}
Example #6
0
StHandle<StFileNode> StFileNode::detach() const {
    StHandle<StFileNode> aCopy = new StFileNode(getPath());
    aCopy->setMIME(getMIME());
    for(size_t aSubId = 0; aSubId < size(); ++aSubId) {
        const StFileNode* aSubNode = getValue(aSubId);
        aCopy->add(new StFileNode(aSubNode->getSubPath(), aCopy.access()));
    }
    return aCopy;
}
Example #7
0
void StJpegParser::fillDictionary(StDictionary& theDict,
                                  const bool    theToShowUnknown) const {
    for(StHandle<StJpegParser::Image> anImg = myImages;
        !anImg.isNull(); anImg = anImg->Next) {
        for(size_t anExifId = 0; anExifId < anImg->Exif.size(); ++anExifId) {
            anImg->Exif[anExifId]->fillDictionary(theDict, theToShowUnknown);
        }
    }
}
Example #8
0
bool StJpegParser::insertSection(const uint8_t   theMarker,
                                 const uint16_t  theSectLen,
                                 const ptrdiff_t theOffset) {
    const size_t aDiff    = size_t(theSectLen) + 2; // 2 bytes for marker
    const size_t aNewSize = myLength + aDiff;
    if(aNewSize > myBuffSize) {
        myBuffSize = aNewSize + 256;
        stUByte_t* aNewData = stMemAllocAligned<stUByte_t*>(myBuffSize);
        if(aNewData == NULL) {
            return false;
        }
        stMemCpy(aNewData, myBuffer, myLength);
        if(myIsOwnData) {
            stMemFreeAligned(myBuffer);
        }
        myIsOwnData = true;

        // update pointers of image(s) data
        for(StHandle<StJpegParser::Image> anImg = myImages;
            !anImg.isNull(); anImg = anImg->Next) {
            ptrdiff_t anOffset = anImg->Data - myBuffer;
            if(anOffset >= theOffset) {
                anOffset += aDiff;
            }
            anImg->Data = aNewData + anOffset;
            if(!anImg->Thumb.isNull()) {
                anOffset = anImg->Thumb->Data - myBuffer;
                if(anOffset >= theOffset) {
                    anOffset += aDiff;
                }
                anImg->Thumb->Data = aNewData + anOffset;
            }
        }

        myBuffer = aNewData;
    }
    myLength = aNewSize;

    // update offset table
    for(size_t anIter = 0; anIter < OffsetsNb; ++anIter) {
        if(myOffsets[anIter] >= theOffset) {
            myOffsets[anIter] += aDiff;
        }
    }

    // initialize new section
    const size_t aTailSize = myLength - theOffset;
    std::memmove(myBuffer + theOffset + 2 + size_t(theSectLen),
                 myBuffer + theOffset,
                 aTailSize);
    stUByte_t* aData = myBuffer + theOffset;
    aData[0] = 0xFF;
    aData[1] = theMarker;
    StAlienData::Set16uBE(aData + 2, theSectLen);
    return true;
}
Example #9
0
void StApplication::addAction(const int                 theActionId,
                              const StHandle<StAction>& theAction) {
    myActions[theActionId] = theAction;
    if(!theAction.isNull()) {
        StString aNameLower = theAction->getName();
        aNameLower.toLowerCase();
        const std::string aName(aNameLower.toCString());
        myActionLookup[aName] = theActionId;
    }
}
Example #10
0
int main(int , char** ) { // force console output
#else
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { // prevent console output
#endif
    setlocale(LC_ALL, ".OCP"); // we set default locale for console output (useful only for debug)
#else
int main(int , char** ) {
#endif
    StOutPageFlip::initGlobalsAsync();
    if(!StVersionInfo::checkTimeBomb("sView")) {
        return 1;
    }

    // setup environment variables
    const StString ST_ENV_NAME_STCORE_PATH =
    #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
        "StCore64";
    #else
        "StCore32";
    #endif
    const StString aProcessPath = StProcess::getProcessFolder();
    StString aProcessUpPath = StFileNode::getFolderUp(aProcessPath);
    if(!aProcessUpPath.isEmpty()) {
        aProcessUpPath += SYS_FS_SPLITTER;
    }
    StProcess::setEnv(ST_ENV_NAME_STCORE_PATH, aProcessPath);
    if(StFolder::isFolder(aProcessPath + "textures")) {
        StProcess::setEnv("StShare", aProcessPath);
    } else if(StFolder::isFolder(aProcessUpPath + "textures")) {
        StProcess::setEnv("StShare", aProcessUpPath);
    }

    StString aResDir = StProcess::getStShareFolder();
    StProcess::setEnv("CSF_UnitsLexicon",          aResDir + "UnitsAPI" ST_FILE_SPLITTER "Lexi_Expr.dat");
    StProcess::setEnv("CSF_UnitsDefinition",       aResDir + "UnitsAPI" ST_FILE_SPLITTER "Units.dat");
    StProcess::setEnv("CSF_ShadersDirectory",      aResDir + "shaders" ST_FILE_SPLITTER "StCADViewer");
    StProcess::setEnv("CSF_SHMessage",             aResDir + "lang");
    StProcess::setEnv("CSF_MDTVTexturesDirectory", aResDir + "textures");

    StHandle<StOpenInfo> anInfo;
    if(anInfo.isNull()
    || (!anInfo->hasPath() && !anInfo->hasArgs())) {
        anInfo = StApplication::parseProcessArguments();
    }
    if(anInfo.isNull()) {
        // show help
        StString aShowHelpString = getAbout();
        st::cout << aShowHelpString;
        stInfo(aShowHelpString);
        return 0;
    }

    StHandle<StResourceManager> aResMgr = new StResourceManager();
    StHandle<StCADViewer> anApp  = new StCADViewer(aResMgr, NULL, anInfo);
    if(!anApp->open()) {
        return 1;
    }
    return anApp->exec();
}
Example #11
0
bool StDXManager::checkAqbsSupport(const HWND theWinHandle) {
    if(!initDxLib()) {
        return false;
    }

    const UINT aD3dAdaptersNb = getAdapterCount();
    D3DADAPTER_IDENTIFIER9 anAdapterInfo;
    for(UINT anAdapterIter = 0; anAdapterIter < aD3dAdaptersNb; ++anAdapterIter) {
        getAdapterIdentifier(anAdapterIter, 0, &anAdapterInfo);
        if(anAdapterInfo.VendorId != ST_DX_VENDOR_AMD) {
            continue;
        }

        // setup the present parameters
        if(getAdapterDisplayMode(anAdapterIter, &myCurrMode) == D3D_OK) {
            myD3dParams.BackBufferFormat = myCurrMode.Format;
            myRefreshRate = myCurrMode.RefreshRate;
        }

        // create temporary video device
        myD3dParams.hDeviceWindow = theWinHandle;
        myD3dDevice = createAqbsTmpDevice(anAdapterIter, theWinHandle, myD3dParams);
        if(myD3dDevice == NULL) {
            continue;
        }

        // create a surface to be used to communicate with the driver
        StHandle<StDXAqbsControl> anAqbsControl = new StDXAqbsControl(myD3dDevice);
        if(!anAqbsControl->isValid()) {
            myD3dDevice->Release();
            myD3dDevice = NULL;
            return false;
        }

        // send the command to the driver using the temporary surface
        if(!anAqbsControl->enableStereo()) {
            anAqbsControl.nullify();
            myD3dDevice->Release();
            myD3dDevice = NULL;
            return false;
        }
        myWithAqbs = true;
        anAqbsControl.nullify();
        myD3dDevice->Release();
        myD3dDevice = NULL;
        return true;
    }
    return false;
}
Example #12
0
void StApplication::addRenderer(const StHandle<StWindow>& theRenderer) {
    if(theRenderer.isNull()) {
        return;
    }

    StHandle<StWindow> aRenderer = theRenderer;
    aRenderer->params.VSyncMode = params.VSyncMode; // share VSync mode between renderers
    aRenderer->setMessagesQueue(myMsgQueue);
    myRenderers.add(aRenderer);
    size_t aDevIter = myDevices.size();
    aRenderer->getDevices(myDevices);
    for(; aDevIter < myDevices.size(); ++aDevIter) {
        params.ActiveDevice->changeValues().add(myDevices[aDevIter]->Name);
    }
}
Example #13
0
 ST_LOCAL StGLMenuActionItem(StGLMenu*                 theParent,
                             const StHandle<StAction>& theAction,
                             StGLMenu*                 theSubMenu)
 : StGLMenuItem(theParent, 0, 0, theSubMenu),
   myAction(theAction) {
     ST_ASSERT(!theAction.isNull(), "StGLMenuActionItem - Unexpected empty action makes no sense!");
     StGLMenuItem::signals.onItemClick.connect(this, &StGLMenuActionItem::doItemClick);
 }
Example #14
0
bool StJpegParser::parse() {
    if(myBuffer == NULL) {
        return false;
    }

    int aCount = 0;
    myImages = parseImage(++aCount, 1, myBuffer, false);
    if(myImages.isNull()) {
        return false;
    }

    // continue reading the file (MPO may contains more than 1 image)
    for(StHandle<StJpegParser::Image> anImg = myImages;
        !anImg.isNull(); anImg = anImg->Next) {
        anImg->Next = parseImage(++aCount, 1, anImg->Data + anImg->Length, true);
    }

    return true;
}
Example #15
0
bool StPlayList::removePhysically(const StHandle<StFileNode>& theFileNode) {
    StString    aPath    = theFileNode->getPath();
    StPlayItem* aRemItem = NULL;
    StMutexAuto anAutoLock(myMutex);
    if(myCurrent == NULL) {
        // empty playlist
        return false;
    } else if(aPath != myCurrent->getPath()) {
        // search play item
        for(StPlayItem* anItem = myFirst; anItem != NULL; anItem = anItem->getNext()) {
            if(aPath == anItem->getPath()) {
                aRemItem = anItem;
                break;
            }
        }
    } else {
        // walk to another playlist position
        aRemItem = myCurrent;
        const bool aPlayedFlag = aRemItem->getPlayedFlag();
        if(myCurrent->hasNext()) {
            myCurrent = myCurrent->getNext();
        } else if(myCurrent->hasPrev()) {
            myCurrent = myCurrent->getPrev();
        } else {
            myCurrent     = NULL;
            myPlayedCount = 0;
        }

        if(myCurrent != NULL) {
            if(aRemItem->getPlayedFlag() != aPlayedFlag) {
                // the item has not been played yet - mark it as such
                aRemItem->setPlayedFlag(aPlayedFlag);
            } else {
                // one played item has been removed
                --myPlayedCount;
            }
        }
    }

    // remove item itself
    const bool isDeleted = aRemItem != NULL
                        && StFileNode::removeFile(aPath);
    if(isDeleted) {
        delPlayItem(aRemItem);
        delete aRemItem;
    }

    anAutoLock.unlock();
    signals.onPlaylistChange();
    return isDeleted;
}
Example #16
0
void StCADViewerGUI::doOpenFile(const size_t ) {
    StGLOpenFile* aDialog = new StGLOpenFile(this, tr(DIALOG_OPEN_FILE), tr(BUTTON_CLOSE));
    aDialog->setMimeList(StCADLoader::ST_CAD_MIME_LIST);
#if defined(_WIN32)
    //
#else
    aDialog->addHotItem("/", "Root");
#endif
    aDialog->addHotItem(getResourceManager()->getFolder(StResourceManager::FolderId_SdCard));
    aDialog->addHotItem(getResourceManager()->getFolder(StResourceManager::FolderId_Downloads));
    aDialog->addHotItem(getResourceManager()->getFolder(StResourceManager::FolderId_Pictures));
    aDialog->addHotItem(getResourceManager()->getFolder(StResourceManager::FolderId_Photos));
    aDialog->signals.onFileSelected = stSlot(myPlugin, &StCADViewer::doOpen1FileFromGui);

    if(myPlugin->params.LastFolder.isEmpty()) {
        StHandle<StFileNode> aCurrFile = myPlugin->myPlayList->getCurrentFile();
        if(!aCurrFile.isNull()) {
            myPlugin->params.LastFolder = aCurrFile->isEmpty() ? aCurrFile->getFolderPath() : aCurrFile->getValue(0)->getFolderPath();
        }
    }
    aDialog->openFolder(myPlugin->params.LastFolder);
    setModalDialog(aDialog);
}
Example #17
0
bool StPlayList::getCurrentFile(StHandle<StFileNode>&     theFileNode,
                                StHandle<StStereoParams>& theParams,
                                StHandle<StFileNode>&     thePlsFile) {
    theFileNode.nullify();
    theParams.nullify();
    thePlsFile.nullify();
    StMutexAuto anAutoLock(myMutex);
    if(myCurrent == NULL) {
        // empty list
        return false;
    }
    StFileNode* aFileNode = myCurrent->getFileNode();
    if(aFileNode == NULL) {
        // invalid item
        return false;
    }

    theFileNode = aFileNode->detach();
    theParams   = myCurrent->getParams();
    if(!myPlsFile.isNull()) {
        thePlsFile = myPlsFile->File;
    }
    return true;
}
Example #18
0
 StTrackedFloatParam(const StHandle<StFloat32Param>& theTracked1,
                     const StHandle<StFloat32Param>& theTracked2)
 : StFloat32Param(theTracked1->getValue(),
                  theTracked1->getMinValue(),
                  theTracked1->getMaxValue(),
                  theTracked1->getDefValue(),
                  theTracked1->getStep(),
                  theTracked1->getTolerance()),
   myTracked1(theTracked1),
   myTracked2(theTracked2) {}
Example #19
0
void StPlayList::loadRecentList(const StString theString) {
    StMutexAuto anAutoLock(myMutex);
    StArgumentsMap aMap;
    aMap.parseString(theString);
    myRecent.clear();

    for(size_t anIter = 0; anIter < myRecentLimit; ++anIter) {
        const StArgument anArgFile  = aMap[StString("file")  + anIter];
        const StArgument anArgLeft  = aMap[StString("left")  + anIter];
        const StArgument anArgRight = aMap[StString("right") + anIter];
        const StArgument anArgTime  = aMap[StString("time")  + anIter];
        StHandle<StRecentItem> aRecent;
        if(anArgLeft.isValid() && anArgRight.isValid()) {
            StHandle<StFileNode> aFileNode = new StFileNode(StString());
            aFileNode->add(new StFileNode(anArgLeft.getValue(),  aFileNode.access()));
            aFileNode->add(new StFileNode(anArgRight.getValue(), aFileNode.access()));
            aRecent = addRecentFile(*aFileNode, false);
        } else if(anArgFile.isValid()) {
            StHandle<StFileNode> aFileNode = new StFileNode(anArgFile.getValue());
            const StArgument anArgPos = aMap[StString("pos") + anIter];
            if(anArgPos.isValid()) {
                aFileNode->add(new StFileNode(anArgPos.getValue(), aFileNode.access()));
            }
            aRecent = addRecentFile(*aFileNode, false);
        }
        if(aRecent.isNull()) {
            continue;
        }

        if(anArgTime.isValid()) {
            if(aRecent->Params.isNull()) {
                aRecent->Params = new StStereoParams();
            }
            std::stringstream aStream;
            aStream.imbue(std::locale("C"));
            aStream << anArgTime.getValue().toCString();
            aStream >> aRecent->Params->Timestamp;
        }
    }
}
Example #20
0
void StPlayList::updateRecent(const StHandle<StFileNode>&     theFile,
                              const StHandle<StStereoParams>& theParams) {
    if(theFile.isNull()) {
        return;
    }

    StMutexAuto anAutoLock(myMutex);
    if(!myPlsFile.isNull()
     && myPlsFile->File == theFile) {
        // remember properties of last played file
        myPlsFile->Params = theParams;
        return;
    }

    for(size_t anIter = 0; anIter < myRecent.size(); ++anIter) {
        StHandle<StRecentItem>& aRecent = myRecent[anIter];
        if(stAreSameRecent(*theFile, *aRecent->File)) {
            aRecent->Params = theParams;
            return;
        }
    }
}
Example #21
0
StHandle<StStereoParams> StPlayList::openRecent(const size_t theItemId) {
    StMutexAuto anAutoLock(myMutex);
    if(theItemId >= myRecent.size()) {
        return StHandle<StStereoParams>();
    }

    const StHandle<StRecentItem> aRecent = myRecent[theItemId];
    const StHandle<StFileNode>   aFile   = aRecent->File;
    if(aFile->size() == 2) {
        // stereo pair from two files
        clear();
        addOneFile(aFile->getValue(0)->getPath(),
                   aFile->getValue(1)->getPath());
    } else if(aFile->size() == 1) {
        // playlist
        open(aFile->getPath(), aFile->getValue(0)->getSubPath());
    } else {
        // single file
        open(aFile->getPath());
    }
    return aRecent->Params;
}
Example #22
0
void StPlayList::addToNode(const StHandle<StFileNode>& theFileNode,
                           const StString&             thePathToAdd) {
    StString aPath = theFileNode->getPath();
    StMutexAuto anAutoLock(myMutex);
    if(myCurrent == NULL) {
        return;
    } else if(aPath != myCurrent->getPath()) {
        for(StPlayItem* anItem = myFirst; anItem != NULL; anItem = anItem->getNext()) {
            if(aPath == anItem->getPath()) {
                myCurrent = anItem;
                break;
            }
        }
    }

    StFileNode* aFileNode = myCurrent->getFileNode();
    if(aFileNode->getParent() != &myFoldersRoot) {
        // convert filenode to metafile with empty root
        aFileNode->reParent(&myFoldersRoot);
        aFileNode->setSubPath(StString());
        aFileNode->add(new StFileNode(aPath, aFileNode));
    }
    aFileNode->add(new StFileNode(thePathToAdd, aFileNode));
}
Example #23
0
    /**
     * Copy OCCT resource file.
     */
    ST_LOCAL bool copyResource(const StHandle<StResourceManager>& theResMgr,
                               const StString& theResFolder,
                               const StString& theDestFolder,
                               const StString& theFileName) {
        StString aFileResPath = theResFolder + SYS_FS_SPLITTER + theFileName;
        StHandle<StResource> aRes = theResMgr->getResource(aFileResPath);
        if( aRes.isNull()
        || !aRes->read()) {
            ST_ERROR_LOG(StString("Can not read resource file ") + aFileResPath);
            return false;
        }

        StRawFile aFileOut;
        StString  aFileOutPath = theDestFolder + SYS_FS_SPLITTER + theFileName;
        if(!aFileOut.openFile(StRawFile::WRITE, aFileOutPath)) {
            ST_ERROR_LOG(StString("Can not create resource file ") + aFileOutPath);
            return false;
        }
        if(!aFileOut.write((const char* )aRes->getData(), aRes->getSize()) != aRes->getSize()) {
            ST_ERROR_LOG(StString("Can not write resource file ") + aFileOutPath);
            return false;
        }
        return true;
    }
Example #24
0
void StApplication::registerHotKeys() {
    myKeyActions.clear();
    for(std::map< int, StHandle<StAction> >::iterator anIter = myActions.begin();
        anIter != myActions.end(); ++anIter) {
        const StHandle<StAction>& anAction = anIter->second;
        if(anAction->getHotKey1() != 0) {
            StHandle<StAction> anOldAction = getActionForKey(anAction->getHotKey1());
            if(!anOldAction.isNull()) {
                anOldAction->setHotKey1(0);
            }
            myKeyActions[anAction->getHotKey1()] = anAction;
        }
        if(anAction->getHotKey2() != 0) {
            StHandle<StAction> anOldAction = getActionForKey(anAction->getHotKey2());
            if(!anOldAction.isNull()) {
                anOldAction->setHotKey2(0);
            }
            myKeyActions[anAction->getHotKey2()] = anAction;
        }
    }
}
Example #25
0
StHandle<StJpegParser::Image> StJpegParser::parseImage(const int      theImgCount,
                                                       const int      theDepth,
                                                       unsigned char* theDataStart,
                                                       const bool     theToFindSOI) {
    // check out of bounds
    if(theDataStart == NULL) {
        return StHandle<StJpegParser::Image>();
    }

    unsigned char*       aData    = theDataStart;
    const unsigned char* aDataEnd = myBuffer + myLength;

    // search image beginning
    if(theToFindSOI) {
        ++aData;
        for(; aData < aDataEnd; ++aData) {
            if(aData[-1] == 0xFF && aData[0] == M_SOI) {
                --aData;
                break;
            }
        }
    }

    // check out of bounds
    if((aData + 2) > aDataEnd) {
        return StHandle<StJpegParser::Image>();
    }

    // check the jpeg identifier
    if(aData[0] != 0xFF || aData[1] != M_SOI) {
        ST_DEBUG_LOG("StJpegParser, no SOI at position " + size_t(aData - myBuffer) + " / " + myLength);
        return StHandle<StJpegParser::Image>();
    }
    aData += 2; // skip already read bytes

    // parse the data
    StHandle<StJpegParser::Image> anImg = new StJpegParser::Image();
    anImg->Data = aData - 2;

    for(;;) {
        // search for the next marker in the file
        ++aData; // one byte forward
        size_t aSkippedBytes = 0;
        unsigned char aMarker = 0;
        for(; aData < aDataEnd; ++aSkippedBytes, ++aData) {
            aMarker = aData[0];
            if(aData[-1] == 0xFF
            && aMarker   != 0xFF
            && aMarker   != 0x00) {
                ++aData; // skip marker id byte
                break;
            }
        }

        //ST_DEBUG_LOG(" #" + theImgCount + "." + theDepth + " [" + markerString(aMarker) + "] at position " + size_t(aData - myBuffer) + " / " + myLength); ///
        if(aMarker == M_EOI) {
            //ST_DEBUG_LOG("Jpeg, EOI at position " + size_t(aData - myBuffer) + " / " + myLength);
            anImg->Length = size_t(aData - anImg->Data);
            return anImg;
        } else if(aMarker == M_SOI) {
            // here the subimage (thumbnail)...
            //ST_DEBUG_LOG("Jpeg, SOI at position " + size_t(aData - myBuffer) + " / " + myLength);
            anImg->Thumb = StJpegParser::parseImage(theImgCount, theDepth + 1, aData - 2, false);
            if(!anImg->Thumb.isNull()) {
                //ST_DEBUG_LOG("anImg->Thumb->Length= " + anImg->Thumb->Length);
                aData += anImg->Thumb->Length - 2;
            }
            continue;
        }

        if(aData + 2 >= aDataEnd) {
            ST_DEBUG_LOG("Corrupt jpeg file or error in parser");
            if(myImages.isNull()) {
                anImg->Data   = myBuffer;
                anImg->Length = myLength;
            }
            return anImg;
        } else if(aSkippedBytes > 10) {
            //ST_DEBUG_LOG("Extraneous " + (aSkippedBytes - 1) + " padding bytes before section " + aMarker);
        }

        // read the length of the section (including these 2 bytes but excluding marker)
        const int anItemLen = StAlienData::Get16uBE(aData);
        if(anItemLen < 3
        || (aData + anItemLen) > aDataEnd) {
            //ST_DEBUG_LOG("Invalid marker " + aMarker + " in jpeg (item lenght = " + anItemLen
            //           + " from position " + int(aDataEnd - aData - 2) + ')');
            // just ignore probably unknown sections
            continue;
        }

        switch(aMarker) {
            case M_SOF0:
            case M_SOF1:
            case M_SOF2:
            case M_SOF3: {
                if(anItemLen >= 7) {
                    anImg->SizeY = StAlienData::Get16uBE(aData + 2 + 1);
                    anImg->SizeX = StAlienData::Get16uBE(aData + 2 + 3);
                    //ST_DEBUG_LOG("   SOF " + anImg->SizeX + "x" + anImg->SizeY);
                }
                aData += anItemLen;
                break;
            }
            case M_DRI: {
                if(anItemLen == 4) {
                    //const int16_t aNbRestartBlocks = anImg->SizeY = StAlienData::Get16uBE(aData + 2);
                }
                aData += anItemLen;
                break;
            }
            case M_SOS: {
                // here the image data...
                //ST_DEBUG_LOG("Jpeg, SOS at position " + size_t(aData - myBuffer - 1) + " / " + myLength);
                aData += anItemLen;
                break;
            }
            case M_RST0:
            case M_RST1:
            case M_RST2:
            case M_RST3:
            case M_RST4:
            case M_RST5:
            case M_RST6:
            case M_RST7: {
                // aData += aNbRestartBlocks * aMcuSize;
                break;
            }
            case M_JFIF: {
                if(anItemLen >= 16
                && stAreEqual(aData + 2, "JFIF\0", 5)) {
                    myOffsets[Offset_Jfif] = aData - myBuffer - 2;
                    //const int8_t aVerMaj = (int8_t )aData[7];
                    //const int8_t aVerMin = (int8_t )aData[8];
                    const JfifUnitsXY aUnits = (JfifUnitsXY )aData[9];
                    const uint16_t aDensityX = StAlienData::Get16uBE(aData + 10);
                    const uint16_t aDensityY = StAlienData::Get16uBE(aData + 12);
                    //const int8_t  aThumbX   = (int8_t )aData[14];
                    //const int8_t  aThumbY   = (int8_t )aData[15];
                    if(aUnits == JfifUnitsXY_AspectRatio) {
                        anImg->ParX = aDensityX;
                        anImg->ParY = aDensityY;
                    }
                    //ST_DEBUG_LOG("  ## JFIF" + aVerMaj + "." + aVerMin + " u" + (int )aUnits + " " + aDensityX + "x" + aDensityY
                    //           + " thumb " + aThumbX + "x" + aThumbY);
                } else if(stAreEqual(aData + 2, "JFXX\0", 5)) {
                    // JFIF extension
                }

                aData += anItemLen;
                break;
            }
            case M_EXIF:
            case M_APP2: {
                myOffsets[aMarker == M_EXIF ? Offset_Exif : Offset_ExifExtra] = aData - myBuffer - 2;
                // there can be different section using the same marker
                if(stAreEqual(aData + 2, "Exif\0\0", 6)) {
                    //ST_DEBUG_LOG("Exif section...");
                    StHandle<StExifDir> aSubDir = new StExifDir();
                    anImg->Exif.add(aSubDir);
                    if(!aSubDir->parseExif(anImg->Exif, aData + 8, anItemLen - 8)) {
                        //
                    }
                } else if(stAreEqual(aData + 2, "MPF\0", 4)) {
                    // MP Extensions (MPO)
                    StHandle<StExifDir> aSubDir = new StExifDir();
                    aSubDir->Type = StExifDir::DType_MPO;
                    anImg->Exif.add(aSubDir);
                    if(!aSubDir->parseExif(anImg->Exif, aData + 6, anItemLen - 6)) {
                        //
                    }
                } else if(stAreEqual(aData + 2, "http:", 5)) {
                    //ST_DEBUG_LOG("Image cotains XMP section");
                } else {
                    //ST_DEBUG_LOG("  @@@ APP2 " + StString((char* )aData + 2));
                }
                // skip already read bytes
                aData += anItemLen;
                break;
            }
            case M_APP3: {
                if(anItemLen >= 16
                && stAreEqual(aData + 2, "_JPSJPS_", 8)) {
                    // outdated VRex section
                    myOffsets[Offset_Jps] = aData - myBuffer - 2;
                    //ST_DEBUG_LOG("Jpeg, _JPSJPS_ section (len= )" + anItemLen);
                    //const uint16_t aBlockLen   = StAlienData::Get16uBE(aData + 10);
                    const uint32_t aStereoDesc = StAlienData::Get32uBE(aData + 12);

                    #define SD_LAYOUT_INTERLEAVED 0x00000100
                    #define SD_LAYOUT_SIDEBYSIDE  0x00000200
                    #define SD_LAYOUT_OVERUNDER   0x00000300
                    #define SD_LAYOUT_ANAGLYPH    0x00000400

                    #define SD_HALF_HEIGHT        0x00010000
                    #define SD_HALF_WIDTH         0x00020000
                    #define SD_LEFT_FIELD_FIRST   0x00040000

                    if(aStereoDesc & 0x00000001) {
                        const bool isLeftFirst = (aStereoDesc & SD_LEFT_FIELD_FIRST) != 0;
                        switch(aStereoDesc & 0x0000FF00) {
                            case SD_LAYOUT_INTERLEAVED: myStFormat = ST_V_SRC_ROW_INTERLACE;     break;
                            case SD_LAYOUT_SIDEBYSIDE:  myStFormat = isLeftFirst
                                                                   ? ST_V_SRC_PARALLEL_PAIR
                                                                   : ST_V_SRC_SIDE_BY_SIDE;      break;
                            case SD_LAYOUT_OVERUNDER:   myStFormat = isLeftFirst
                                                                   ? ST_V_SRC_OVER_UNDER_LR
                                                                   : ST_V_SRC_OVER_UNDER_RL;     break;
                            case SD_LAYOUT_ANAGLYPH:    myStFormat = ST_V_SRC_ANAGLYPH_RED_CYAN; break;
                            default: break;
                        }
                    } else {
                        myStFormat = ST_V_SRC_MONO;
                    }
                    if(anItemLen > 18) {
                        const uint16_t aStringLen = StAlienData::Get16uBE(aData + 16);
                        char* aStrData = (char* )aData + 18;
                        myJpsComment = StString(aStrData, aStringLen);
                    }
                }
                // skip already read bytes
                aData += anItemLen;
                break;
            }
            case M_DQT: {
                myOffsets[Offset_Dqt] = aData - myBuffer - 2;
                aData += anItemLen;
                break;
            }
            case M_APP4:
            case M_APP5:
            case M_APP6:
            case M_APP7:
            case M_APP8:
            case M_APP9:
            case M_APP10:
            case M_APP11:
            case M_APP12:
            case M_APP13:
            case M_APP14:
            case M_APP15:
            case M_DHT: {
                aData += anItemLen;
                break;
            }
            case M_COM: {
                myOffsets[Offset_Comment] = aData - myBuffer - 2;
                if(anItemLen > 2) {
                    myComment = StString((char* )aData + 2, anItemLen - 2);
                }
                //ST_DEBUG_LOG("StJpegParser, comment= '" + myComment + "'");
                aData += anItemLen;
                break;
            }
            default: {
                // carefully skip unknown sections
                //aData += anItemLen;
                break;
            }
        }
    }
}
Example #26
0
void StBrowserPlugin::stWindowLoop() {
    // do not load plugin until it is placed on screen
    StWindow aParentWin(myResMgr, myParentWin);
    for(;;) {
#ifndef _WIN32
        const int32_t anActiveNb =
#endif
            ST_PLUGIN_QUEUE.increment();

        if(aParentWin.isParentOnScreen()
#ifndef _WIN32
                || anActiveNb <= 1
#endif
          ) {
            break;
        }

        ST_PLUGIN_QUEUE.decrement();
        StThread::sleep(10);
        if(myToQuit) {
            return;
        }
    }

    // Load image viewer
    myStApp = new StImageViewer(myResMgr, myParentWin, new StOpenInfo());

    if(!myStApp->open()) {
        ST_PLUGIN_QUEUE.decrement();
        myStApp.nullify();
        return;
    }

    ST_PLUGIN_QUEUE.decrement();

    bool isFileOpened = false;
    bool isFullscreen = false;
    bool isFullLoaded = false;
    myIsActive = true;
    for(;;) {
        if(myStApp->closingDown()) {
            myStApp.nullify();
            myIsActive = false;
            return;
        }

        myIsActive = myStApp->isActive();
        if(myToQuit) {
            myStApp->exit(0);
        } else if(!isFileOpened
                  && myIsActive) {
            // load the image
            StMutexAuto aLock(myMutex);
            if(myPreviewUrl.isEmpty()) {
                if(!myFullPath.isEmpty()) {
                    myOpenInfo.setPath(myFullPath);
                    aLock.unlock();
                    myStApp->open(myOpenInfo);
                    isFileOpened = true;
                }
            } else if(!myPreviewPath.isEmpty()) {
                myOpenInfo.setPath(myPreviewPath);
                aLock.unlock();
                myStApp->open(myOpenInfo);
                isFileOpened = true;
            }
        }

        StHandle<StWindow> aWin = myStApp->getMainWindow();
        if(myIsActive) {
            aWin->show();
        } else {
            aWin->hide();
        }
        myStApp->processEvents();

        if(aWin->isFullScreen()) {
            StMutexAuto aLock(myMutex);
            if(!isFullscreen && !myFullPath.isEmpty()) {
                myOpenInfo.setPath(myFullPath);
                aLock.unlock();
                myStApp->open(myOpenInfo);
                isFullscreen = true;
            } else if(!isFullLoaded && NPNFuncs.pluginthreadasynccall != NULL) {
                aLock.unlock();
                NPNFuncs.pluginthreadasynccall(nppInstance, StBrowserPlugin::doLoadFullSize, this);
                isFullLoaded = true;
            }
        } else if(isFullscreen) {
            StMutexAuto aLock(myMutex);
            if(!myPreviewPath.isEmpty()) {
                myOpenInfo.setPath(myPreviewPath);
                aLock.unlock();
                myStApp->open(myOpenInfo);
                isFullscreen = false;
            }
        }
    }
}
Example #27
0
StOutAnaglyph::StOutAnaglyph(const StNativeWin_t theParentWindow)
: StWindow(theParentWindow),
  mySettings(new StSettings(ST_OUT_PLUGIN_NAME)),
  myFrBuffer(new StGLStereoFrameBuffer()),
  myStereoProgram(NULL),
  mySimpleAnaglyph("Anaglyph Simple"),
  myGrayAnaglyph("Anaglyph Gray"),
  myTrueAnaglyph("Anaglyph True"),
  myOptimAnaglyph("Anaglyph Optimized"),
  myYellowAnaglyph("Anaglyph Yellow"),
  myYellowDubiosAnaglyph("Anaglyph Yellow Dubios"),
  myGreenAnaglyph("Anaglyph Green"),
  myToSavePlacement(theParentWindow == (StNativeWin_t )NULL),
  myToCompressMem(myInstancesNb.increment() > 1),
  myIsBroken(false) {
    StTranslations aLangMap(ST_OUT_PLUGIN_NAME);

    myStereoProgram = &mySimpleAnaglyph;

    // about string
    StString& aTitle     = aLangMap.changeValueId(STTR_PLUGIN_TITLE,   "sView - Anaglyph Output module");
    StString& aVerString = aLangMap.changeValueId(STTR_VERSION_STRING, "version");
    StString& aDescr     = aLangMap.changeValueId(STTR_PLUGIN_DESCRIPTION,
        "(C) 2007-2014 Kirill Gavrilov <*****@*****.**>\nOfficial site: www.sview.ru\n\nThis library distributed under LGPL3.0");
    myAbout = aTitle + '\n' + aVerString + ": " + StVersionInfo::getSDKVersionString() + "\n \n" + aDescr;

    // devices list
    StHandle<StOutDevice> aDevice = new StOutDevice();
    aDevice->PluginId = ST_OUT_PLUGIN_NAME;
    aDevice->DeviceId = "Anaglyph";
    aDevice->Priority = ST_DEVICE_SUPPORT_LOW; // anaglyph could be run on every display...
    aDevice->Name     = aLangMap.changeValueId(STTR_ANAGLYPH_NAME, "Anaglyph glasses");
    aDevice->Desc     = aLangMap.changeValueId(STTR_ANAGLYPH_DESC, "Simple glasses with color-filters");
    myDevices.add(aDevice);

    // Glasses switch option
    StHandle<StEnumParam> aGlasses = new StEnumParam(GLASSES_TYPE_REDCYAN,
                                                     aLangMap.changeValueId(STTR_ANAGLYPH_GLASSES, "Glasses type"));
    aGlasses->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_REDCYAN, "Red-cyan"));
    aGlasses->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_YELLOW,  "Yellow-Blue"));
    aGlasses->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_GREEN,   "Green-Magenta"));
    aGlasses->signals.onChanged.connect(this, &StOutAnaglyph::doSetShader);
    params.Glasses = aGlasses;

    // Red-cyan filter switch option
    StHandle<StEnumParam> aFilterRC = new StEnumParam(REDCYAN_MODE_SIMPLE,
                                                      aLangMap.changeValueId(STTR_ANAGLYPH_REDCYAN_MENU, "Red-Cyan filter"));
    aFilterRC->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_REDCYAN_SIMPLE, "Simple"));
    aFilterRC->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_REDCYAN_OPTIM,  "Optimized"));
    aFilterRC->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_REDCYAN_GRAY,   "Grayed"));
    aFilterRC->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_REDCYAN_DARK,   "Dark"));
    aFilterRC->signals.onChanged.connect(this, &StOutAnaglyph::doSetShader);
    params.RedCyan = aFilterRC;

    // Amber-Blue filter switch option
    StHandle<StEnumParam> aFilterAB = new StEnumParam(AMBERBLUE_MODE_SIMPLE,
                                                      aLangMap.changeValueId(STTR_ANAGLYPH_AMBERBLUE_MENU, "Yellow filter"));
    aFilterAB->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_AMBERBLUE_SIMPLE, "Simple"));
    aFilterAB->changeValues().add(aLangMap.changeValueId(STTR_ANAGLYPH_AMBERBLUE_DUBIOS, "Dubios"));
    aFilterAB->signals.onChanged.connect(this, &StOutAnaglyph::doSetShader);
    params.AmberBlue = aFilterAB;

    // load window position
    StRect<int32_t> aRect(256, 768, 256, 1024);
    mySettings->loadInt32Rect(ST_SETTING_WINDOWPOS, aRect);
    StWindow::setPlacement(aRect, true);
    StWindow::setTitle("sView - Anaglyph Renderer");

    // load glasses settings
    mySettings->loadParam(ST_SETTING_GLASSES,   params.Glasses);
    mySettings->loadParam(ST_SETTING_REDCYAN,   params.RedCyan);
    mySettings->loadParam(ST_SETTING_AMBERBLUE, params.AmberBlue);
}
Example #28
0
bool StApplication::open() {
    if(!myWindow.isNull()) {
        return true;
    }

    StSettings aGlobalSettings(myResMgr, "sview");
    if(!mySwitchTo.isNull()) {
        myRendId = mySwitchTo->getRendererId();
        myWindow = mySwitchTo;
        mySwitchTo.nullify();
        aGlobalSettings.saveString(ST_SETTING_RENDERER,      myRendId);
        aGlobalSettings.saveBool  (ST_SETTING_RENDERER_AUTO, false);
    } else {
        if(myRenderers.isEmpty()) {
            myWindow = new StWindow(myResMgr, myWinParent);
            myWindow->setMessagesQueue(myMsgQueue);
            myWindow->params.VSyncMode = params.VSyncMode;
        } else {
            bool isAuto = myRendId.isEqualsIgnoreCase(ST_SETTING_AUTO_VALUE);
            if(!isAuto) {
                for(size_t anIter = 0; anIter < myRenderers.size(); ++anIter) {
                    StHandle<StWindow> aWin = myRenderers[anIter];
                    if(myRendId == aWin->getRendererId()) {
                        myWindow = aWin;
                        aGlobalSettings.saveString(ST_SETTING_RENDERER,      myRendId);
                        aGlobalSettings.saveBool  (ST_SETTING_RENDERER_AUTO, isAuto);
                        break;
                    }
                }

                if(myWindow.isNull()) {
                    stError(StString("Output with id '" + myRendId + "' is not found."));
                    isAuto = true;
                }
            }

            if(isAuto) {
                // autodetection
                aGlobalSettings.saveString(ST_SETTING_RENDERER,      ST_SETTING_AUTO_VALUE);
                aGlobalSettings.saveBool  (ST_SETTING_RENDERER_AUTO, isAuto);
                myWindow = myRenderers[0];
                if(!myDevices.isEmpty()) {
                    StHandle<StOutDevice> aBestDev = myDevices[0];
                    for(size_t aDevIter = 0; aDevIter < myDevices.size(); ++aDevIter) {
                        const StHandle<StOutDevice>& aDev = myDevices[aDevIter];
                        if(aDev->Priority > aBestDev->Priority) {
                            aBestDev = aDev;
                        }
                    }
                    for(size_t anIter = 0; anIter < myRenderers.size(); ++anIter) {
                        const StHandle<StWindow>& aWin = myRenderers[anIter];
                        if(aBestDev->PluginId == aWin->getRendererId()) {
                            myWindow = aWin;
                            myWindow->setDevice(aBestDev->DeviceId);
                            break;
                        }
                    }
                }
            }
        }
        myWindow->setTitle(myTitle);
    }

    // synchronize devices enumeration
    const StString aPluginId = myWindow->getRendererId();
    const StString aDeviceId = myWindow->getDeviceId();
    for(size_t aDevIter = 0; aDevIter < myDevices.size(); ++aDevIter) {
        const StHandle<StOutDevice>& aDev = myDevices[aDevIter];
        if(aPluginId == aDev->PluginId
        && aDeviceId == aDev->DeviceId) {
            params.ActiveDevice->setValue((int32_t )aDevIter);
            break;
        }
    }

    // setup GL options before window creation
    const StWinAttr anAttribs[] = {
        StWinAttr_GlDebug, (StWinAttr )myGlDebug,
        StWinAttr_NULL
    };
    myWindow->setAttributes(anAttribs);

    myIsOpened = myWindow->create();
    if(myIsOpened) {
        // connect slots
        myWindow->signals.onRedraw    = stSlot(this, &StApplication::doDrawProxy);
        myWindow->signals.onClose     = stSlot(this, &StApplication::doClose);
        myWindow->signals.onPause     = stSlot(this, &StApplication::doPause);
        myWindow->signals.onResize    = stSlot(this, &StApplication::doResize);
        myWindow->signals.onAction    = stSlot(this, &StApplication::doAction);
        myWindow->signals.onKeyDown   = stSlot(this, &StApplication::doKeyDown);
        myWindow->signals.onKeyUp     = stSlot(this, &StApplication::doKeyUp);
        myWindow->signals.onKeyHold   = stSlot(this, &StApplication::doKeyHold);
        myWindow->signals.onMouseDown = stSlot(this, &StApplication::doMouseDown);
        myWindow->signals.onMouseUp   = stSlot(this, &StApplication::doMouseUp);
        myWindow->signals.onTouch     = stSlot(this, &StApplication::doTouch);
        myWindow->signals.onGesture   = stSlot(this, &StApplication::doGesture);
        myWindow->signals.onScroll    = stSlot(this, &StApplication::doScroll);
        myWindow->signals.onFileDrop  = stSlot(this, &StApplication::doFileDrop);
        myWindow->signals.onNavigate  = stSlot(this, &StApplication::doNavigate);
    }

    return myIsOpened;
}
Example #29
0
StHandle<StOpenInfo> StApplication::parseProcessArguments() {
    StHandle<StOpenInfo> anInfo = new StOpenInfo();

    StArrayList<StString> anArguments = StProcess::getArguments();
    StArgumentsMap anOpenFileArgs;
    size_t aFilesCount = 0;
    bool isFilesSection = false;
    const StString ARGUMENT_FILES_SECTION     = '-';
    const StString ARGUMENT_ANY               = "--";
    const StString ARGUMENT_HELP              = "help";
    const StString ARGUMENT_FILE              = "file";
    const StString ARGUMENT_LEFT_VIEW         = "left";
    const StString ARGUMENT_RIGHT_VIEW        = "right";
    // parse extra parameters
    for(size_t aParamIter = 1; aParamIter < anArguments.size(); ++aParamIter) {
        StString aParam = anArguments[aParamIter];
        ///ST_DEBUG_LOG("aParam= '" + aParam + "'");
        if(isFilesSection) {
            // file name
            StString aFilePath = StProcess::getAbsolutePath(aParam);
            anOpenFileArgs.add(StArgument(ARGUMENT_FILE + aFilesCount++, aFilePath));
            if(!anInfo->hasPath()) {
                // first file determines MIME type (needed to autoselect Drawer plugin)
                anInfo->setPath(aFilePath);
            }
        } else if(aParam == ARGUMENT_FILES_SECTION) {
            isFilesSection = true;
        } else if(aParam.isStartsWith(ARGUMENT_ANY)) {
            // argument
            StArgument anArg; anArg.parseString(aParam.subString(2, aParam.getLength())); // cut suffix --

            if(anArg.getKey().isEqualsIgnoreCase(ARGUMENT_HELP)) {
                return NULL;
            } else if(anArg.getKey().isEqualsIgnoreCase(ARGUMENT_LEFT_VIEW)) {
                // left view
                anArg.setValue(StProcess::getAbsolutePath(anArg.getValue()));
                anOpenFileArgs.add(anArg);
                anInfo->setPath(anArg.getValue()); // left file always determines MIME type
            } else if(anArg.getKey().isEqualsIgnoreCase(ARGUMENT_RIGHT_VIEW)) {
                // right view
                anArg.setValue(StProcess::getAbsolutePath(anArg.getValue()));
                anOpenFileArgs.add(anArg);
                if(!anInfo->hasPath()) {
                    anInfo->setPath(anArg.getValue());
                }
            } else {
                // pass argument unchanged
                anOpenFileArgs.add(anArg);
            }
        } else {
            // file name
            StString aFilePath = StProcess::getAbsolutePath(aParam);
            anOpenFileArgs.add(StArgument(ARGUMENT_FILE + aFilesCount++, aFilePath));
            if(!anInfo->hasPath()) {
                // first file determines MIME type (needed to autoselect Drawer plugin)
                anInfo->setPath(aFilePath);
            }
        }
    }

    anInfo->setArgumentsMap(anOpenFileArgs);
    return anInfo;
}
Example #30
0
void StPlayList::open(const StCString& thePath,
                      const StCString& theItem) {
    StMutexAuto anAutoLock(myMutex);

    // check if it is recently played playlist
    bool hasTarget = !theItem.isEmpty();
    StString aTarget = hasTarget ? theItem : thePath;
    if(!hasTarget) {
        for(size_t anIter = 0; anIter < myRecent.size(); ++anIter) {
            const StHandle<StRecentItem>& aRecent = myRecent[anIter];
            const StHandle<StFileNode>&   aFile   = aRecent->File;
            if(aFile->size() != 1) {
                continue;
            }

            if(thePath.isEquals(aFile->getPath())) {
                hasTarget = true;
                aTarget = aFile->getValue(0)->getSubPath();
                break;
            }
        }
    }

    clear();
    int aSearchDeep = myRecursionDeep;
    StString aFolderPath;
    StString aFileName;
    if(StFolder::isFolder(thePath)) {
        // add all files from the folder and subfolders
        aFolderPath = thePath;
        aSearchDeep = myRecursionDeep;
        myPlsFile   = addRecentFile(StFileNode(thePath)); // append to recent files list
    } else if(StFileNode::isFileExists(thePath)) {
        // search only current folder
        StFileNode::getFolderAndFile(thePath, aFolderPath, aFileName);
        aSearchDeep = 1;
        bool hasSupportedExt = false;
        StString anExt = StFileNode::getExtension(aFileName);
        for(size_t anExtId = 0; anExtId < myExtensions.size() && !hasSupportedExt; ++anExtId) {
            hasSupportedExt = anExt.isEqualsIgnoreCase(myExtensions[anExtId]);
        }

        // parse m3u playlist
        if(anExt.isEqualsIgnoreCase(stCString("m3u"))
        || anExt.isEqualsIgnoreCase(stCString("m3u8"))) {
            StHandle<StRawFile> aRawFile = new StRawFile(thePath);
            if(aRawFile->readFile()) {
                StFolder* aPlsFolder = new StFolder(aFolderPath, &myFoldersRoot);
                myFoldersRoot.add(aPlsFolder);

                StString aTitle;
                for(char* anIter = skipBOM((char* )aRawFile->getBuffer()); anIter != NULL;) {
                    anIter = parseM3UIter(anIter, aPlsFolder, aTitle);
                }
                aRawFile.nullify();

                if(myFirst != nullptr
                && myFirst->getNext() == nullptr) {
                    const StString aFirstPath = myFirst->getPath();
                    StString anItemExt = StFileNode::getExtension(aFirstPath);
                    if(anItemExt.isEqualsIgnoreCase(stCString("m3u"))
                    || anItemExt.isEqualsIgnoreCase(stCString("m3u8"))) {
                        aRawFile = new StRawFile(aFirstPath);
                        if(aRawFile->readFile()) {
                            for(char* anIter = skipBOM((char* )aRawFile->getBuffer()); anIter != NULL;) {
                                anIter = parseM3UIter(anIter, NULL, aTitle);
                            }
                            remove(aFirstPath, false);
                        }
                        aRawFile.nullify();
                    }
                }

                myPlsFile = addRecentFile(StFileNode(thePath)); // append to recent files list
                if(hasTarget) {
                    // set current item
                    for(StPlayItem* anItem = myFirst; anItem != NULL; anItem = anItem->getNext()) {
                        if(anItem->getPath() == aTarget) {
                            myCurrent = anItem;
                            break;
                        }
                    }
                }

                anAutoLock.unlock();
                signals.onPlaylistChange();
                return;
            }
        }

        if(!hasSupportedExt) {
            // file with unsupported extension?
            StFileNode* aFileNode = new StFileNode(thePath, &myFoldersRoot);
            myFoldersRoot.add(aFileNode);
            addPlayItem(new StPlayItem(aFileNode, myDefStParams));
        }
    } else {
        // not a filesystem element - probably url or invalid path
        StFileNode* aFileNode = new StFileNode(thePath, &myFoldersRoot);
        myFoldersRoot.add(aFileNode);
        addRecentFile(*aFileNode); // append to recent files list
        addPlayItem(new StPlayItem(aFileNode, myDefStParams));

        anAutoLock.unlock();
        signals.onPlaylistChange();
        return;
    }
    StFolder* aSubFolder = new StFolder(aFolderPath, &myFoldersRoot);
    aSubFolder->init(myExtensions, aSearchDeep);
    myFoldersRoot.add(aSubFolder);

    addToPlayList(aSubFolder);

    myCurrent = myFirst;
    if(hasTarget || !aFileName.isEmpty()) {
        // set current item
        for(StPlayItem* anItem = myFirst; anItem != NULL; anItem = anItem->getNext()) {
            if(anItem->getPath() == aTarget) {
                myCurrent = anItem;
                if(myPlsFile.isNull()) {
                    addRecentFile(*anItem->getFileNode()); // append to recent files list
                }
                break;
            }
        }
    }

    anAutoLock.unlock();
    signals.onPlaylistChange();
}