JOOMLA中国
  • Joomla中国首页
  • 社区
  • 教程
  • 应用市场
  • B计划
Joomla! Framework TM
  • Namespace
  • Class
  • Tree
  • Deprecated

Namespaces

  • Composer
    • Autoload
  • Joomla
    • Application
      • Cli
        • Output
          • Processor
      • Web
    • Data
    • DI
      • Exception
    • Event
    • Filter
    • Input
    • Ldap
    • Registry
      • Format
    • Session
      • Storage
    • String
    • Uri
    • Utilities
  • None
  • PasswordCompat
    • binary
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Yaml
        • Exception
    • Polyfill
      • Util

Classes

  • CallbackFilterIterator
  • ComposerAutoloaderInit205c915b9c7d3e718e7c95793ee67ffe
  • easyparse
  • EasyPeasyICS
  • FOFAutoloaderComponent
  • FOFAutoloaderFof
  • FOFConfigDomainDispatcher
  • FOFConfigDomainTables
  • FOFConfigDomainViews
  • FOFConfigProvider
  • FOFController
  • FOFDatabase
  • FOFDatabaseDriver
  • FOFDatabaseDriverJoomla
  • FOFDatabaseDriverMysql
  • FOFDatabaseDriverMysqli
  • FOFDatabaseDriverOracle
  • FOFDatabaseDriverPdo
  • FOFDatabaseDriverPdomysql
  • FOFDatabaseDriverPostgresql
  • FOFDatabaseDriverSqlazure
  • FOFDatabaseDriverSqlite
  • FOFDatabaseDriverSqlsrv
  • FOFDatabaseFactory
  • FOFDatabaseInstaller
  • FOFDatabaseIterator
  • FOFDatabaseIteratorAzure
  • FOFDatabaseIteratorMysql
  • FOFDatabaseIteratorMysqli
  • FOFDatabaseIteratorOracle
  • FOFDatabaseIteratorPdo
  • FOFDatabaseIteratorPdomysql
  • FOFDatabaseIteratorPostgresql
  • FOFDatabaseIteratorSqlite
  • FOFDatabaseIteratorSqlsrv
  • FOFDatabaseQuery
  • FOFDatabaseQueryElement
  • FOFDatabaseQueryMysql
  • FOFDatabaseQueryMysqli
  • FOFDatabaseQueryOracle
  • FOFDatabaseQueryPdo
  • FOFDatabaseQueryPdomysql
  • FOFDatabaseQueryPostgresql
  • FOFDatabaseQuerySqlazure
  • FOFDatabaseQuerySqlite
  • FOFDatabaseQuerySqlsrv
  • FOFDispatcher
  • FOFDownload
  • FOFDownloadAdapterAbstract
  • FOFDownloadAdapterCurl
  • FOFDownloadAdapterFopen
  • FOFEncryptAes
  • FOFEncryptAesAbstract
  • FOFEncryptAesMcrypt
  • FOFEncryptAesOpenssl
  • FOFEncryptBase32
  • FOFEncryptRandval
  • FOFEncryptTotp
  • FOFForm
  • FOFFormFieldAccesslevel
  • FOFFormFieldActions
  • FOFFormFieldButton
  • FOFFormFieldCachehandler
  • FOFFormFieldCalendar
  • FOFFormFieldCaptcha
  • FOFFormFieldCheckbox
  • FOFFormFieldCheckboxes
  • FOFFormFieldComponents
  • FOFFormFieldEditor
  • FOFFormFieldEmail
  • FOFFormFieldGroupedbutton
  • FOFFormFieldGroupedlist
  • FOFFormFieldHidden
  • FOFFormFieldImage
  • FOFFormFieldImagelist
  • FOFFormFieldInteger
  • FOFFormFieldLanguage
  • FOFFormFieldList
  • FOFFormFieldMedia
  • FOFFormFieldModel
  • FOFFormFieldOrdering
  • FOFFormFieldPassword
  • FOFFormFieldPlugins
  • FOFFormFieldPublished
  • FOFFormFieldRadio
  • FOFFormFieldRelation
  • FOFFormFieldRules
  • FOFFormFieldSelectrow
  • FOFFormFieldSessionhandler
  • FOFFormFieldSpacer
  • FOFFormFieldSql
  • FOFFormFieldTag
  • FOFFormFieldTel
  • FOFFormFieldText
  • FOFFormFieldTextarea
  • FOFFormFieldTimezone
  • FOFFormFieldTitle
  • FOFFormFieldUrl
  • FOFFormFieldUser
  • FOFFormFieldUsergroup
  • FOFFormHeader
  • FOFFormHeaderAccesslevel
  • FOFFormHeaderField
  • FOFFormHeaderFielddate
  • FOFFormHeaderFieldfilterable
  • FOFFormHeaderFieldsearchable
  • FOFFormHeaderFieldselectable
  • FOFFormHeaderFieldsql
  • FOFFormHeaderFilterdate
  • FOFFormHeaderFilterfilterable
  • FOFFormHeaderFiltersearchable
  • FOFFormHeaderFilterselectable
  • FOFFormHeaderFiltersql
  • FOFFormHeaderLanguage
  • FOFFormHeaderModel
  • FOFFormHeaderOrdering
  • FOFFormHeaderPublished
  • FOFFormHeaderRowselect
  • FOFFormHelper
  • FOFHalDocument
  • FOFHalLink
  • FOFHalLinks
  • FOFHalRenderJson
  • FOFInflector
  • FOFInput
  • FOFIntegrationJoomlaFilesystem
  • FOFIntegrationJoomlaPlatform
  • FOFLayoutFile
  • FOFLayoutHelper
  • FOFLess
  • FOFLessFormatterClassic
  • FOFLessFormatterCompressed
  • FOFLessFormatterJoomla
  • FOFLessFormatterLessjs
  • FOFLessParser
  • FOFModel
  • FOFModelBehavior
  • FOFModelBehaviorAccess
  • FOFModelBehaviorEmptynonzero
  • FOFModelBehaviorEnabled
  • FOFModelBehaviorFilters
  • FOFModelBehaviorLanguage
  • FOFModelBehaviorPrivate
  • FOFModelDispatcherBehavior
  • FOFModelField
  • FOFModelFieldBoolean
  • FOFModelFieldDate
  • FOFModelFieldNumber
  • FOFModelFieldText
  • FOFPlatform
  • FOFPlatformFilesystem
  • FOFQueryAbstract
  • FOFRenderAbstract
  • FOFRenderJoomla
  • FOFRenderJoomla3
  • FOFRenderStrapper
  • FOFStringUtils
  • FOFTable
  • FOFTableBehavior
  • FOFTableBehaviorAssets
  • FOFTableBehaviorContenthistory
  • FOFTableBehaviorTags
  • FOFTableDispatcherBehavior
  • FOFTableNested
  • FOFTableRelations
  • FOFTemplateUtils
  • FOFToolbar
  • FOFUtilsArray
  • FOFUtilsCacheCleaner
  • FOFUtilsConfigHelper
  • FOFUtilsFilescheck
  • FOFUtilsIniParser
  • FOFUtilsInstallscript
  • FOFUtilsIp
  • FOFUtilsObject
  • FOFUtilsObservableDispatcher
  • FOFUtilsObservableEvent
  • FOFUtilsPhpfunc
  • FOFUtilsTimer
  • FOFUtilsUpdate
  • FOFUtilsUpdateCollection
  • FOFUtilsUpdateExtension
  • FOFUtilsUpdateJoomla
  • FOFView
  • FOFViewCsv
  • FOFViewForm
  • FOFViewHtml
  • FOFViewJson
  • FOFViewRaw
  • idna_convert
  • JAccess
  • JAccessRule
  • JAccessRules
  • JAccessWrapperAccess
  • JAdapter
  • JAdapterInstance
  • JApplication
  • JApplicationAdministrator
  • JApplicationBase
  • JApplicationCli
  • JApplicationCms
  • JApplicationDaemon
  • JApplicationHelper
  • JApplicationSite
  • JApplicationWeb
  • JApplicationWebRouter
  • JApplicationWebRouterBase
  • JApplicationWebRouterRest
  • JArchive
  • JArchiveBzip2
  • JArchiveGzip
  • JArchiveTar
  • JArchiveWrapperArchive
  • JArchiveZip
  • JArrayHelper
  • JAssociationExtensionHelper
  • JAuthentication
  • JAuthenticationHelper
  • JAuthenticationResponse
  • JBrowser
  • JBuffer
  • JButton
  • JCache
  • JCacheController
  • JCacheControllerCallback
  • JCacheControllerOutput
  • JCacheControllerPage
  • JCacheControllerView
  • JCacheStorage
  • JCacheStorageApc
  • JCacheStorageApcu
  • JCacheStorageCachelite
  • JCacheStorageFile
  • JCacheStorageHelper
  • JCacheStorageMemcache
  • JCacheStorageMemcached
  • JCacheStorageRedis
  • JCacheStorageWincache
  • JCacheStorageXcache
  • JCaptcha
  • JCategories
  • JCategoryNode
  • JClassLoader
  • JCli
  • JClientFtp
  • JClientHelper
  • JClientLdap
  • JClientWrapperHelper
  • JComponentHelper
  • JComponentRecord
  • JComponentRouterBase
  • JComponentRouterLegacy
  • JComponentRouterRulesMenu
  • JComponentRouterRulesNomenu
  • JComponentRouterRulesStandard
  • JComponentRouterView
  • JComponentRouterViewconfiguration
  • JControllerAdmin
  • JControllerBase
  • JControllerForm
  • JControllerLegacy
  • JCrypt
  • JCryptCipher3Des
  • JCryptCipherBlowfish
  • JCryptCipherCrypto
  • JCryptCipherMcrypt
  • JCryptCipherRijndael256
  • JCryptCipherSimple
  • JCryptKey
  • JCryptPasswordSimple
  • JDaemon
  • JDatabase
  • JDatabaseDriver
  • JDatabaseDriverMysql
  • JDatabaseDriverMysqli
  • JDatabaseDriverOracle
  • JDatabaseDriverPdo
  • JDatabaseDriverPdomysql
  • JDatabaseDriverPostgresql
  • JDatabaseDriverSqlazure
  • JDatabaseDriverSqlite
  • JDatabaseDriverSqlsrv
  • JDatabaseExporter
  • JDatabaseExporterMysql
  • JDatabaseExporterMysqli
  • JDatabaseExporterPdomysql
  • JDatabaseExporterPostgresql
  • JDatabaseFactory
  • JDatabaseImporter
  • JDatabaseImporterMysql
  • JDatabaseImporterMysqli
  • JDatabaseImporterPdomysql
  • JDatabaseImporterPostgresql
  • JDatabaseInterface
  • JDatabaseIterator
  • JDatabaseIteratorMysql
  • JDatabaseIteratorMysqli
  • JDatabaseIteratorOracle
  • JDatabaseIteratorPdo
  • JDatabaseIteratorPdomysql
  • JDatabaseIteratorPostgresql
  • JDatabaseIteratorSqlazure
  • JDatabaseIteratorSqlite
  • JDatabaseIteratorSqlsrv
  • JDatabaseMysql
  • JDatabaseMysqli
  • JDatabaseQuery
  • JDatabaseQueryElement
  • JDatabaseQueryLimitable
  • JDatabaseQueryMysql
  • JDatabaseQueryMysqli
  • JDatabaseQueryOracle
  • JDatabaseQueryPdo
  • JDatabaseQueryPdomysql
  • JDatabaseQueryPostgresql
  • JDatabaseQueryPreparable
  • JDatabaseQuerySqlazure
  • JDatabaseQuerySqlite
  • JDatabaseQuerySqlsrv
  • JDatabaseSqlazure
  • JDatabaseSqlsrv
  • JDate
  • JDispatcher
  • JDocument
  • JDocumentError
  • JDocumentFeed
  • JDocumentHtml
  • JDocumentImage
  • JDocumentJson
  • JDocumentOpensearch
  • JDocumentRaw
  • JDocumentRenderer
  • JDocumentRendererAtom
  • JDocumentRendererComponent
  • JDocumentRendererFeedAtom
  • JDocumentRendererFeedRss
  • JDocumentRendererHead
  • JDocumentRendererHtmlComponent
  • JDocumentRendererHtmlHead
  • JDocumentRendererHtmlMessage
  • JDocumentRendererHtmlModule
  • JDocumentRendererHtmlModules
  • JDocumentRendererMessage
  • JDocumentRendererModule
  • JDocumentRendererModules
  • JDocumentRendererRSS
  • JDocumentXml
  • JEditor
  • JError
  • JErrorPage
  • JEvent
  • JEventDispatcher
  • JExtension
  • JFacebook
  • JFacebookAlbum
  • JFacebookCheckin
  • JFacebookComment
  • JFacebookEvent
  • JFacebookGroup
  • JFacebookLink
  • JFacebookNote
  • JFacebookOAuth
  • JFacebookObject
  • JFacebookPhoto
  • JFacebookPost
  • JFacebookStatus
  • JFacebookUser
  • JFacebookVideo
  • JFactory
  • JFeed
  • JFeedEnclosure
  • JFeedEntry
  • JFeedFactory
  • JFeedImage
  • JFeedItem
  • JFeedLink
  • JFeedParser
  • JFeedParserAtom
  • JFeedParserRss
  • JFeedParserRssItunes
  • JFeedParserRssMedia
  • JFeedPerson
  • JFile
  • JFilesystemHelper
  • JFilesystemPatcher
  • JFilesystemWrapperFile
  • JFilesystemWrapperFolder
  • JFilesystemWrapperPath
  • JFilterInput
  • JFilterOutput
  • JFilterWrapperOutput
  • JFolder
  • JForm
  • JFormField
  • JFormFieldAccessLevel
  • JFormFieldAliastag
  • JFormFieldAuthor
  • JFormFieldCacheHandler
  • JFormFieldCalendar
  • JFormFieldCaptcha
  • JFormFieldCategory
  • JFormFieldCheckbox
  • JFormFieldCheckboxes
  • JFormFieldChromeStyle
  • JFormFieldColor
  • JFormFieldCombo
  • JFormFieldComponentlayout
  • JFormFieldComponents
  • JFormFieldContenthistory
  • JFormFieldContentlanguage
  • JFormFieldContenttype
  • JFormFieldDatabaseConnection
  • JFormFieldEditor
  • JFormFieldEMail
  • JFormFieldFile
  • JFormFieldFileList
  • JFormFieldFolderList
  • JFormFieldFrontend_Language
  • JFormFieldGroupedList
  • JFormFieldHeadertag
  • JFormFieldHelpsite
  • JFormFieldHidden
  • JFormFieldImageList
  • JFormFieldInteger
  • JFormFieldLanguage
  • JFormFieldLastvisitDateRange
  • JFormFieldLimitbox
  • JFormFieldList
  • JFormFieldMedia
  • JFormFieldMenu
  • JFormFieldMenuitem
  • JFormFieldMeter
  • JFormFieldModulelayout
  • JFormFieldModuleOrder
  • JFormFieldModulePosition
  • JFormFieldModuletag
  • JFormFieldNote
  • JFormFieldNumber
  • JFormFieldOrdering
  • JFormFieldPassword
  • JFormFieldPlugin_Status
  • JFormFieldPlugins
  • JFormFieldPredefinedList
  • JFormFieldRadio
  • JFormFieldRange
  • JFormFieldRegistrationDateRange
  • JFormFieldRepeatable
  • JFormFieldRules
  • JFormFieldSessionHandler
  • JFormFieldSpacer
  • JFormFieldSQL
  • JFormFieldStatus
  • JFormFieldSubform
  • JFormFieldTag
  • JFormFieldTel
  • JFormFieldTemplatestyle
  • JFormFieldText
  • JFormFieldTextarea
  • JFormFieldTimezone
  • JFormFieldUrl
  • JFormFieldUser
  • JFormFieldUserActive
  • JFormFieldUsergroup
  • JFormFieldUserGroupList
  • JFormFieldUserState
  • JFormHelper
  • JFormRule
  • JFormRuleBoolean
  • JFormRuleCalendar
  • JFormRuleCaptcha
  • JFormRuleColor
  • JFormRuleEmail
  • JFormRuleEquals
  • JFormRuleNotequals
  • JFormRuleNumber
  • JFormRuleOptions
  • JFormRulePassword
  • JFormRuleRules
  • JFormRuleTel
  • JFormRuleUrl
  • JFormRuleUsername
  • JFormWrapperHelper
  • JFTP
  • JGithub
  • JGithubAccount
  • JGithubCommits
  • JGithubForks
  • JGithubHooks
  • JGithubHttp
  • JGithubMeta
  • JGithubMilestones
  • JGithubObject
  • JGithubPackage
  • JGithubPackageActivity
  • JGithubPackageActivityEvents
  • JGithubPackageActivityNotifications
  • JGithubPackageActivityStarring
  • JGithubPackageActivityWatching
  • JGithubPackageAuthorization
  • JGithubPackageData
  • JGithubPackageDataBlobs
  • JGithubPackageDataCommits
  • JGithubPackageDataRefs
  • JGithubPackageDataTags
  • JGithubPackageDataTrees
  • JGithubPackageGists
  • JGithubPackageGistsComments
  • JGithubPackageGitignore
  • JGithubPackageIssues
  • JGithubPackageIssuesAssignees
  • JGithubPackageIssuesComments
  • JGithubPackageIssuesEvents
  • JGithubPackageIssuesLabels
  • JGithubPackageIssuesMilestones
  • JGithubPackageMarkdown
  • JGithubPackageOrgs
  • JGithubPackageOrgsMembers
  • JGithubPackageOrgsTeams
  • JGithubPackagePulls
  • JGithubPackagePullsComments
  • JGithubPackageRepositories
  • JGithubPackageRepositoriesCollaborators
  • JGithubPackageRepositoriesComments
  • JGithubPackageRepositoriesCommits
  • JGithubPackageRepositoriesContents
  • JGithubPackageRepositoriesDownloads
  • JGithubPackageRepositoriesForks
  • JGithubPackageRepositoriesHooks
  • JGithubPackageRepositoriesKeys
  • JGithubPackageRepositoriesMerging
  • JGithubPackageRepositoriesStatistics
  • JGithubPackageRepositoriesStatuses
  • JGithubPackageSearch
  • JGithubPackageUsers
  • JGithubPackageUsersEmails
  • JGithubPackageUsersFollowers
  • JGithubPackageUsersKeys
  • JGithubRefs
  • JGithubStatuses
  • JGoogle
  • JGoogleAuth
  • JGoogleAuthOauth2
  • JGoogleData
  • JGoogleDataAdsense
  • JGoogleDataCalendar
  • JGoogleDataPicasa
  • JGoogleDataPicasaAlbum
  • JGoogleDataPicasaPhoto
  • JGoogleDataPlus
  • JGoogleDataPlusActivities
  • JGoogleDataPlusComments
  • JGoogleDataPlusPeople
  • JGoogleEmbed
  • JGoogleEmbedAnalytics
  • JGoogleEmbedMaps
  • JGrid
  • JHelp
  • JHelper
  • JHelperContent
  • JHelperContenthistory
  • JHelperMedia
  • JHelperRoute
  • JHelperTags
  • JHelperUsergroups
  • JHtml
  • JHtmlAccess
  • JHtmlActionsDropdown
  • JHtmlBatch
  • JHtmlBehavior
  • JHtmlBootstrap
  • JHtmlCategory
  • JHtmlContent
  • JHtmlContentLanguage
  • JHtmlDate
  • JHtmlDebug
  • JHtmlDropdown
  • JHtmlEmail
  • JHtmlForm
  • JHtmlFormbehavior
  • JHtmlGrid
  • JHtmlIcons
  • JHtmlJGrid
  • JHtmlJquery
  • JHtmlLinks
  • JHtmlList
  • JHtmlMenu
  • JHtmlNumber
  • JHtmlRules
  • JHtmlSearchtools
  • JHtmlSelect
  • JHtmlSidebar
  • JHtmlSliders
  • JHtmlSortablelist
  • JHtmlString
  • JHtmlTabs
  • JHtmlTag
  • JHtmlTel
  • JHtmlUser
  • JHttp
  • JHttpFactory
  • JHttpResponse
  • JHttpTransportCurl
  • JHttpTransportSocket
  • JHttpTransportStream
  • JHttpWrapperFactory
  • JImage
  • JImageFilter
  • JImageFilterBackgroundfill
  • JImageFilterBrightness
  • JImageFilterContrast
  • JImageFilterEdgedetect
  • JImageFilterEmboss
  • JImageFilterGrayscale
  • JImageFilterNegate
  • JImageFilterSketchy
  • JImageFilterSmooth
  • JInput
  • JInputCli
  • JInputCookie
  • JInputFiles
  • JInputJSON
  • JInstaller
  • JInstallerAdapter
  • JInstallerAdapterComponent
  • JInstallerAdapterFile
  • JInstallerAdapterLanguage
  • JInstallerAdapterLibrary
  • JInstallerAdapterModule
  • JInstallerAdapterPackage
  • JInstallerAdapterPlugin
  • JInstallerAdapterTemplate
  • JInstallerComponent
  • JInstallerExtension
  • JInstallerFile
  • JInstallerHelper
  • JInstallerLanguage
  • JInstallerLibrary
  • JInstallerManifest
  • JInstallerManifestLibrary
  • JInstallerManifestPackage
  • JInstallerModule
  • JInstallerPackage
  • JInstallerPlugin
  • JInstallerScript
  • JInstallerTemplate
  • JKeychain
  • JLanguage
  • JLanguageAssociations
  • JLanguageHelper
  • JLanguageMultilang
  • JLanguageStemmer
  • JLanguageStemmerPorteren
  • JLanguageTransliterate
  • JLanguageWrapperHelper
  • JLanguageWrapperText
  • JLanguageWrapperTransliterate
  • JLayoutBase
  • JLayoutFile
  • JLayoutHelper
  • JLDAP
  • JLess
  • JLessFormatterJoomla
  • JLibraryHelper
  • JLinkedin
  • JLinkedinCommunications
  • JLinkedinCompanies
  • JLinkedinGroups
  • JLinkedinJobs
  • JLinkedinOauth
  • JLinkedinObject
  • JLinkedinPeople
  • JLinkedinStream
  • JLoader
  • JLog
  • JLogEntry
  • JLogger
  • JLogLogger
  • JLogLoggerCallback
  • JLogLoggerDatabase
  • JLogLoggerEcho
  • JLogLoggerFormattedtext
  • JLogLoggerMessagequeue
  • JLogLoggerSyslog
  • JLogLoggerW3c
  • JMail
  • JMailHelper
  • JMailWrapperHelper
  • JMediawiki
  • JMediawikiCategories
  • JMediawikiHttp
  • JMediawikiImages
  • JMediawikiLinks
  • JMediawikiObject
  • JMediawikiPages
  • JMediawikiSearch
  • JMediawikiSites
  • JMediawikiUsers
  • JMenu
  • JMenuAdministrator
  • JMenuItem
  • JMenuSite
  • JMicrodata
  • JModelAdmin
  • JModelBase
  • JModelDatabase
  • JModelForm
  • JModelItem
  • JModelLegacy
  • JModelList
  • JModuleHelper
  • JNode
  • JOAuth1Client
  • JOAuth2Client
  • JObject
  • JObservable
  • JObserver
  • JObserverMapper
  • JObserverUpdater
  • JObserverWrapperMapper
  • JOpenSearchImage
  • JOpenSearchUrl
  • JOpenstreetmap
  • JOpenstreetmapChangesets
  • JOpenstreetmapElements
  • JOpenstreetmapGps
  • JOpenstreetmapInfo
  • JOpenstreetmapOauth
  • JOpenstreetmapObject
  • JOpenstreetmapUser
  • JPagination
  • JPaginationObject
  • JPath
  • JPathway
  • JPathwaySite
  • JPlatform
  • JPlugin
  • JPluginHelper
  • JProfiler
  • JRequest
  • JResponse
  • JResponseJson
  • JRoute
  • JRouter
  • JRouterAdministrator
  • JRouterSite
  • JRouteWrapperRoute
  • JRule
  • JRules
  • JSchemaChangeitem
  • JSchemaChangeitemMysql
  • JSchemaChangeitemPostgresql
  • JSchemaChangeitemSqlsrv
  • JSchemaChangeset
  • JSearchHelper
  • JSession
  • JSessionHandlerJoomla
  • JSessionHandlerNative
  • JSessionStorage
  • JSessionStorageApc
  • JSessionStorageDatabase
  • JSessionStorageMemcache
  • JSessionStorageMemcached
  • JSessionStorageNone
  • JSessionStorageWincache
  • JSessionStorageXcache
  • JSimplecrypt
  • JSimplepieFactory
  • JStream
  • JStreamString
  • JString
  • JStringController
  • JStringPunycode
  • JStringWrapperNormalise
  • JStringWrapperPunycode
  • JTable
  • JTableAsset
  • JTableCategory
  • JTableContent
  • JTableContenthistory
  • JTableContenttype
  • JTableCorecontent
  • JTableExtension
  • JTableInterface
  • JTableLanguage
  • JTableMenu
  • JTableMenuType
  • JTableModule
  • JTableNested
  • JTableObserver
  • JTableObserverContenthistory
  • JTableObserverTags
  • JTableSession
  • JTableUcm
  • JTableUpdate
  • JTableUpdatesite
  • JTableUser
  • JTableUsergroup
  • JTableViewlevel
  • JText
  • JToolbar
  • JToolbarButton
  • JToolbarButtonConfirm
  • JToolbarButtonCustom
  • JToolbarButtonHelp
  • JToolbarButtonLink
  • JToolbarButtonPopup
  • JToolbarButtonSeparator
  • JToolbarButtonSlider
  • JToolbarButtonStandard
  • JTree
  • JTwitter
  • JTwitterBlock
  • JTwitterDirectmessages
  • JTwitterFavorites
  • JTwitterFriends
  • JTwitterHelp
  • JTwitterLists
  • JTwitterOAuth
  • JTwitterObject
  • JTwitterPlaces
  • JTwitterProfile
  • JTwittersearch
  • JTwitterStatuses
  • JTwitterTrends
  • JTwitterUsers
  • JUcmBase
  • JUcmContent
  • JUcmType
  • JUpdate
  • JUpdateAdapter
  • JUpdater
  • JUpdaterCollection
  • JUpdaterExtension
  • JUri
  • JUser
  • JUserHelper
  • JUserWrapperHelper
  • JUtility
  • JVersion
  • JViewBase
  • JViewCategories
  • JViewCategory
  • JViewCategoryfeed
  • JViewHtml
  • JViewLegacy
  • JWeb
  • JWebClient
  • JXMLElement
  • lessc
  • lessc_formatter_classic
  • lessc_formatter_compressed
  • lessc_formatter_lessjs
  • lessc_parser
  • lessify
  • Net_IDNA_php4
  • nodecounter
  • ntlm_sasl_client_class
  • PHPMailer
  • PHPMailerOAuth
  • PHPMailerOAuthGoogle
  • POP3
  • SimplePie
  • SimplePie_Author
  • SimplePie_Autoloader
  • SimplePie_Cache
  • SimplePie_Cache_DB
  • SimplePie_Cache_File
  • SimplePie_Cache_Memcache
  • SimplePie_Cache_MySQL
  • SimplePie_Caption
  • SimplePie_Category
  • SimplePie_Content_Type_Sniffer
  • SimplePie_Copyright
  • SimplePie_Core
  • SimplePie_Credit
  • SimplePie_Decode_HTML_Entities
  • SimplePie_Enclosure
  • SimplePie_File
  • SimplePie_gzdecode
  • SimplePie_HTTP_Parser
  • SimplePie_IRI
  • SimplePie_Item
  • SimplePie_Locator
  • SimplePie_Misc
  • SimplePie_Net_IPv6
  • SimplePie_Parse_Date
  • SimplePie_Parser
  • SimplePie_Rating
  • SimplePie_Registry
  • SimplePie_Restriction
  • SimplePie_Sanitize
  • SimplePie_Source
  • SimplePie_XML_Declaration_Parser
  • SMTP
  • tagparse
  • TypeError

Interfaces

  • FOFConfigDomainInterface
  • FOFDatabaseInterface
  • FOFDatabaseQueryLimitable
  • FOFDatabaseQueryPreparable
  • FOFDownloadInterface
  • FOFEncryptAesInterface
  • FOFEncryptRandvalinterface
  • FOFFormField
  • FOFHalRenderInterface
  • FOFPlatformFilesystemInterface
  • FOFPlatformInterface
  • JArchiveExtractable
  • JAssociationExtensionInterface
  • JCacheException
  • JComponentRouterInterface
  • JComponentRouterRulesInterface
  • JController
  • JCryptCipher
  • JCryptPassword
  • JFeedParserNamespace
  • JHttpTransport
  • JLayout
  • JModel
  • JObservableInterface
  • JObserverInterface
  • JObserverUpdaterInterface
  • JSessionHandlerInterface
  • JsonSerializable
  • JUcm
  • JView
  • SimplePie_Cache_Base

Exceptions

  • Error
  • JAccessExceptionNotallowed
  • JCacheExceptionConnecting
  • JCacheExceptionUnsupported
  • JComponentExceptionMissing
  • JDatabaseException
  • JDatabaseExceptionConnecting
  • JDatabaseExceptionExecuting
  • JDatabaseExceptionUnsupported
  • JException
  • JSessionExceptionUnsupported
  • LogException
  • phpmailerException
  • SimplePie_Exception

Constants

  • JERROR_CALLBACK_NOT_CALLABLE
  • JERROR_ILLEGAL_MODE
  • JERROR_ILLEGAL_OPTIONS
  • JREQUEST_ALLOWHTML
  • JREQUEST_ALLOWRAW
  • JREQUEST_NOTRIM
  • JROUTER_MODE_RAW
  • JROUTER_MODE_SEF

Functions

  • __autoload
  • array_column
  • boolval
  • composerRequire205c915b9c7d3e718e7c95793ee67ffe
  • gzopen
  • gzseek
  • gztell
  • hash_equals
  • hash_pbkdf2
  • HTMLFilter
  • jexit
  • jimport
  • json_last_error_msg
  • ldap_escape
  • password_get_info
  • password_hash
  • password_needs_rehash
  • password_verify
  • PHPMailerAutoload
  • random_bytes
  • random_int
  • RandomCompat_intval
  • RandomCompat_strlen
  • RandomCompat_substr
  • tln_body2div
  • tln_casenormalize
  • tln_deent
  • tln_defang
  • tln_findnxreg
  • tln_findnxstr
  • tln_fixatts
  • tln_fixstyle
  • tln_fixurl
  • tln_getnxtag
  • tln_sanitize
  • tln_skipspace
  • tln_tagprint
  • tln_unspace
  • utf8_accents_to_ascii
  • utf8_bad_explain
  • utf8_bad_find
  • utf8_bad_findall
  • utf8_bad_identify
  • utf8_bad_replace
  • utf8_bad_strip
  • utf8_byte_position
  • utf8_compliant
  • utf8_from_unicode
  • utf8_ireplace
  • utf8_is_ascii
  • utf8_is_ascii_ctrl
  • utf8_is_valid
  • utf8_is_word_chars
  • utf8_locate_current_chr
  • utf8_locate_next_chr
  • utf8_ltrim
  • utf8_ord
  • utf8_rtrim
  • utf8_specials_pattern
  • utf8_str_pad
  • utf8_str_split
  • utf8_strcasecmp
  • utf8_strcspn
  • utf8_strip_ascii_ctrl
  • utf8_strip_non_ascii
  • utf8_strip_non_ascii_ctrl
  • utf8_strip_specials
  • utf8_stristr
  • utf8_strlen
  • utf8_strpos
  • utf8_strrev
  • utf8_strrpos
  • utf8_strspn
  • utf8_strtolower
  • utf8_strtoupper
  • utf8_substr
  • utf8_substr_replace
  • utf8_to_unicode
  • utf8_trim
  • utf8_ucfirst
  • utf8_ucwords
  • utf8_ucwords_callback
   1 <?php
   2 /**
   3  * @package     FrameworkOnFramework
   4  * @subpackage  less
   5  * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
   6  * @license     GNU General Public License version 2 or later; see LICENSE.txt
   7  */
   8 // Protect from unauthorized access
   9 defined('FOF_INCLUDED') or die;
  10 
  11 /**
  12  * This class is taken verbatim from:
  13  *
  14  * lessphp v0.3.9
  15  * http://leafo.net/lessphp
  16  *
  17  * LESS css compiler, adapted from http://lesscss.org
  18  *
  19  * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
  20  * Licensed under MIT or GPLv3, see LICENSE
  21  *
  22  * Responsible for taking a string of LESS code and converting it into a syntax tree
  23  *
  24  * @since  2.0
  25  */
  26 class FOFLessParser
  27 {
  28     // Used to uniquely identify blocks
  29     protected static $nextBlockId = 0;
  30 
  31     protected static $precedence = array(
  32         '=<'                     => 0,
  33         '>='                     => 0,
  34         '='                      => 0,
  35         '<'                      => 0,
  36         '>'                      => 0,
  37         '+'                      => 1,
  38         '-'                      => 1,
  39         '*'                      => 2,
  40         '/'                      => 2,
  41         '%'                      => 2,
  42     );
  43 
  44     protected static $whitePattern;
  45 
  46     protected static $commentMulti;
  47 
  48     protected static $commentSingle = "//";
  49 
  50     protected static $commentMultiLeft = "/*";
  51 
  52     protected static $commentMultiRight = "*/";
  53 
  54     // Regex string to match any of the operators
  55     protected static $operatorString;
  56 
  57     // These properties will supress division unless it's inside parenthases
  58     protected static $supressDivisionProps = array('/border-radius$/i', '/^font$/i');
  59 
  60     protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document");
  61 
  62     protected $lineDirectives = array("charset");
  63 
  64     /**
  65      * if we are in parens we can be more liberal with whitespace around
  66      * operators because it must evaluate to a single value and thus is less
  67      * ambiguous.
  68      *
  69      * Consider:
  70      *     property1: 10 -5; // is two numbers, 10 and -5
  71      *     property2: (10 -5); // should evaluate to 5
  72      */
  73     protected $inParens = false;
  74 
  75     // Caches preg escaped literals
  76     protected static $literalCache = array();
  77 
  78     /**
  79      * Constructor
  80      *
  81      * @param   [type]  $lessc       [description]
  82      * @param   string  $sourceName  [description]
  83      */
  84     public function __construct($lessc, $sourceName = null)
  85     {
  86         $this->eatWhiteDefault = true;
  87 
  88         // Reference to less needed for vPrefix, mPrefix, and parentSelector
  89         $this->lessc = $lessc;
  90 
  91         // Name used for error messages
  92         $this->sourceName = $sourceName;
  93 
  94         $this->writeComments = false;
  95 
  96         if (!self::$operatorString)
  97         {
  98             self::$operatorString = '(' . implode('|', array_map(array('FOFLess', 'preg_quote'), array_keys(self::$precedence))) . ')';
  99 
 100             $commentSingle = FOFLess::preg_quote(self::$commentSingle);
 101             $commentMultiLeft = FOFLess::preg_quote(self::$commentMultiLeft);
 102             $commentMultiRight = FOFLess::preg_quote(self::$commentMultiRight);
 103 
 104             self::$commentMulti = $commentMultiLeft . '.*?' . $commentMultiRight;
 105             self::$whitePattern = '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentMulti . ')\s*|\s+/Ais';
 106         }
 107     }
 108 
 109     /**
 110      * Parse text
 111      *
 112      * @param   string  $buffer  [description]
 113      *
 114      * @return  [type]           [description]
 115      */
 116     public function parse($buffer)
 117     {
 118         $this->count = 0;
 119         $this->line = 1;
 120 
 121         // Block stack
 122         $this->env = null;
 123         $this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
 124         $this->pushSpecialBlock("root");
 125         $this->eatWhiteDefault = true;
 126         $this->seenComments = array();
 127 
 128         /*
 129          * trim whitespace on head
 130          * if (preg_match('/^\s+/', $this->buffer, $m)) {
 131          *  $this->line += substr_count($m[0], "\n");
 132          *  $this->buffer = ltrim($this->buffer);
 133          * }
 134          */
 135         $this->whitespace();
 136 
 137         // Parse the entire file
 138         $lastCount = $this->count;
 139         while (false !== $this->parseChunk());
 140 
 141         if ($this->count != strlen($this->buffer))
 142         {
 143             $this->throwError();
 144         }
 145 
 146         // TODO report where the block was opened
 147         if (!is_null($this->env->parent))
 148         {
 149             throw new exception('parse error: unclosed block');
 150         }
 151 
 152         return $this->env;
 153     }
 154 
 155     /**
 156      * Parse a single chunk off the head of the buffer and append it to the
 157      * current parse environment.
 158      * Returns false when the buffer is empty, or when there is an error.
 159      *
 160      * This function is called repeatedly until the entire document is
 161      * parsed.
 162      *
 163      * This parser is most similar to a recursive descent parser. Single
 164      * functions represent discrete grammatical rules for the language, and
 165      * they are able to capture the text that represents those rules.
 166      *
 167      * Consider the function lessc::keyword(). (all parse functions are
 168      * structured the same)
 169      *
 170      * The function takes a single reference argument. When calling the
 171      * function it will attempt to match a keyword on the head of the buffer.
 172      * If it is successful, it will place the keyword in the referenced
 173      * argument, advance the position in the buffer, and return true. If it
 174      * fails then it won't advance the buffer and it will return false.
 175      *
 176      * All of these parse functions are powered by lessc::match(), which behaves
 177      * the same way, but takes a literal regular expression. Sometimes it is
 178      * more convenient to use match instead of creating a new function.
 179      *
 180      * Because of the format of the functions, to parse an entire string of
 181      * grammatical rules, you can chain them together using &&.
 182      *
 183      * But, if some of the rules in the chain succeed before one fails, then
 184      * the buffer position will be left at an invalid state. In order to
 185      * avoid this, lessc::seek() is used to remember and set buffer positions.
 186      *
 187      * Before parsing a chain, use $s = $this->seek() to remember the current
 188      * position into $s. Then if a chain fails, use $this->seek($s) to
 189      * go back where we started.
 190      *
 191      * @return  boolean
 192      */
 193     protected function parseChunk()
 194     {
 195         if (empty($this->buffer))
 196         {
 197             return false;
 198         }
 199 
 200         $s = $this->seek();
 201 
 202         // Setting a property
 203         if ($this->keyword($key) && $this->assign()
 204             && $this->propertyValue($value, $key) && $this->end())
 205         {
 206             $this->append(array('assign', $key, $value), $s);
 207 
 208             return true;
 209         }
 210         else
 211         {
 212             $this->seek($s);
 213         }
 214 
 215         // Look for special css blocks
 216         if ($this->literal('@', false))
 217         {
 218             $this->count--;
 219 
 220             // Media
 221             if ($this->literal('@media'))
 222             {
 223                 if (($this->mediaQueryList($mediaQueries) || true)
 224                     && $this->literal('{'))
 225                 {
 226                     $media = $this->pushSpecialBlock("media");
 227                     $media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
 228 
 229                     return true;
 230                 }
 231                 else
 232                 {
 233                     $this->seek($s);
 234 
 235                     return false;
 236                 }
 237             }
 238 
 239             if ($this->literal("@", false) && $this->keyword($dirName))
 240             {
 241                 if ($this->isDirective($dirName, $this->blockDirectives))
 242                 {
 243                     if (($this->openString("{", $dirValue, null, array(";")) || true)
 244                         && $this->literal("{"))
 245                     {
 246                         $dir = $this->pushSpecialBlock("directive");
 247                         $dir->name = $dirName;
 248 
 249                         if (isset($dirValue))
 250                         {
 251                             $dir->value = $dirValue;
 252                         }
 253 
 254                         return true;
 255                     }
 256                 }
 257                 elseif ($this->isDirective($dirName, $this->lineDirectives))
 258                 {
 259                     if ($this->propertyValue($dirValue) && $this->end())
 260                     {
 261                         $this->append(array("directive", $dirName, $dirValue));
 262 
 263                         return true;
 264                     }
 265                 }
 266             }
 267 
 268             $this->seek($s);
 269         }
 270 
 271         // Setting a variable
 272         if ($this->variable($var) && $this->assign()
 273             && $this->propertyValue($value) && $this->end())
 274         {
 275             $this->append(array('assign', $var, $value), $s);
 276 
 277             return true;
 278         }
 279         else
 280         {
 281             $this->seek($s);
 282         }
 283 
 284         if ($this->import($importValue))
 285         {
 286             $this->append($importValue, $s);
 287 
 288             return true;
 289         }
 290 
 291         // Opening parametric mixin
 292         if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg)
 293             && ($this->guards($guards) || true)
 294             && $this->literal('{'))
 295         {
 296             $block = $this->pushBlock($this->fixTags(array($tag)));
 297             $block->args = $args;
 298             $block->isVararg = $isVararg;
 299 
 300             if (!empty($guards))
 301             {
 302                 $block->guards = $guards;
 303             }
 304 
 305             return true;
 306         }
 307         else
 308         {
 309             $this->seek($s);
 310         }
 311 
 312         // Opening a simple block
 313         if ($this->tags($tags) && $this->literal('{'))
 314         {
 315             $tags = $this->fixTags($tags);
 316             $this->pushBlock($tags);
 317 
 318             return true;
 319         }
 320         else
 321         {
 322             $this->seek($s);
 323         }
 324 
 325         // Closing a block
 326         if ($this->literal('}', false))
 327         {
 328             try
 329             {
 330                 $block = $this->pop();
 331             }
 332             catch (exception $e)
 333             {
 334                 $this->seek($s);
 335                 $this->throwError($e->getMessage());
 336             }
 337 
 338             $hidden = false;
 339 
 340             if (is_null($block->type))
 341             {
 342                 $hidden = true;
 343 
 344                 if (!isset($block->args))
 345                 {
 346                     foreach ($block->tags as $tag)
 347                     {
 348                         if (!is_string($tag) || $tag{0} != $this->lessc->mPrefix)
 349                         {
 350                             $hidden = false;
 351                             break;
 352                         }
 353                     }
 354                 }
 355 
 356                 foreach ($block->tags as $tag)
 357                 {
 358                     if (is_string($tag))
 359                     {
 360                         $this->env->children[$tag][] = $block;
 361                     }
 362                 }
 363             }
 364 
 365             if (!$hidden)
 366             {
 367                 $this->append(array('block', $block), $s);
 368             }
 369 
 370             // This is done here so comments aren't bundled into he block that was just closed
 371             $this->whitespace();
 372 
 373             return true;
 374         }
 375 
 376         // Mixin
 377         if ($this->mixinTags($tags)
 378             && ($this->argumentValues($argv) || true)
 379             && ($this->keyword($suffix) || true)
 380             && $this->end())
 381         {
 382             $tags = $this->fixTags($tags);
 383             $this->append(array('mixin', $tags, $argv, $suffix), $s);
 384 
 385             return true;
 386         }
 387         else
 388         {
 389             $this->seek($s);
 390         }
 391 
 392         // Spare ;
 393         if ($this->literal(';'))
 394         {
 395             return true;
 396         }
 397 
 398         // Got nothing, throw error
 399         return false;
 400     }
 401 
 402     /**
 403      * [isDirective description]
 404      *
 405      * @param   string  $dirname     [description]
 406      * @param   [type]  $directives  [description]
 407      *
 408      * @return  boolean
 409      */
 410     protected function isDirective($dirname, $directives)
 411     {
 412         // TODO: cache pattern in parser
 413         $pattern = implode("|", array_map(array("FOFLess", "preg_quote"), $directives));
 414         $pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
 415 
 416         return preg_match($pattern, $dirname);
 417     }
 418 
 419     /**
 420      * [fixTags description]
 421      *
 422      * @param   [type]  $tags  [description]
 423      *
 424      * @return  [type]         [description]
 425      */
 426     protected function fixTags($tags)
 427     {
 428         // Move @ tags out of variable namespace
 429         foreach ($tags as &$tag)
 430         {
 431             if ($tag{0} == $this->lessc->vPrefix)
 432             {
 433                 $tag[0] = $this->lessc->mPrefix;
 434             }
 435         }
 436 
 437         return $tags;
 438     }
 439 
 440     /**
 441      * a list of expressions
 442      *
 443      * @param   [type]  &$exps  [description]
 444      *
 445      * @return  boolean
 446      */
 447     protected function expressionList(&$exps)
 448     {
 449         $values = array();
 450 
 451         while ($this->expression($exp))
 452         {
 453             $values[] = $exp;
 454         }
 455 
 456         if (count($values) == 0)
 457         {
 458             return false;
 459         }
 460 
 461         $exps = FOFLess::compressList($values, ' ');
 462 
 463         return true;
 464     }
 465 
 466     /**
 467      * Attempt to consume an expression.
 468      *
 469      * @param   string  &$out  [description]
 470      *
 471      * @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
 472      *
 473      * @return  boolean
 474      */
 475     protected function expression(&$out)
 476     {
 477         if ($this->value($lhs))
 478         {
 479             $out = $this->expHelper($lhs, 0);
 480 
 481             // Look for / shorthand
 482             if (!empty($this->env->supressedDivision))
 483             {
 484                 unset($this->env->supressedDivision);
 485                 $s = $this->seek();
 486 
 487                 if ($this->literal("/") && $this->value($rhs))
 488                 {
 489                     $out = array("list", "",
 490                         array($out, array("keyword", "/"), $rhs));
 491                 }
 492                 else
 493                 {
 494                     $this->seek($s);
 495                 }
 496             }
 497 
 498             return true;
 499         }
 500 
 501         return false;
 502     }
 503 
 504     /**
 505      * Recursively parse infix equation with $lhs at precedence $minP
 506      *
 507      * @param   type  $lhs   [description]
 508      * @param   type  $minP  [description]
 509      *
 510      * @return   string
 511      */
 512     protected function expHelper($lhs, $minP)
 513     {
 514         $this->inExp = true;
 515         $ss = $this->seek();
 516 
 517         while (true)
 518         {
 519             $whiteBefore = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]);
 520 
 521             // If there is whitespace before the operator, then we require
 522             // whitespace after the operator for it to be an expression
 523             $needWhite = $whiteBefore && !$this->inParens;
 524 
 525             if ($this->match(self::$operatorString . ($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP)
 526             {
 527                 if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision))
 528                 {
 529                     foreach (self::$supressDivisionProps as $pattern)
 530                     {
 531                         if (preg_match($pattern, $this->env->currentProperty))
 532                         {
 533                             $this->env->supressedDivision = true;
 534                             break 2;
 535                         }
 536                     }
 537                 }
 538 
 539                 $whiteAfter = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]);
 540 
 541                 if (!$this->value($rhs))
 542                 {
 543                     break;
 544                 }
 545 
 546                 // Peek for next operator to see what to do with rhs
 547                 if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]])
 548                 {
 549                     $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
 550                 }
 551 
 552                 $lhs = array('expression', $m[1], $lhs, $rhs, $whiteBefore, $whiteAfter);
 553                 $ss = $this->seek();
 554 
 555                 continue;
 556             }
 557 
 558             break;
 559         }
 560 
 561         $this->seek($ss);
 562 
 563         return $lhs;
 564     }
 565 
 566     /**
 567      * Consume a list of values for a property
 568      *
 569      * @param   [type]  &$value   [description]
 570      * @param   [type]  $keyName  [description]
 571      *
 572      * @return  boolean
 573      */
 574     public function propertyValue(&$value, $keyName = null)
 575     {
 576         $values = array();
 577 
 578         if ($keyName !== null)
 579         {
 580             $this->env->currentProperty = $keyName;
 581         }
 582 
 583         $s = null;
 584 
 585         while ($this->expressionList($v))
 586         {
 587             $values[] = $v;
 588             $s = $this->seek();
 589 
 590             if (!$this->literal(','))
 591             {
 592                 break;
 593             }
 594         }
 595 
 596         if ($s)
 597         {
 598             $this->seek($s);
 599         }
 600 
 601         if ($keyName !== null)
 602         {
 603             unset($this->env->currentProperty);
 604         }
 605 
 606         if (count($values) == 0)
 607         {
 608             return false;
 609         }
 610 
 611         $value = FOFLess::compressList($values, ', ');
 612 
 613         return true;
 614     }
 615 
 616     /**
 617      * [parenValue description]
 618      *
 619      * @param   [type]  &$out  [description]
 620      *
 621      * @return  boolean
 622      */
 623     protected function parenValue(&$out)
 624     {
 625         $s = $this->seek();
 626 
 627         // Speed shortcut
 628         if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(")
 629         {
 630             return false;
 631         }
 632 
 633         $inParens = $this->inParens;
 634 
 635         if ($this->literal("(") && ($this->inParens = true) && $this->expression($exp) && $this->literal(")"))
 636         {
 637             $out = $exp;
 638             $this->inParens = $inParens;
 639 
 640             return true;
 641         }
 642         else
 643         {
 644             $this->inParens = $inParens;
 645             $this->seek($s);
 646         }
 647 
 648         return false;
 649     }
 650 
 651     /**
 652      * a single value
 653      *
 654      * @param   [type]  &$value  [description]
 655      *
 656      * @return  boolean
 657      */
 658     protected function value(&$value)
 659     {
 660         $s = $this->seek();
 661 
 662         // Speed shortcut
 663         if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-")
 664         {
 665             // Negation
 666             if ($this->literal("-", false) &&(($this->variable($inner) && $inner = array("variable", $inner))
 667                 || $this->unit($inner) || $this->parenValue($inner)))
 668             {
 669                 $value = array("unary", "-", $inner);
 670 
 671                 return true;
 672             }
 673             else
 674             {
 675                 $this->seek($s);
 676             }
 677         }
 678 
 679         if ($this->parenValue($value))
 680         {
 681             return true;
 682         }
 683 
 684         if ($this->unit($value))
 685         {
 686             return true;
 687         }
 688 
 689         if ($this->color($value))
 690         {
 691             return true;
 692         }
 693 
 694         if ($this->func($value))
 695         {
 696             return true;
 697         }
 698 
 699         if ($this->string($value))
 700         {
 701             return true;
 702         }
 703 
 704         if ($this->keyword($word))
 705         {
 706             $value = array('keyword', $word);
 707 
 708             return true;
 709         }
 710 
 711         // Try a variable
 712         if ($this->variable($var))
 713         {
 714             $value = array('variable', $var);
 715 
 716             return true;
 717         }
 718 
 719         // Unquote string (should this work on any type?
 720         if ($this->literal("~") && $this->string($str))
 721         {
 722             $value = array("escape", $str);
 723 
 724             return true;
 725         }
 726         else
 727         {
 728             $this->seek($s);
 729         }
 730 
 731         // Css hack: \0
 732         if ($this->literal('\\') && $this->match('([0-9]+)', $m))
 733         {
 734             $value = array('keyword', '\\' . $m[1]);
 735 
 736             return true;
 737         }
 738         else
 739         {
 740             $this->seek($s);
 741         }
 742 
 743         return false;
 744     }
 745 
 746     /**
 747      * an import statement
 748      *
 749      * @param   [type]  &$out  [description]
 750      *
 751      * @return  boolean
 752      */
 753     protected function import(&$out)
 754     {
 755         $s = $this->seek();
 756 
 757         if (!$this->literal('@import'))
 758         {
 759             return false;
 760         }
 761 
 762         /*
 763          * @import "something.css" media;
 764          * @import url("something.css") media;
 765          * @import url(something.css) media;
 766          */
 767 
 768         if ($this->propertyValue($value))
 769         {
 770             $out = array("import", $value);
 771 
 772             return true;
 773         }
 774     }
 775 
 776     /**
 777      * [mediaQueryList description]
 778      *
 779      * @param   [type]  &$out  [description]
 780      *
 781      * @return  boolean
 782      */
 783     protected function mediaQueryList(&$out)
 784     {
 785         if ($this->genericList($list, "mediaQuery", ",", false))
 786         {
 787             $out = $list[2];
 788 
 789             return true;
 790         }
 791 
 792         return false;
 793     }
 794 
 795     /**
 796      * [mediaQuery description]
 797      *
 798      * @param   [type]  &$out  [description]
 799      *
 800      * @return  [type]        [description]
 801      */
 802     protected function mediaQuery(&$out)
 803     {
 804         $s = $this->seek();
 805 
 806         $expressions = null;
 807         $parts = array();
 808 
 809         if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType))
 810         {
 811             $prop = array("mediaType");
 812 
 813             if (isset($only))
 814             {
 815                 $prop[] = "only";
 816             }
 817 
 818             if (isset($not))
 819             {
 820                 $prop[] = "not";
 821             }
 822 
 823             $prop[] = $mediaType;
 824             $parts[] = $prop;
 825         }
 826         else
 827         {
 828             $this->seek($s);
 829         }
 830 
 831         if (!empty($mediaType) && !$this->literal("and"))
 832         {
 833             // ~
 834         }
 835         else
 836         {
 837             $this->genericList($expressions, "mediaExpression", "and", false);
 838 
 839             if (is_array($expressions))
 840             {
 841                 $parts = array_merge($parts, $expressions[2]);
 842             }
 843         }
 844 
 845         if (count($parts) == 0)
 846         {
 847             $this->seek($s);
 848 
 849             return false;
 850         }
 851 
 852         $out = $parts;
 853 
 854         return true;
 855     }
 856 
 857     /**
 858      * [mediaExpression description]
 859      *
 860      * @param   [type]  &$out  [description]
 861      *
 862      * @return  boolean
 863      */
 864     protected function mediaExpression(&$out)
 865     {
 866         $s = $this->seek();
 867         $value = null;
 868 
 869         if ($this->literal("(") && $this->keyword($feature) && ($this->literal(":")
 870             && $this->expression($value) || true) && $this->literal(")"))
 871         {
 872             $out = array("mediaExp", $feature);
 873 
 874             if ($value)
 875             {
 876                 $out[] = $value;
 877             }
 878 
 879             return true;
 880         }
 881         elseif ($this->variable($variable))
 882         {
 883             $out = array('variable', $variable);
 884 
 885             return true;
 886         }
 887         $this->seek($s);
 888 
 889         return false;
 890     }
 891 
 892     /**
 893      * An unbounded string stopped by $end
 894      *
 895      * @param   [type]  $end          [description]
 896      * @param   [type]  &$out         [description]
 897      * @param   [type]  $nestingOpen  [description]
 898      * @param   [type]  $rejectStrs   [description]
 899      *
 900      * @return  boolean
 901      */
 902     protected function openString($end, &$out, $nestingOpen = null, $rejectStrs = null)
 903     {
 904         $oldWhite = $this->eatWhiteDefault;
 905         $this->eatWhiteDefault = false;
 906 
 907         $stop = array("'", '"', "@{", $end);
 908         $stop = array_map(array("FOFLess", "preg_quote"), $stop);
 909 
 910         // $stop[] = self::$commentMulti;
 911 
 912         if (!is_null($rejectStrs))
 913         {
 914             $stop = array_merge($stop, $rejectStrs);
 915         }
 916 
 917         $patt = '(.*?)(' . implode("|", $stop) . ')';
 918 
 919         $nestingLevel = 0;
 920 
 921         $content = array();
 922 
 923         while ($this->match($patt, $m, false))
 924         {
 925             if (!empty($m[1]))
 926             {
 927                 $content[] = $m[1];
 928 
 929                 if ($nestingOpen)
 930                 {
 931                     $nestingLevel += substr_count($m[1], $nestingOpen);
 932                 }
 933             }
 934 
 935             $tok = $m[2];
 936 
 937             $this->count -= strlen($tok);
 938 
 939             if ($tok == $end)
 940             {
 941                 if ($nestingLevel == 0)
 942                 {
 943                     break;
 944                 }
 945                 else
 946                 {
 947                     $nestingLevel--;
 948                 }
 949             }
 950 
 951             if (($tok == "'" || $tok == '"') && $this->string($str))
 952             {
 953                 $content[] = $str;
 954                 continue;
 955             }
 956 
 957             if ($tok == "@{" && $this->interpolation($inter))
 958             {
 959                 $content[] = $inter;
 960                 continue;
 961             }
 962 
 963             if (in_array($tok, $rejectStrs))
 964             {
 965                 $count = null;
 966                 break;
 967             }
 968 
 969             $content[] = $tok;
 970             $this->count += strlen($tok);
 971         }
 972 
 973         $this->eatWhiteDefault = $oldWhite;
 974 
 975         if (count($content) == 0)
 976             return false;
 977 
 978         // Trim the end
 979         if (is_string(end($content)))
 980         {
 981             $content[count($content) - 1] = rtrim(end($content));
 982         }
 983 
 984         $out = array("string", "", $content);
 985 
 986         return true;
 987     }
 988 
 989     /**
 990      * [string description]
 991      *
 992      * @param   [type]  &$out  [description]
 993      *
 994      * @return  boolean
 995      */
 996     protected function string(&$out)
 997     {
 998         $s = $this->seek();
 999 
1000         if ($this->literal('"', false))
1001         {
1002             $delim = '"';
1003         }
1004         elseif ($this->literal("'", false))
1005         {
1006             $delim = "'";
1007         }
1008         else
1009         {
1010             return false;
1011         }
1012 
1013         $content = array();
1014 
1015         // Look for either ending delim , escape, or string interpolation
1016         $patt = '([^\n]*?)(@\{|\\\\|' . FOFLess::preg_quote($delim) . ')';
1017 
1018         $oldWhite = $this->eatWhiteDefault;
1019         $this->eatWhiteDefault = false;
1020 
1021         while ($this->match($patt, $m, false))
1022         {
1023             $content[] = $m[1];
1024 
1025             if ($m[2] == "@{")
1026             {
1027                 $this->count -= strlen($m[2]);
1028 
1029                 if ($this->interpolation($inter, false))
1030                 {
1031                     $content[] = $inter;
1032                 }
1033                 else
1034                 {
1035                     $this->count += strlen($m[2]);
1036 
1037                     // Ignore it
1038                     $content[] = "@{";
1039                 }
1040             }
1041             elseif ($m[2] == '\\')
1042             {
1043                 $content[] = $m[2];
1044 
1045                 if ($this->literal($delim, false))
1046                 {
1047                     $content[] = $delim;
1048                 }
1049             }
1050             else
1051             {
1052                 $this->count -= strlen($delim);
1053 
1054                 // Delim
1055                 break;
1056             }
1057         }
1058 
1059         $this->eatWhiteDefault = $oldWhite;
1060 
1061         if ($this->literal($delim))
1062         {
1063             $out = array("string", $delim, $content);
1064 
1065             return true;
1066         }
1067 
1068         $this->seek($s);
1069 
1070         return false;
1071     }
1072 
1073     /**
1074      * [interpolation description]
1075      *
1076      * @param   [type]  &$out  [description]
1077      *
1078      * @return  boolean
1079      */
1080     protected function interpolation(&$out)
1081     {
1082         $oldWhite = $this->eatWhiteDefault;
1083         $this->eatWhiteDefault = true;
1084 
1085         $s = $this->seek();
1086 
1087         if ($this->literal("@{") && $this->openString("}", $interp, null, array("'", '"', ";")) && $this->literal("}", false))
1088         {
1089             $out = array("interpolate", $interp);
1090             $this->eatWhiteDefault = $oldWhite;
1091 
1092             if ($this->eatWhiteDefault)
1093             {
1094                 $this->whitespace();
1095             }
1096 
1097             return true;
1098         }
1099 
1100         $this->eatWhiteDefault = $oldWhite;
1101         $this->seek($s);
1102 
1103         return false;
1104     }
1105 
1106     /**
1107      * [unit description]
1108      *
1109      * @param   [type]  &$unit  [description]
1110      *
1111      * @return  boolean
1112      */
1113     protected function unit(&$unit)
1114     {
1115         // Speed shortcut
1116         if (isset($this->buffer[$this->count]))
1117         {
1118             $char = $this->buffer[$this->count];
1119 
1120             if (!ctype_digit($char) && $char != ".")
1121             {
1122                 return false;
1123             }
1124         }
1125 
1126         if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m))
1127         {
1128             $unit = array("number", $m[1], empty($m[2]) ? "" : $m[2]);
1129 
1130             return true;
1131         }
1132 
1133         return false;
1134     }
1135 
1136     /**
1137      * a # color
1138      *
1139      * @param   [type]  &$out  [description]
1140      *
1141      * @return  boolean
1142      */
1143     protected function color(&$out)
1144     {
1145         if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m))
1146         {
1147             if (strlen($m[1]) > 7)
1148             {
1149                 $out = array("string", "", array($m[1]));
1150             }
1151             else
1152             {
1153                 $out = array("raw_color", $m[1]);
1154             }
1155 
1156             return true;
1157         }
1158 
1159         return false;
1160     }
1161 
1162     /**
1163      * Consume a list of property values delimited by ; and wrapped in ()
1164      *
1165      * @param   [type]  &$args  [description]
1166      * @param   [type]  $delim  [description]
1167      *
1168      * @return  boolean
1169      */
1170     protected function argumentValues(&$args, $delim = ',')
1171     {
1172         $s = $this->seek();
1173 
1174         if (!$this->literal('('))
1175         {
1176             return false;
1177         }
1178 
1179         $values = array();
1180 
1181         while (true)
1182         {
1183             if ($this->expressionList($value))
1184             {
1185                 $values[] = $value;
1186             }
1187 
1188             if (!$this->literal($delim))
1189             {
1190                 break;
1191             }
1192             else
1193             {
1194                 if ($value == null)
1195                 {
1196                     $values[] = null;
1197                 }
1198 
1199                 $value = null;
1200             }
1201         }
1202 
1203         if (!$this->literal(')'))
1204         {
1205             $this->seek($s);
1206 
1207             return false;
1208         }
1209 
1210         $args = $values;
1211 
1212         return true;
1213     }
1214 
1215     /**
1216      * Consume an argument definition list surrounded by ()
1217      * each argument is a variable name with optional value
1218      * or at the end a ... or a variable named followed by ...
1219      *
1220      * @param   [type]  &$args      [description]
1221      * @param   [type]  &$isVararg  [description]
1222      * @param   [type]  $delim      [description]
1223      *
1224      * @return  boolean
1225      */
1226     protected function argumentDef(&$args, &$isVararg, $delim = ',')
1227     {
1228         $s = $this->seek();
1229         if (!$this->literal('('))
1230             return false;
1231 
1232         $values = array();
1233 
1234         $isVararg = false;
1235 
1236         while (true)
1237         {
1238             if ($this->literal("..."))
1239             {
1240                 $isVararg = true;
1241                 break;
1242             }
1243 
1244             if ($this->variable($vname))
1245             {
1246                 $arg = array("arg", $vname);
1247                 $ss = $this->seek();
1248 
1249                 if ($this->assign() && $this->expressionList($value))
1250                 {
1251                     $arg[] = $value;
1252                 }
1253                 else
1254                 {
1255                     $this->seek($ss);
1256 
1257                     if ($this->literal("..."))
1258                     {
1259                         $arg[0] = "rest";
1260                         $isVararg = true;
1261                     }
1262                 }
1263 
1264                 $values[] = $arg;
1265 
1266                 if ($isVararg)
1267                 {
1268                     break;
1269                 }
1270 
1271                 continue;
1272             }
1273 
1274             if ($this->value($literal))
1275             {
1276                 $values[] = array("lit", $literal);
1277             }
1278 
1279             if (!$this->literal($delim))
1280             {
1281                 break;
1282             }
1283         }
1284 
1285         if (!$this->literal(')'))
1286         {
1287             $this->seek($s);
1288 
1289             return false;
1290         }
1291 
1292         $args = $values;
1293 
1294         return true;
1295     }
1296 
1297     /**
1298      * Consume a list of tags
1299      * This accepts a hanging delimiter
1300      *
1301      * @param   [type]  &$tags   [description]
1302      * @param   [type]  $simple  [description]
1303      * @param   [type]  $delim   [description]
1304      *
1305      * @return  boolean
1306      */
1307     protected function tags(&$tags, $simple = false, $delim = ',')
1308     {
1309         $tags = array();
1310 
1311         while ($this->tag($tt, $simple))
1312         {
1313             $tags[] = $tt;
1314 
1315             if (!$this->literal($delim))
1316             {
1317                 break;
1318             }
1319         }
1320 
1321         if (count($tags) == 0)
1322         {
1323             return false;
1324         }
1325 
1326         return true;
1327     }
1328 
1329     /**
1330      * List of tags of specifying mixin path
1331      * Optionally separated by > (lazy, accepts extra >)
1332      *
1333      * @param   [type]  &$tags  [description]
1334      *
1335      * @return  boolean
1336      */
1337     protected function mixinTags(&$tags)
1338     {
1339         $s = $this->seek();
1340         $tags = array();
1341 
1342         while ($this->tag($tt, true))
1343         {
1344             $tags[] = $tt;
1345             $this->literal(">");
1346         }
1347 
1348         if (count($tags) == 0)
1349         {
1350             return false;
1351         }
1352 
1353         return true;
1354     }
1355 
1356     /**
1357      * A bracketed value (contained within in a tag definition)
1358      *
1359      * @param   [type]  &$value  [description]
1360      *
1361      * @return  boolean
1362      */
1363     protected function tagBracket(&$value)
1364     {
1365         // Speed shortcut
1366         if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[")
1367         {
1368             return false;
1369         }
1370 
1371         $s = $this->seek();
1372 
1373         if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false))
1374         {
1375             $value = '[' . $c . ']';
1376 
1377             // Whitespace?
1378             if ($this->whitespace())
1379             {
1380                 $value .= " ";
1381             }
1382 
1383             // Escape parent selector, (yuck)
1384             $value = str_replace($this->lessc->parentSelector, "$&$", $value);
1385 
1386             return true;
1387         }
1388 
1389         $this->seek($s);
1390 
1391         return false;
1392     }
1393 
1394     /**
1395      * [tagExpression description]
1396      *
1397      * @param   [type]  &$value  [description]
1398      *
1399      * @return  boolean
1400      */
1401     protected function tagExpression(&$value)
1402     {
1403         $s = $this->seek();
1404 
1405         if ($this->literal("(") && $this->expression($exp) && $this->literal(")"))
1406         {
1407             $value = array('exp', $exp);
1408 
1409             return true;
1410         }
1411 
1412         $this->seek($s);
1413 
1414         return false;
1415     }
1416 
1417     /**
1418      * A single tag
1419      *
1420      * @param   [type]   &$tag    [description]
1421      * @param   boolean  $simple  [description]
1422      *
1423      * @return  boolean
1424      */
1425     protected function tag(&$tag, $simple = false)
1426     {
1427         if ($simple)
1428         {
1429             $chars = '^@,:;{}\][>\(\) "\'';
1430         }
1431         else
1432         {
1433             $chars = '^@,;{}["\'';
1434         }
1435 
1436         $s = $this->seek();
1437 
1438         if (!$simple && $this->tagExpression($tag))
1439         {
1440             return true;
1441         }
1442 
1443         $hasExpression = false;
1444         $parts         = array();
1445 
1446         while ($this->tagBracket($first))
1447         {
1448             $parts[] = $first;
1449         }
1450 
1451         $oldWhite = $this->eatWhiteDefault;
1452 
1453         $this->eatWhiteDefault = false;
1454 
1455         while (true)
1456         {
1457             if ($this->match('([' . $chars . '0-9][' . $chars . ']*)', $m))
1458             {
1459                 $parts[] = $m[1];
1460 
1461                 if ($simple)
1462                 {
1463                     break;
1464                 }
1465 
1466                 while ($this->tagBracket($brack))
1467                 {
1468                     $parts[] = $brack;
1469                 }
1470 
1471                 continue;
1472             }
1473 
1474             if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@")
1475             {
1476                 if ($this->interpolation($interp))
1477                 {
1478                     $hasExpression = true;
1479 
1480                     // Don't unescape
1481                     $interp[2] = true;
1482                     $parts[] = $interp;
1483 
1484                     continue;
1485                 }
1486 
1487                 if ($this->literal("@"))
1488                 {
1489                     $parts[] = "@";
1490 
1491                     continue;
1492                 }
1493             }
1494 
1495             // For keyframes
1496             if ($this->unit($unit))
1497             {
1498                 $parts[] = $unit[1];
1499                 $parts[] = $unit[2];
1500                 continue;
1501             }
1502 
1503             break;
1504         }
1505 
1506         $this->eatWhiteDefault = $oldWhite;
1507 
1508         if (!$parts)
1509         {
1510             $this->seek($s);
1511 
1512             return false;
1513         }
1514 
1515         if ($hasExpression)
1516         {
1517             $tag = array("exp", array("string", "", $parts));
1518         }
1519         else
1520         {
1521             $tag = trim(implode($parts));
1522         }
1523 
1524         $this->whitespace();
1525 
1526         return true;
1527     }
1528 
1529     /**
1530      * A css function
1531      *
1532      * @param   [type]  &$func  [description]
1533      *
1534      * @return  boolean
1535      */
1536     protected function func(&$func)
1537     {
1538         $s = $this->seek();
1539 
1540         if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('('))
1541         {
1542             $fname = $m[1];
1543 
1544             $sPreArgs = $this->seek();
1545 
1546             $args = array();
1547 
1548             while (true)
1549             {
1550                 $ss = $this->seek();
1551 
1552                 // This ugly nonsense is for ie filter properties
1553                 if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value))
1554                 {
1555                     $args[] = array("string", "", array($name, "=", $value));
1556                 }
1557                 else
1558                 {
1559                     $this->seek($ss);
1560 
1561                     if ($this->expressionList($value))
1562                     {
1563                         $args[] = $value;
1564                     }
1565                 }
1566 
1567                 if (!$this->literal(','))
1568                 {
1569                     break;
1570                 }
1571             }
1572 
1573             $args = array('list', ',', $args);
1574 
1575             if ($this->literal(')'))
1576             {
1577                 $func = array('function', $fname, $args);
1578 
1579                 return true;
1580             }
1581             elseif ($fname == 'url')
1582             {
1583                 // Couldn't parse and in url? treat as string
1584                 $this->seek($sPreArgs);
1585 
1586                 if ($this->openString(")", $string) && $this->literal(")"))
1587                 {
1588                     $func = array('function', $fname, $string);
1589 
1590                     return true;
1591                 }
1592             }
1593         }
1594 
1595         $this->seek($s);
1596 
1597         return false;
1598     }
1599 
1600     /**
1601      * Consume a less variable
1602      *
1603      * @param   [type]  &$name  [description]
1604      *
1605      * @return  boolean
1606      */
1607     protected function variable(&$name)
1608     {
1609         $s = $this->seek();
1610 
1611         if ($this->literal($this->lessc->vPrefix, false) && ($this->variable($sub) || $this->keyword($name)))
1612         {
1613             if (!empty($sub))
1614             {
1615                 $name = array('variable', $sub);
1616             }
1617             else
1618             {
1619                 $name = $this->lessc->vPrefix . $name;
1620             }
1621 
1622             return true;
1623         }
1624 
1625         $name = null;
1626         $this->seek($s);
1627 
1628         return false;
1629     }
1630 
1631     /**
1632      * Consume an assignment operator
1633      * Can optionally take a name that will be set to the current property name
1634      *
1635      * @param   string  $name  [description]
1636      *
1637      * @return  boolean
1638      */
1639     protected function assign($name = null)
1640     {
1641         if ($name)
1642         {
1643             $this->currentProperty = $name;
1644         }
1645 
1646         return $this->literal(':') || $this->literal('=');
1647     }
1648 
1649     /**
1650      * Consume a keyword
1651      *
1652      * @param   [type]  &$word  [description]
1653      *
1654      * @return  boolean
1655      */
1656     protected function keyword(&$word)
1657     {
1658         if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m))
1659         {
1660             $word = $m[1];
1661 
1662             return true;
1663         }
1664 
1665         return false;
1666     }
1667 
1668     /**
1669      * Consume an end of statement delimiter
1670      *
1671      * @return  boolean
1672      */
1673     protected function end()
1674     {
1675         if ($this->literal(';'))
1676         {
1677             return true;
1678         }
1679         elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}')
1680         {
1681             // If there is end of file or a closing block next then we don't need a ;
1682             return true;
1683         }
1684 
1685         return false;
1686     }
1687 
1688     /**
1689      * [guards description]
1690      *
1691      * @param   [type]  &$guards  [description]
1692      *
1693      * @return  boolean
1694      */
1695     protected function guards(&$guards)
1696     {
1697         $s = $this->seek();
1698 
1699         if (!$this->literal("when"))
1700         {
1701             $this->seek($s);
1702 
1703             return false;
1704         }
1705 
1706         $guards = array();
1707 
1708         while ($this->guardGroup($g))
1709         {
1710             $guards[] = $g;
1711 
1712             if (!$this->literal(","))
1713             {
1714                 break;
1715             }
1716         }
1717 
1718         if (count($guards) == 0)
1719         {
1720             $guards = null;
1721             $this->seek($s);
1722 
1723             return false;
1724         }
1725 
1726         return true;
1727     }
1728 
1729     /**
1730      * A bunch of guards that are and'd together
1731      *
1732      * @param   [type]  &$guardGroup  [description]
1733      *
1734      * @todo rename to guardGroup
1735      *
1736      * @return  boolean
1737      */
1738     protected function guardGroup(&$guardGroup)
1739     {
1740         $s = $this->seek();
1741         $guardGroup = array();
1742 
1743         while ($this->guard($guard))
1744         {
1745             $guardGroup[] = $guard;
1746 
1747             if (!$this->literal("and"))
1748             {
1749                 break;
1750             }
1751         }
1752 
1753         if (count($guardGroup) == 0)
1754         {
1755             $guardGroup = null;
1756             $this->seek($s);
1757 
1758             return false;
1759         }
1760 
1761         return true;
1762     }
1763 
1764     /**
1765      * [guard description]
1766      *
1767      * @param   [type]  &$guard  [description]
1768      *
1769      * @return  boolean
1770      */
1771     protected function guard(&$guard)
1772     {
1773         $s = $this->seek();
1774         $negate = $this->literal("not");
1775 
1776         if ($this->literal("(") && $this->expression($exp) && $this->literal(")"))
1777         {
1778             $guard = $exp;
1779 
1780             if ($negate)
1781             {
1782                 $guard = array("negate", $guard);
1783             }
1784 
1785             return true;
1786         }
1787 
1788         $this->seek($s);
1789 
1790         return false;
1791     }
1792 
1793     /* raw parsing functions */
1794 
1795     /**
1796      * [literal description]
1797      *
1798      * @param   [type]  $what           [description]
1799      * @param   [type]  $eatWhitespace  [description]
1800      *
1801      * @return  boolean
1802      */
1803     protected function literal($what, $eatWhitespace = null)
1804     {
1805         if ($eatWhitespace === null)
1806         {
1807             $eatWhitespace = $this->eatWhiteDefault;
1808         }
1809 
1810         // Shortcut on single letter
1811         if (!isset($what[1]) && isset($this->buffer[$this->count]))
1812         {
1813             if ($this->buffer[$this->count] == $what)
1814             {
1815                 if (!$eatWhitespace)
1816                 {
1817                     $this->count++;
1818 
1819                     return true;
1820                 }
1821             }
1822             else
1823             {
1824                 return false;
1825             }
1826         }
1827 
1828         if (!isset(self::$literalCache[$what]))
1829         {
1830             self::$literalCache[$what] = FOFLess::preg_quote($what);
1831         }
1832 
1833         return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
1834     }
1835 
1836     /**
1837      * [genericList description]
1838      *
1839      * @param   [type]   &$out       [description]
1840      * @param   [type]   $parseItem  [description]
1841      * @param   string   $delim      [description]
1842      * @param   boolean  $flatten    [description]
1843      *
1844      * @return  boolean
1845      */
1846     protected function genericList(&$out, $parseItem, $delim = "", $flatten = true)
1847     {
1848         $s = $this->seek();
1849         $items = array();
1850 
1851         while ($this->$parseItem($value))
1852         {
1853             $items[] = $value;
1854 
1855             if ($delim)
1856             {
1857                 if (!$this->literal($delim))
1858                 {
1859                     break;
1860                 }
1861             }
1862         }
1863 
1864         if (count($items) == 0)
1865         {
1866             $this->seek($s);
1867 
1868             return false;
1869         }
1870 
1871         if ($flatten && count($items) == 1)
1872         {
1873             $out = $items[0];
1874         }
1875         else
1876         {
1877             $out = array("list", $delim, $items);
1878         }
1879 
1880         return true;
1881     }
1882 
1883     /**
1884      * Advance counter to next occurrence of $what
1885      * $until - don't include $what in advance
1886      * $allowNewline, if string, will be used as valid char set
1887      *
1888      * @param   [type]   $what          [description]
1889      * @param   [type]   &$out          [description]
1890      * @param   boolean  $until         [description]
1891      * @param   boolean  $allowNewline  [description]
1892      *
1893      * @return  boolean
1894      */
1895     protected function to($what, &$out, $until = false, $allowNewline = false)
1896     {
1897         if (is_string($allowNewline))
1898         {
1899             $validChars = $allowNewline;
1900         }
1901         else
1902         {
1903             $validChars = $allowNewline ? "." : "[^\n]";
1904         }
1905 
1906         if (!$this->match('(' . $validChars . '*?)' . FOFLess::preg_quote($what), $m, !$until))
1907         {
1908             return false;
1909         }
1910 
1911         if ($until)
1912         {
1913             // Give back $what
1914             $this->count -= strlen($what);
1915         }
1916 
1917         $out = $m[1];
1918 
1919         return true;
1920     }
1921 
1922     /**
1923      * Try to match something on head of buffer
1924      *
1925      * @param   [type]  $regex          [description]
1926      * @param   [type]  &$out           [description]
1927      * @param   [type]  $eatWhitespace  [description]
1928      *
1929      * @return  boolean
1930      */
1931     protected function match($regex, &$out, $eatWhitespace = null)
1932     {
1933         if ($eatWhitespace === null)
1934         {
1935             $eatWhitespace = $this->eatWhiteDefault;
1936         }
1937 
1938         $r = '/' . $regex . ($eatWhitespace && !$this->writeComments ? '\s*' : '') . '/Ais';
1939 
1940         if (preg_match($r, $this->buffer, $out, null, $this->count))
1941         {
1942             $this->count += strlen($out[0]);
1943 
1944             if ($eatWhitespace && $this->writeComments)
1945             {
1946                 $this->whitespace();
1947             }
1948 
1949             return true;
1950         }
1951 
1952         return false;
1953     }
1954 
1955     /**
1956      * Watch some whitespace
1957      *
1958      * @return  boolean
1959      */
1960     protected function whitespace()
1961     {
1962         if ($this->writeComments)
1963         {
1964             $gotWhite = false;
1965 
1966             while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count))
1967             {
1968                 if (isset($m[1]) && empty($this->commentsSeen[$this->count]))
1969                 {
1970                     $this->append(array("comment", $m[1]));
1971                     $this->commentsSeen[$this->count] = true;
1972                 }
1973 
1974                 $this->count += strlen($m[0]);
1975                 $gotWhite = true;
1976             }
1977 
1978             return $gotWhite;
1979         }
1980         else
1981         {
1982             $this->match("", $m);
1983 
1984             return strlen($m[0]) > 0;
1985         }
1986     }
1987 
1988     /**
1989      * Match something without consuming it
1990      *
1991      * @param   [type]  $regex  [description]
1992      * @param   [type]  &$out   [description]
1993      * @param   [type]  $from   [description]
1994      *
1995      * @return  boolean
1996      */
1997     protected function peek($regex, &$out = null, $from = null)
1998     {
1999         if (is_null($from))
2000         {
2001             $from = $this->count;
2002         }
2003 
2004         $r = '/' . $regex . '/Ais';
2005         $result = preg_match($r, $this->buffer, $out, null, $from);
2006 
2007         return $result;
2008     }
2009 
2010     /**
2011      * Seek to a spot in the buffer or return where we are on no argument
2012      *
2013      * @param   [type]  $where  [description]
2014      *
2015      * @return  boolean
2016      */
2017     protected function seek($where = null)
2018     {
2019         if ($where === null)
2020         {
2021             return $this->count;
2022         }
2023         else
2024         {
2025             $this->count = $where;
2026         }
2027 
2028         return true;
2029     }
2030 
2031     /* misc functions */
2032 
2033     /**
2034      * [throwError description]
2035      *
2036      * @param   string  $msg    [description]
2037      * @param   [type]  $count  [description]
2038      *
2039      * @return  void
2040      */
2041     public function throwError($msg = "parse error", $count = null)
2042     {
2043         $count = is_null($count) ? $this->count : $count;
2044 
2045         $line = $this->line + substr_count(substr($this->buffer, 0, $count), "\n");
2046 
2047         if (!empty($this->sourceName))
2048         {
2049             $loc = "$this->sourceName on line $line";
2050         }
2051         else
2052         {
2053             $loc = "line: $line";
2054         }
2055 
2056         // TODO this depends on $this->count
2057         if ($this->peek("(.*?)(\n|$)", $m, $count))
2058         {
2059             throw new exception("$msg: failed at `$m[1]` $loc");
2060         }
2061         else
2062         {
2063             throw new exception("$msg: $loc");
2064         }
2065     }
2066 
2067     /**
2068      * [pushBlock description]
2069      *
2070      * @param   [type]  $selectors  [description]
2071      * @param   [type]  $type       [description]
2072      *
2073      * @return  stdClass
2074      */
2075     protected function pushBlock($selectors = null, $type = null)
2076     {
2077         $b = new stdclass;
2078         $b->parent = $this->env;
2079 
2080         $b->type = $type;
2081         $b->id = self::$nextBlockId++;
2082 
2083         // TODO: kill me from here
2084         $b->isVararg = false;
2085         $b->tags = $selectors;
2086 
2087         $b->props = array();
2088         $b->children = array();
2089 
2090         $this->env = $b;
2091 
2092         return $b;
2093     }
2094 
2095     /**
2096      * Push a block that doesn't multiply tags
2097      *
2098      * @param   [type]  $type  [description]
2099      *
2100      * @return  stdClass
2101      */
2102     protected function pushSpecialBlock($type)
2103     {
2104         return $this->pushBlock(null, $type);
2105     }
2106 
2107     /**
2108      * Append a property to the current block
2109      *
2110      * @param   [type]  $prop  [description]
2111      * @param   [type]  $pos   [description]
2112      *
2113      * @return  void
2114      */
2115     protected function append($prop, $pos = null)
2116     {
2117         if ($pos !== null)
2118         {
2119             $prop[-1] = $pos;
2120         }
2121 
2122         $this->env->props[] = $prop;
2123     }
2124 
2125     /**
2126      * Pop something off the stack
2127      *
2128      * @return  [type]  [description]
2129      */
2130     protected function pop()
2131     {
2132         $old = $this->env;
2133         $this->env = $this->env->parent;
2134 
2135         return $old;
2136     }
2137 
2138     /**
2139      * Remove comments from $text
2140      *
2141      * @param   [type]  $text  [description]
2142      *
2143      * @todo: make it work for all functions, not just url
2144      *
2145      * @return  [type]         [description]
2146      */
2147     protected function removeComments($text)
2148     {
2149         $look = array(
2150             'url(', '//', '/*', '"', "'"
2151         );
2152 
2153         $out = '';
2154         $min = null;
2155 
2156         while (true)
2157         {
2158             // Find the next item
2159             foreach ($look as $token)
2160             {
2161                 $pos = strpos($text, $token);
2162 
2163                 if ($pos !== false)
2164                 {
2165                     if (!isset($min) || $pos < $min[1])
2166                     {
2167                         $min = array($token, $pos);
2168                     }
2169                 }
2170             }
2171 
2172             if (is_null($min))
2173                 break;
2174 
2175             $count = $min[1];
2176             $skip = 0;
2177             $newlines = 0;
2178 
2179             switch ($min[0])
2180             {
2181                 case 'url(':
2182 
2183                     if (preg_match('/url\(.*?\)/', $text, $m, 0, $count))
2184                     {
2185                         $count += strlen($m[0]) - strlen($min[0]);
2186                     }
2187 
2188                     break;
2189                 case '"':
2190                 case "'":
2191 
2192                     if (preg_match('/' . $min[0] . '.*?' . $min[0] . '/', $text, $m, 0, $count))
2193                     {
2194                         $count += strlen($m[0]) - 1;
2195                     }
2196 
2197                     break;
2198                 case '//':
2199                     $skip = strpos($text, "\n", $count);
2200 
2201                     if ($skip === false)
2202                     {
2203                         $skip = strlen($text) - $count;
2204                     }
2205                     else
2206                     {
2207                         $skip -= $count;
2208                     }
2209 
2210                     break;
2211                 case '/*':
2212 
2213                     if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count))
2214                     {
2215                         $skip = strlen($m[0]);
2216                         $newlines = substr_count($m[0], "\n");
2217                     }
2218 
2219                     break;
2220             }
2221 
2222             if ($skip == 0)
2223             {
2224                 $count += strlen($min[0]);
2225             }
2226 
2227             $out .= substr($text, 0, $count) . str_repeat("\n", $newlines);
2228             $text = substr($text, $count + $skip);
2229 
2230             $min = null;
2231         }
2232 
2233         return $out . $text;
2234     }
2235 }
2236 
Joomla! Framework TM API documentation generated by ApiGen 2.8.0
Joomla!® and Joomla! Framework™ are trademarks of Open Source Matters, Inc. in the United States and other countries.