Compare commits

...

487 Commits

Author SHA1 Message Date
Sebastiaan Janssen 7ffb73e467 Updates Examine dependency 2015-04-23 16:45:24 +02:00
Sebastiaan Janssen 57c3665d0f Show different ReadMe for fresh install vs. upgrade installs 2015-04-23 16:01:23 +02:00
Sebastiaan Janssen 8037f929aa Ignore more slow tests 2015-04-23 15:35:42 +02:00
Sebastiaan Janssen fec3e57ed6 Ignore tests that don't run to completion on slower build server 2015-04-23 15:19:18 +02:00
Sebastiaan Janssen 5106ffab97 Mark as Release Candidate 2015-04-23 15:00:12 +02:00
Sebastiaan Janssen 9f569171c3 Suppress error (it's useless information) 2015-04-23 14:59:13 +02:00
Sebastiaan Janssen d607041ca4 U4-6450 Creating Partial View Macro without 'Create Macro' selected still tries to create a macro
#U4-6450 Fixed
2015-04-23 14:55:57 +02:00
Sebastiaan Janssen b3daf7f55d Merge branch 'dev-v7-xmllock' into dev-v7 2015-04-23 14:23:23 +02:00
Sebastiaan Janssen a77d3bc4ac Adds some more defaults tests 2015-04-23 14:22:42 +02:00
Stephan c4aa87d73d Backport Xml concurrency fixes 2015-04-13 19:12:03 +02:00
Stephan 57909489cb AsyncLock - import 2015-04-13 19:12:00 +02:00
Shannon c78b371965 updates the BackgroundTaskRunnerAwaiter so that it exits if the runner is not running when it is ctor'd, adds diags. 2015-04-09 17:59:34 +10:00
Shannon c525be3e44 Completes: U4-6474 Update to latest examine v0.1.62 2015-04-09 15:33:58 +10:00
Shannon cc804bd3bd removes duplicate test 2015-04-08 17:57:00 +10:00
Shannon 24dc8309f1 sets ConfigureAwait(false) for XmlCacheFilePersister await calls and BackgroundTaskRunner await calls since these are always on background threads, no synchronizing with any context. 2015-04-08 17:15:21 +10:00
Shannon ce81f9b1b1 we'll try these tests again 2015-04-08 17:08:06 +10:00
Shannon 3f70761d49 this should fix one of the tests 2015-04-08 17:01:38 +10:00
Shannon dee45146a4 applies a max timout for BackgroundTaskRunnerTests 2015-04-08 16:55:34 +10:00
Shannon b35397b464 uses property type ctor overload to accept an alias which prob should have been there all along since in most cases you need an alias to create one (same prob goes for property groups, etc... but oh well). Adds a couple tests for case insensitive comparisons in PropertyCollection 2015-04-08 16:33:16 +10:00
Shannon 147cc92ac5 Updates BackgroundTaskRunner & tests: removes the need for most Thread.Sleep which is error prone, this is done by updating the GetAwaiter() method to be a custom awaiter so we can await the entire background task running operations. We then add a property called CurrentThraedingTask which then allows awaiting the current Task instance. Adds error handling to all event handlers for the task runner. Changes events to be TypedEventHandlers 2015-04-08 16:28:42 +10:00
Shannon 3230fce76a fixes lock on PropertyCollection, should just be a normal lock 2015-04-08 11:47:16 +10:00
Shannon 1d22c1e81e fixes get hash code on Entity base class 2015-04-08 11:47:00 +10:00
Shannon ece2e2359e Updates PropertyGroup's equality comparisons to: check the base comparison, then check for a case insensitive comparison with name, fixes GetHashCode to be consistent with the Equals method. 2015-04-08 11:31:14 +10:00
Shannon 8cbe53f49d Updates PropertyType to have a ctor overload accepting an alias when one already exists. Updates it's equality comparisons to: check the base comparison, then check for a case insensitive comparison with alias, fixes GetHashCode to be consistent with the Equals method. 2015-04-08 11:30:35 +10:00
Shannon Deminick cac3ddc3c8 Merge pull request #666 from JimBobSquarePants/dev-v7
Remove Content Service Setter case sensitivity
2015-04-08 10:07:34 +10:00
Shannon 0eac50ceba Fixes: U4-6506 Grid config in package.manifest doesn't allow for multiple grid editors and adds tests 2015-04-07 17:24:35 +10:00
Shannon d5e735ac14 Fixes singleton accessors and adds ctor which would allow unit testability. 2015-04-07 12:07:54 +10:00
Shannon Deminick 8d841d3537 Merge pull request #667 from AndyButland/u4-1733
U4-1733 - Added overloads to RedirectToUmbracoPage methods to allow passing of a querystring
2015-04-07 11:05:05 +10:00
Sebastiaan Janssen 5f175874b2 Fixes tests and adds a few 2015-04-02 17:52:59 +02:00
Sebastiaan Janssen fa053426c3 Don't disableFindContentByIdPath when in preview mode 2015-04-02 17:16:56 +02:00
AndyButland 437e7f0ffc Removed unused usings from previous commit 2015-04-01 23:29:43 +02:00
AndyButland afa6c35bb5 Added overloads to RedirectToUmbracoPage methods to allow passing of a querystring 2015-04-01 23:27:20 +02:00
James South 8d00dbf648 Remove Content Service Setter case sensitivity
Makes property alias key checking case-insensitive bringing behaviour in
line with IPublishedContent getters.
2015-04-01 12:37:28 +01:00
Stephan cd26a1ad21 U4-6479 - fix GetCulture for unpublished content + add tests 2015-04-01 12:59:01 +02:00
Shannon 437ab4aaf1 Fixes installer permission steps - this cannot just arbitrarily write to the umbraco xml cache file 2015-04-01 17:44:27 +11:00
Shannon 051e9366e5 updates js undefined check 2015-04-01 13:39:54 +11:00
Shannon Deminick 46c6503320 Merge pull request #665 from magnuskragelund/dev-v7-U4-6469-mntp-referencing-deleted-nodes
fixes bug when trying to render a deleted node in multinode tree picker
2015-04-01 13:36:18 +11:00
Shannon 1cf2fc7870 updates sln docs and removes pdf test bits 2015-04-01 11:22:10 +11:00
Shannon cf1c38dcaa fixes build 2015-03-31 17:04:32 +11:00
Shannon 73d7cd4856 updates sln file to remove the PDF proj and removes the sln folder containing umbraco examine libs 2015-03-31 14:27:18 +11:00
Shannon 1b87fd074c Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-03-31 13:49:39 +11:00
Shannon 33f21e0528 Updates build and solution to exclude UmbracoExamine.PDF, removes files for UmbracoExamine.PDF, updates links to license in nuspec files 2015-03-31 13:49:28 +11:00
Sebastiaan Janssen 0b5a2452c2 U4-6476 Examine Issue: The CancellationTokenSource has been disposed.
#U4-6476 Fixed Due in version 7.2.5
2015-03-30 14:38:59 +02:00
Shannon cc8962f090 Removes the old umbracoexamine.azure libs 2015-03-30 20:07:26 +11:00
Shannon f6b9fdba72 Removes old docs folder 2015-03-30 20:06:51 +11:00
Shannon e0effec3b4 fixes pdf build to only have it's required files in the zip 2015-03-30 19:13:13 +11:00
Shannon 76a2f433d9 simplifies build since we don't have the examine azure stuff 2015-03-30 18:42:47 +11:00
Shannon a2bfca4d3a Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-03-30 17:40:46 +11:00
Shannon fb24becd0d completes: U4-6468 Move all 'Strategies' in the Web project that performs Core data operations to the Core project 2015-03-30 17:40:36 +11:00
Shannon 58857c5d83 Moves publishing strategies into CacheRefresherEventHandler where the event handlers are supposed to exist. 2015-03-30 17:36:54 +11:00
Shannon 7a31d6cae3 better exception logging for examine 2015-03-30 17:23:28 +11:00
Shannon Deminick 021bb6d367 Merge pull request #661 from kgiszewski/dev-v7
Fix for U4-6462
2015-03-30 16:27:19 +11:00
Shannon Deminick 0742108ec1 Merge pull request #662 from AndyButland/u4-6412
U4-6412 - Ensures footer breadcrumb in content and media returned in correct order
2015-03-30 10:44:08 +11:00
Magnus Kragelund 1c3a7b95fc fixes bug when trying to render a deleted node in multinode tree picker 2015-03-27 11:02:35 +01:00
Shannon fda72b2acc changes the MaxWaitMilliseconds tp 30000 to be consistent with the 7.3 branch 2015-03-27 15:19:31 +11:00
Shannon ec742d1f66 removes the usages of ILogger and ProfilerLogger since this is not for 7.3.0, will need to re-fix for 7.3 branch. 2015-03-27 14:56:12 +11:00
Shannon 4bdac1475f fixes log scrub interval with ms with updated background tasks 2015-03-27 14:52:38 +11:00
Stephan 58ce04e26b cleanup 2015-03-27 14:49:31 +11:00
Shannon 4c3de920c6 Removes the 'else' so that 'wait' is always checked. 2015-03-27 14:49:31 +11:00
Stephan be37026587 refactor latched background tasks, now use a task for xml
Conflicts:
	src/Umbraco.Web.UI/config/ClientDependency.config
2015-03-27 14:49:25 +11:00
Stephan a73b7a5849 refactor Scheduler to use new BackgroundTaskRunner capabilities
Conflicts:
	src/Umbraco.Web/Scheduling/Scheduler.cs
2015-03-27 14:48:47 +11:00
Stephan b7436dc55f refactor BackgroundTaskRunner 2015-03-27 14:47:42 +11:00
Shannon bc068b201d Updates BackgroundTaskRunner to ensure canceled or skipped tasks are disposed, updated tests to reflect 2015-03-27 14:47:42 +11:00
Shannon 912b01c9aa Updates BackgroundTaskRunner to support more complex options including the ability to only execute the last/final task in the queue. Added tests to support, updated the 'content' object to use this option so that only the last task in the queue will execute so that file persisting doesn't get queued but the correctly queued data will be written. 2015-03-27 14:47:42 +11:00
Shannon a82035061c Updates BackgroundTaskRunner to support async operations. Updates the content xml cache file persisting to use a IBackgroundTask instead of the strange queuing for persistence - which was super strange because in many cases another request thread will actually be the thread that is persisting the xml file than the request thread that requested it created. This implementation is far better, the xml file will be persisted on a non request thread and will handle multiple documents being published at the same time guaranteeing that the latest published version is the one persisted. The file persistence is also web aware (due to how BackgroundTaskRunner works) so during app shutdown the file will still be written if it's currently being processed. 2015-03-27 14:47:41 +11:00
AndyButland 0c107fd869 Ensures footer breadcrumb in content and media returned in correct order 2015-03-25 21:52:39 +01:00
kgiszewski 6419f301f7 Fix for U4-6462 2015-03-25 16:30:47 -04:00
Sebastiaan Janssen e775471013 Set disableFindContentByIdPath=false for local debugging of Umb source (the release config was already correct) 2015-03-25 17:08:53 +01:00
Shannon Deminick cc109d1ed0 Merge pull request #660 from perosb/U4-6444
Fix for U4-6444
2015-03-25 09:16:49 +11:00
Sebastiaan Janssen 9dfccd86fd U4-2499 Remove the possibility for accessing pages with nodeid's or give a redirect option
#U4-2499 Fixed Due in version 7.2.5
2015-03-24 20:09:48 +01:00
Per Osbeck ffaf1f96b9 Fix for U4-6444 2015-03-24 09:28:53 +01:00
Shannon Deminick aa3c1d645b Merge pull request #659 from robertjf/dev-v7
Issue#U4-6448 typo fix in pageIndex Mandate checks
2015-03-24 12:45:35 +11:00
Robert Foster c6b393f2e8 typo fix in pageIndex Mandate checks 2015-03-24 12:30:28 +11:00
Shannon Deminick 344d909e6b Merge pull request #657 from webprofijt/packageinstaller-spelling
Fix some spelling mistakes in package installer
2015-03-23 09:45:56 +11:00
Arnoud de Vries e3925f18ef Fix some spelling mistakes in package installer 2015-03-22 16:29:53 +01:00
Sebastiaan Janssen 53a4d063e0 U4-464 The embedded passwordStrength.js file is GPL-licensed
#U4-464 Fixed Due in version 7.2.5
2015-03-22 13:13:51 +01:00
Sebastiaan Janssen 907e5e7ca4 Bump version 2015-03-20 11:25:59 +01:00
Sebastiaan Janssen 94e281e951 Merge branch '7.2.4' into dev-v7 2015-03-20 11:23:30 +01:00
Sebastiaan Janssen 03b60d4923 "It's simple until you make it complicated"
- So now this logic has been un-complicated: look for the web.config file, if it exists and has a umbracoConfigurationStatus appSetting then don't overwrite the web.config, the user is upgrading umbraco and config transforms can do their thing. Otherwise, copy in a fresh web.config with all the required Umbraco bits.
2015-03-20 10:35:41 +01:00
Shannon 27e96d6d5b Fixes: U4-6436 Localization in the back office doesn't work immediately after app restart 2015-03-20 10:35:34 +01:00
Shannon d2b4345773 Fixes: U4-6433 Usercontrol loaded after package installation not executing 2015-03-20 10:35:23 +01:00
Sebastiaan Janssen c5bbf97921 Bump version 2015-03-20 10:35:14 +01:00
Sebastiaan Janssen 8c4eba7837 "It's simple until you make it complicated"
- So now this logic has been un-complicated: look for the web.config file, if it exists and has a umbracoConfigurationStatus appSetting then don't overwrite the web.config, the user is upgrading umbraco and config transforms can do their thing. Otherwise, copy in a fresh web.config with all the required Umbraco bits.
2015-03-20 10:16:53 +01:00
Shannon 08a2ec6883 Fixes: U4-6436 Localization in the back office doesn't work immediately after app restart 2015-03-20 18:15:31 +11:00
Shannon b02e0c0232 Fixes: U4-6433 Usercontrol loaded after package installation not executing 2015-03-20 17:47:33 +11:00
Shannon fff0151b62 Updates build process to: Ensure the AssemblyFileVersion is set to the real umbraco version, AssemblyInformationalVersion is set to the real umbraco version including the pre-release name if there is one, AssemblyCopyright has the correct year. 2015-03-20 09:31:14 +11:00
Sebastiaan Janssen 90fdbb007e Bump version 2015-03-19 14:45:00 +01:00
Per Ploug 19e4fe5059 Grid labels header colors for delete and move actions 2015-03-19 14:33:12 +01:00
Sebastiaan Janssen 311d503d8b Updates CDF dependency to latest version 2015-03-19 12:54:00 +01:00
Per Ploug f0fc3313e4 Tweaked borders a tiny bit 2015-03-19 12:46:29 +01:00
Per Ploug dc7cb08824 Styling for grid editors + row labels 2015-03-19 12:29:05 +01:00
Stephan 5ddcf42bc3 U4-3753 - keep some things internal 2015-03-19 09:37:39 +01:00
Shannon af112f6b20 Adds nicer grid editor labels on hover 2015-03-19 17:08:14 +11:00
Shannon cbef51eaf0 Fixes: U4-6294 Feature Request 7.2.1 Grid - UX - labeling the grid editors - but will see if we can do a better job of the labeling 2015-03-19 16:10:46 +11:00
Shannon 85ba41dd06 Fixes: U4-5435 Dropdown list multiple, publish keys - single item 2015-03-19 15:50:58 +11:00
Shannon e5cf7b089c oops, added timeouts where they cannot exist for request cache, fixes build 2015-03-19 14:47:08 +11:00
Shannon 5fae61b196 Merge branch 'mattbrailsford-7.2.1-configurablemacrogrideditor' into dev-v7 2015-03-19 14:34:00 +11:00
Shannon db5c204d8c Merge branch '7.2.1-configurablemacrogrideditor' of https://github.com/mattbrailsford/Umbraco-CMS into mattbrailsford-7.2.1-configurablemacrogrideditor 2015-03-19 14:33:36 +11:00
Shannon b9082cf390 Fixes our usages of GetCacheItem so that there is a timeout, this is needed otherwise memory won't be given back unless memory gets too high where in fact for most of these we want to give it back as soon as possible if it isn't being used. 2015-03-19 14:00:48 +11:00
Shannon 9469b0b844 Fixes: U4-6402 Grid config file should be merged with package.manifests & U4-6427 Grid config file has caching problems because it's downloaded as a static file
This also fixes up the OutputCaching params on the BackOfficeController since OutputCache is bypassed when an action requires authentication, so now we manually do some caching when not in debug mode for authorized actions (of course auth happens before any cached response can occur). This also fixes up the static caching that was happening with the ManifestBuilder so now when that is not in use it gives back it's memory. This also fixes up any client side caching that was happening on BackOfficeController - before we were allowing client cache to happen for a few actions on that controller which is incorrect, we need to disable all client cache for all actions on that controller.
2015-03-19 13:53:15 +11:00
Shannon 5737cdfbe2 Fixes the way HttpResponseMessages are created - they should always be created with Request.CreateReponse! 2015-03-19 12:03:55 +11:00
Shannon 1a082464e9 Fixes: U4-5127 AssetService does not support virtual paths (~/) - and fixes up some formatting 2015-03-19 11:44:37 +11:00
Shannon e004ad31b5 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7
Conflicts:
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js
2015-03-19 11:36:05 +11:00
Shannon 6cf25f0043 Fixes: U4-6428 Grid configuration does not support virtual paths - and therefore is not compatible with virtual directories 2015-03-19 11:35:04 +11:00
Shannon Deminick c0f50a4c1b Merge pull request #656 from ProfessorFarnsworth/U4-6419
fixed issue U4-6419 by removing that character
2015-03-19 10:05:25 +11:00
Sebastiaan Janssen 00fbc6dfcb Revert "Fixes broken bower jquery reference"
This reverts commit c2cfd26ee6.
2015-03-18 13:05:21 +01:00
Per Ploug 3a9ad91f8f Adds better error handling to missing grid editors 2015-03-18 11:45:22 +01:00
Per Ploug c2cfd26ee6 Fixes broken bower jquery reference 2015-03-18 11:45:04 +01:00
Per Ploug c5f26c7c15 Fixes: U4-6331 The grid tools overlay disable the links/buttons on smaller screens 2015-03-18 11:44:49 +01:00
Helmuth Bederna f742c0a958 fixed issue U4-6419 by removing that character 2015-03-18 10:41:15 +01:00
Shannon Deminick 8cefe22bee Merge pull request #649 from protherj/grid-rendering-quote-fix
Changed the surrounding quotes for Grid custom settings/styles to be double quotes
2015-03-18 19:55:32 +11:00
Shannon fad3599f50 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-03-18 19:52:56 +11:00
Shannon 37b219f6e1 Fixes: U4-4942 Widget disappears in RTE when there is a space in the macro alias 2015-03-18 19:52:45 +11:00
Sebastiaan Janssen 4e9667a067 Don't forcibly remove System.Web.Helpers.dll during upgrades in case people have it already and packages rely on it 2015-03-18 09:49:18 +01:00
Shannon Deminick 300a46f1b2 Merge pull request #613 from gildebrand/patch-4
parseMacroSyntax accepts other characters than a-z
2015-03-18 19:17:33 +11:00
Shannon 9aa5df43bf Fixes: U4-5956 Feature request: Enhance the preview mode with labels clearly explaining the current view 2015-03-18 19:14:47 +11:00
Shannon 02b0e4dd6a Fixes: U4-6380 ClientDependency Bug on server - Can't Access Backoffice 2015-03-18 19:06:41 +11:00
Shannon 9c1d3fabb8 Fixes: U4-6418 Loading back office with ClientDependency does not respect the configured value for the compositeFileHandlerPath 2015-03-18 19:04:49 +11:00
Shannon e9e84a7faa Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-03-18 19:03:57 +11:00
Shannon 137d8553de Fixes: U4-6417 When including a $schema element in package.manifest with a url schema, the regex will incorrectly strip required characters 2015-03-18 19:03:46 +11:00
Sebastiaan Janssen 7210c6cd95 U4-6384 Incorrect Error Message When Uploading Large File
#U4-6384 Fixed Due in version 7.2.3
2015-03-17 17:59:24 +01:00
Stephan 6856f9f341 Merge pull request #654 from umbraco/U4-274-disable-alttemplate
U4-274 - Adds config option to disable alternative templates
2015-03-17 14:32:08 +01:00
Sebastiaan Janssen d24ef3650e U4-274 - Adds config option to disable alternative templates 2015-03-17 13:50:33 +01:00
Shannon 2feef247ed Fixes: U4-3562 Cannot preview when no template is assigned 2015-03-17 19:31:46 +11:00
Stephan 4974e2a2ce U4-6306 - hostname validation issue 2015-03-16 10:52:54 +01:00
Stephan 3eb0dac48a U4-3753 - fix the build 2015-03-16 09:28:24 +01:00
Stephan a44b19da18 U4-6320 - fix default scrubbing interval, set to 4hrs 2015-03-16 09:16:28 +01:00
Shannon Deminick 3ee4234968 Merge pull request #653 from kgiszewski/dev-v7
Fix for U4-6395, U4-6117
2015-03-16 09:50:52 +11:00
kgiszewski f06a468fb4 Fix for U4-6395, U4-6117 2015-03-13 11:40:04 -04:00
Stephan 420c334af4 U4-3753 - refactor
Conflicts:
	src/Umbraco.Web/Umbraco.Web.csproj
2015-03-12 15:03:46 +01:00
Stephan 20b21c86ea U4-3753 - add a way to get the rendering culture of a content 2015-03-12 15:02:18 +01:00
Shannon d2083673be Fixes: U4-3420 Firefox v25.0 - Right click context menu doesn't work - this felt like being a web dev 10 years ago when you had to code totally differently for each browser. Firefox unfortunatley treats 'a' tags differently than anything else and combined with angular saying you can have empty 'href' tags doesn't work. In the end, the fix was easy, just remove the empty (supposed to be supported) href attributes from the 'a' tags in the tree, then the contextmenu starts working in firefox and the events can be canceled as per normal. This commit also moves the angular localization library to use bower. 2015-03-10 13:02:34 +11:00
Shannon fe40b8fe99 ok, fixes the null check for real this time. 2015-03-09 17:53:58 +11:00
Shannon dd477a0cbe whoops, fixes comparison on lazy val 2015-03-09 17:37:25 +11:00
Shannon 2834ccdc2b Fixes: U4-6344 TinyMCE RTE style_formats configuration changes 2015-03-09 17:31:29 +11:00
Shannon b3f6f48834 fixes ugly null check on ContentTypeSort comparison 2015-03-09 16:42:30 +11:00
Shannon 4544520b66 Fixes: U4-6303 SaveAndPublishWithStatus error - updates to latest Examine with the fix. 2015-03-09 15:06:32 +11:00
Shannon 017663833a Missing a fairly critical log entry 2015-03-06 16:54:55 +11:00
Shannon 9a5923771d fixes changing the underscore of a user language to culture. 2015-03-06 16:05:37 +11:00
Shannon 0932c980e9 Fixes: U4-6307 Incorrect culture assigned to user (missing region code) 2015-03-06 16:01:49 +11:00
Shannon 7e9261d4bc Updates member indexer to consume less memory on rebuild, iterates over collection already in memory and just adds nodes as the are iterated, before was re-adding to memory in order to do counts, now we iteratively count. 2015-03-06 13:36:52 +11:00
Shannon 0ce503b369 Fixes: U4-6349 Optimizing indexes says that the index is not optimized 2015-03-06 13:34:09 +11:00
Shannon Deminick 6d5d8fb39c Merge pull request #647 from hAmpzter/U4-6304
U4-6304 ContentTypeBaseRepository.MapContentTypes throws exception with ...
2015-03-05 17:49:48 +11:00
Shannon Deminick 9613772036 Merge pull request #648 from Jeavon/U4-6336
Fixes U4-6336 GetCropUrl - preferFocalPoint is ignored if focal point is...
2015-03-05 17:22:23 +11:00
Shannon Deminick 604779667d Merge pull request #650 from mikkelhm/dev-v7
U4-4080 Missing icons in context menu
2015-03-05 17:18:47 +11:00
Shannon 46212904ef Changes the SetPropertyValueAndDetectChanges to throw an exception if an Enumerable is passed in without using the overload the specifies an IEqualityComparer. Updates all entities that use this method with IEnumerables to specify the correct Equality comparer which now uses the new UnsortedSequenceEqual method. Added unit tests for new EnumerableExtensions and makes the ContainsAll work faster. 2015-03-05 17:08:58 +11:00
Shannon b7bb98d824 fixes localized text request when an invalid cookie is present 2015-03-05 17:04:02 +11:00
Shannon f31d2ca7cf Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-03-05 16:44:34 +11:00
Shannon 88ae95150e Fixes: U4-6342 UmbracoEnsuredPage doesn't work in 7.2.2 2015-03-05 16:36:06 +11:00
Sebastiaan Janssen 97a085d12b Bump version 2015-03-03 20:19:41 +01:00
Sebastiaan Janssen 74d0ec949d Delete bower_components folder before build else missing packages will sometimes not be downloaded 2015-03-03 19:43:19 +01:00
Shannon 9a042fbbdf Removes the assignment of the DefaultPermissions property since this is auto assigned in the ctor (and should be assignable) 2015-03-03 19:40:37 +11:00
Shannon 834b780d8e Removes change tracking for User.DefaultPermissions since it is entirely not necessary (and in fact shouldn't be settable). Also ensures that the cloning of the default permissions is a new list, wasn't doing this before... which might have been the culprit for strange thread issues. 2015-03-03 19:37:13 +11:00
Shannon 8905878a87 Adds some methods to TracksChangesEntityBase to enable/disable change tracking and to reset the change tracking dictionaries, this is then used for DeepCloning so that change tracking is turned off for the cloning process. 2015-03-03 18:33:04 +11:00
Shannon 36bed40db0 typo 2015-03-03 17:37:42 +11:00
Shannon f708a24401 fixes U4-6333, U4-6348 2015-03-03 17:36:53 +11:00
Shannon d32cf12c6f Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-03-02 17:02:35 +11:00
Shannon 100485f748 Fixes: U4-6005 Please add a public constructor to InstallApiController 2015-03-02 17:02:25 +11:00
Shannon 56017a340c makes PropertyEditorResolver faster by not having to re-union every time its accessed 2015-03-02 16:59:40 +11:00
Shannon 21c70462c9 publicizes cache extensions 2015-03-02 16:59:05 +11:00
Sebastiaan Janssen 9b254f8bf9 Previous commit added a IApplicationStartupHandler which broke the count in this unit test 2015-03-01 14:09:35 +01:00
Sebastiaan Janssen 6dd63e8a01 U4-6341 Relate document on copy doesn't create a relation record in umbracoRelations table
#U4-6341 Fixed Due in version 7.2.3
2015-03-01 13:52:02 +01:00
mikkelhm bac940d4ed U4-4080 Missing icons in context menu for relation types, update comments aswell 2015-02-28 22:19:17 +01:00
mikkelhm c1c090faab U4-4080 Missing icons in context menu for relation types 2015-02-28 22:16:07 +01:00
Jason Prothero 32bedfaa6a Changed the surrounding quotes for Grid custom settings/styles to be double quotes 2015-02-27 10:06:45 -08:00
Jeavon Leopold b003c027e5 Removed unused "using" references in cropper extension methods 2015-02-27 14:49:36 +00:00
Jeavon Leopold 0295aaba3b Added test for U4-6336 GetCropUrl - preferFocalPoint is ignored if focal point is in the center 2015-02-27 14:42:00 +00:00
Jeavon Leopold bb04f83a49 Fixes U4-6336 GetCropUrl - preferFocalPoint is ignored if focal point is in the center 2015-02-27 12:15:28 +00:00
hAmpzter 793ba42f9e U4-6304 ContentTypeBaseRepository.MapContentTypes throws exception with SByte / Bool type with Mysql.
Force it with Convert.ToBoolean()
2015-02-27 12:42:55 +01:00
Shannon ded1def8e2 Fixes: U4-6333 - but should fix this better (i.e. centralize the code to clean for xss in JS like we have in c#) 2015-02-27 16:50:33 +11:00
Shannon 5a2a3c3b1e removes duplicate attribute 2015-02-27 01:04:53 +01:00
Sebastiaan Janssen 6f2fa2ed4d Makes sure that the version comment gets cleared when there is no comment. 2015-02-26 12:38:03 +01:00
Shannon 7dad078af4 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-02-20 09:43:28 +01:00
Shannon 9a89b6048a Merge branch '7.2.0_U4-5236' of https://github.com/bjarnef/Umbraco-CMS into bjarnef-7.2.0_U4-5236
Conflicts:
	src/Umbraco.Web.UI.Client/src/less/tree.less
2015-02-20 09:43:21 +01:00
Shannon Deminick 8c13b89c79 Merge pull request #637 from xumix/6.2.5
Fix dictionary key access
2015-02-20 09:36:20 +01:00
Shannon d54e09c40b fixes jjj - no idea what happened there 2015-02-20 09:12:30 +01:00
Shannon c0d6c511e4 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-02-19 14:55:08 +01:00
Shannon 2da3ec27db fixes punycode reference 2015-02-19 14:55:00 +01:00
Sebastiaan Janssen 5f10ed99aa Revert "U4-4565 Add margin to bottom bar"
This reverts commit c1cc8a3824.
2015-02-19 14:14:30 +01:00
Shannon Deminick 48fa60039b Merge pull request #641 from AussieInSeattle/U4-6288
U4-6288 Changes
2015-02-19 11:56:23 +01:00
Shannon 20ceceffe0 Fixes: U4-5932 Grid editor has JS errors 2015-02-19 11:43:08 +01:00
Shannon b73c7fbb16 Fixes: U4-6284 UmbracoCms.7.2.2-build.26 - missing feedback when file is too large 2015-02-19 11:34:43 +01:00
Shannon c96b866f1d Fixes bower config for jquery 2015-02-19 10:35:06 +01:00
Sebastiaan Janssen b724a185b7 Pushes the ascii art down one line as it looked a bit weird because the cursor is on the first line by default after installing 2015-02-19 09:37:56 +01:00
Sebastiaan Janssen f94d280e27 Removes unnecessary dummy files. Some directories are old and not needed, plus they all get created on app startup anyway. 2015-02-19 09:23:07 +01:00
Shannon b2399e97cc updates cdf refs 2015-02-18 17:39:33 +01:00
Shannon 5580523c08 Merge remote-tracking branch 'origin/dev-v6' into dev-v7
Conflicts:
	build/NuSpecs/UmbracoCms.Core.nuspec
	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
	src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
	src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
	src/Umbraco.Core/Umbraco.Core.csproj
	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
	src/Umbraco.Web.UI/packages.config
	src/Umbraco.Web/Umbraco.Web.csproj
	src/Umbraco.Web/packages.config
	src/umbraco.cms/packages.config
	src/umbraco.cms/umbraco.cms.csproj
	src/umbraco.controls/packages.config
	src/umbraco.controls/umbraco.controls.csproj
	src/umbraco.editorControls/packages.config
	src/umbraco.editorControls/umbraco.editorControls.csproj
	src/umbraco.macroRenderings/packages.config
	src/umbraco.macroRenderings/umbraco.macroRenderings.csproj
2015-02-18 17:34:35 +01:00
Shannon 6670f7036b publicizes RouteDefinition 2015-02-18 17:30:44 +01:00
Shannon a59dd32dd1 Updates cdf refs 2015-02-18 09:15:07 +01:00
AussieInSeattle ee78e3815b U4-6288 Changes 2015-02-17 19:32:25 -08:00
Shannon 2acfd64706 Updates exif reader to an MIT licensed reader from https://code.google.com/p/exiflibrary 2015-02-17 16:47:29 +01:00
Shannon df3d8d3757 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-02-17 14:37:52 +01:00
Shannon a6f6a321f9 Fixes extension method finder and TypeHelper with Stephen's awesome code 2015-02-17 14:37:44 +01:00
Sebastiaan Janssen 03b0133b58 Merge branch 'Shazwazza-dev-v7-upgradablemvc5webapi2' into dev-v7 2015-02-17 10:46:58 +01:00
Sebastiaan Janssen 25cfceadc0 Merge branch 'dev-v7-upgradablemvc5webapi2' of https://github.com/Shazwazza/Umbraco-CMS into Shazwazza-dev-v7-upgradablemvc5webapi2
Conflicts:
	build/UmbracoVersion.txt
	src/Umbraco.Core/Configuration/UmbracoVersion.cs
2015-02-17 10:46:36 +01:00
Vilen Tambovtsev 03969fd687 Fix dictionary key access
Looks like someone does not know how to use a dictionary
2015-02-13 12:21:16 +03:00
Sebastiaan Janssen 7788452fb7 U4-6219 Visual Studio 2013 Crashes When Opening umbraco.sln
#U4-6219 Fixed
2015-02-13 10:04:35 +01:00
Shannon c7778467e3 Updates to latest examine version which internally supports tokenized paths in config so we don't need to do this in the umbraco core. 2015-02-13 15:34:54 +11:00
Shannon 0600d5c463 backports some updates made in the dist load balancing branch that allows for examine path storage by machinename and appdomainappid 2015-02-13 14:50:16 +11:00
Shannon 15c36a63d3 Fixes: U4-6168 Custom Section is not showing correctly in 7.2 if custom tree is empty 2015-02-13 12:35:57 +11:00
Shannon bcba12abc8 Fixes: U4-6268 TreeController cannot exist in App_Code 2015-02-13 11:50:42 +11:00
Shannon Deminick c0dd32d1f9 Merge pull request #625 from bjarnef/dev-v7-U4-4418
U4-4418 - fix issue with tab sorting
2015-02-13 11:13:46 +11:00
Shannon 2411271ae0 removes cancel button from related links as it is not needed and doesn't actually cancel due to two way binding. 2015-02-13 11:11:43 +11:00
Shannon Deminick c87d0a6430 Merge pull request #634 from andycyberian/U4-4198
U4 4198
2015-02-13 11:06:48 +11:00
Shannon c0051ba8cd fixes jshint warnings 2015-02-13 10:38:53 +11:00
Shannon 2cf590d9c9 Merge branch '7.2.1' of https://github.com/markusdrake/Umbraco-CMS into dev-v7 2015-02-13 10:36:41 +11:00
Shannon Deminick 2729da2c08 Merge pull request #630 from SorenA/SorenA-patch-1-rteformatting
RTE composite block and class formatting
2015-02-13 10:05:06 +11:00
Shannon 9046319dc9 fixes grid are you sure button style 2015-02-13 09:45:25 +11:00
Shannon Deminick fa27a37207 Merge pull request #636 from robbaman/u4-6208
Auto hide the 'Are you sure you want to delete' message on columns of a grid
2015-02-13 09:34:02 +11:00
Shannon 80f81ce379 fixes: U4-6255 Add configurable option in base membership providers to toggle AllowManuallyChangingPassword 2015-02-12 15:58:11 +11:00
Shannon 3022293565 re-wires up the input file fields 2015-02-12 15:43:41 +11:00
Shannon 34889c147a Updates the media picker dialog to use the new directives, fixes: U4-6257 for it's drop zone, adds a drag over ui indicator, shows progress bar for uploading. 2015-02-12 15:25:49 +11:00
Shannon 7d17aef953 Streamlines image upload directives for more re-use, creates umbImageUpload directive which is a wrapper for the blueimp file-upload directive which allows us to have a directive that exposes an API (which the blue imp does not do), creates new upload progress directive so that can easily be re-used inside of any umbimageupload directive. 2015-02-12 14:40:15 +11:00
Shannon 8af8a6d411 Makes a new umbImageFolder directive which can be easily shared and is now used by the dashboard and the folder browser. 2015-02-12 11:59:19 +11:00
Robert Mulder dd736dce3a Hide the 'Are you sure you want to delete' message on columns of a grid when mouse-leaving them just like it does on the similar message on the row level. This way they messages work the same for both rows and columns. 2015-02-11 10:18:51 +01:00
Shannon cd4c738c04 Moves jquery and blueimp files to be included with bower, removes all unnecessary jquery files that are committed to the repo. Jquery and jquery ui versions remain the same, however the canvas designer was using a jquery ui version one patch version ahead so need to test that it works with the bower version, otherwise we'll have to re-include it. 2015-02-11 18:39:53 +11:00
Shannon ed383bdaeb Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-02-11 18:24:01 +11:00
Shannon 4874a71e72 fixes publish button so it saves properly without causing js errors 2015-02-11 18:23:49 +11:00
Sebastiaan Janssen 58b8aacff1 Fixes U4-6052 Umbraco 7.2.1 web app installed with Nuget fails at start with error :"Cannot create an MVC Area path without the umbracoPath specified"
#U4-6052 Fixed Due in version 7.2.2
2015-02-10 17:38:19 +01:00
Sebastiaan Janssen d4d5a355e3 Update CDF dependency 2015-02-10 15:08:27 +01:00
Shannon 24ef0dd961 fixes small issue with the image layout when viewing media folder, in some cases when there are consecutive small images that when placed beside each other cannot fit the width, they'll end up individually on a row due to their small size, this fix allows for a leniency when fitting to the width so in these cases they'll get rendered together on the row even though they won't actually fit. 2015-02-10 17:31:31 +11:00
Shannon 0efb9b72e7 Adds small exif library to read meta data from jpg's so we can attempt to read width/height from exif instead of loading the file into mem with GDI, makes for much faster and far less memory processing.U4-6246 Uploading specific images causes GDI+ Errors 2015-02-10 16:33:59 +11:00
Shannon Deminick dd680b6fd1 Merge pull request #635 from NathalieLarsson/dev-v7
Changes to lang config, notifications area - Sv
2015-02-10 10:54:03 +11:00
Nathalie Larsson 788ed68b5b Changes to lang config, notifications area - Sv 2015-02-09 15:47:16 +01:00
Shannon 89606d3a05 Goes brute force to try to resolve: U4-4049 Some images fail when uploading multiple media files 2015-02-06 11:19:52 +11:00
Andy Rose 77319301c6 U4-4198, adding a specific save event to ensure that the related links title property is updated with its caption property 2015-02-05 09:19:47 +00:00
Andy Rose 227bd1cd7e Revert "U4-4198, adding a hidden field in the related links property editor to maintain the title property when editing. This will be mapped directly to the caption property value."
This reverts commit 68ac167ec3.
2015-02-05 09:18:48 +00:00
Sebastiaan Janssen 4790dc59a9 Update CDF dependency 2015-02-05 09:01:42 +01:00
Stephan de53dbffd1 U4-6129 - fix order of EntityService.GetByIds items 2015-02-04 19:07:51 +01:00
Andy Rose 68ac167ec3 U4-4198, adding a hidden field in the related links property editor to maintain the title property when editing. This will be mapped directly to the caption property value. 2015-02-04 16:30:14 +00:00
Stephan c8087d1f68 Cleanup TypeHelper, add tests - IsAssignableFromGeneric may have issues? 2015-02-04 17:05:18 +01:00
Shannon c4c21b8b6e fixes: U4-6151 Datatype PreValues not updated in Datatype Saved Event 2015-02-04 13:35:22 +11:00
Shannon a7c134a375 fixes last failing test 2015-02-04 12:11:10 +11:00
Shannon 9cdea752e8 Updates ExtensionMethodFinder to use new TypeFinder methods, all tests are passing now. Moved Stephen's MatchType methods to TypeHelper and moved those tests to TypeHelperTests. Now, need to compare notes with Stephen and add more tests to validate/invalidate the aproaches taken to see what might not be supported between either approaches and should probably look into benchmarks too. 2015-02-04 10:24:09 +11:00
Shannon de3c836ac1 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7
Conflicts:
	src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
	src/Umbraco.Tests/DynamicsAndReflection/ExtensionMethodFinderTests.cs
2015-02-04 09:58:48 +11:00
Stephan 2cdc89297f U4-6210 - fix failing tests, improve extension methods support on dynamics 2015-02-03 19:38:14 +01:00
Shannon 839a5b13b0 updates extension method finder with tests to better support finding generic equivialents, adds tests for TypeHelper as well. 2015-02-03 20:23:05 +11:00
Shannon 40cc4b90fc updates a test 2015-02-03 14:41:43 +11:00
Shannon ba54f96efd updates nuspec 2015-02-03 13:16:30 +11:00
Shannon f4a0bcfc96 updates nuspec 2015-02-03 13:15:15 +11:00
Shannon Deminick b5696de71e Merge pull request #629 from AndyButland/u4-6183
U4 6183 - Only allow change document type to types that would allow the existing children to be created under them
2015-02-02 18:16:37 +11:00
Stephan a4d4cbd99f U4-6034 - issue when renaming tabs 2015-01-30 15:02:21 +01:00
Stephan 08a2c0d082 U4-6184 - pipeline falls back from example.com:666 to example.com 2015-01-30 14:44:47 +01:00
Shannon f037f8541c Fixes: U4-6210 ExtensionMethodFinder doesn't work with overloaded extensions - this means overloaded extension methods for dynamic content won't work. and finalizes: U4-6209 GetGridHtml needs to be an extension on HtmlHelper not IPublishedContent so that ViewData and ModelState are inherited 2015-01-30 19:04:39 +11:00
Shannon 10990e50e6 Fixes: U4-6209 GetGridHtml needs to be an extension on HtmlHelper not IPublishedContent so that ViewData and ModelState are inherited 2015-01-30 15:48:55 +11:00
Shannon 9dad4c9573 Fixes: U4-6111 GetGridHtml throws an exception if no grid value is available 2015-01-30 15:42:12 +11:00
Shannon 6318b85449 Fixes: U4-6208 Cannot cancel grid 'Are you sure' button when deleting a cell, U4-5942 Issue with placing cursor in right part of richtext editor in Grid 2015-01-30 15:17:13 +11:00
Shannon Deminick 9d313898d0 Merge pull request #624 from bjarnef/dev-v7-U4-5942
U4-5942 - change width of grid cell tools
2015-01-30 11:09:33 +11:00
Shannon 0380b04b03 fixes breadcrumb on content/media, ensures a request to load it doesn't happen if there is no parent, ensures that the full breadcrumb is shown and in the right order and ensures that the breadcrumb class is not added if there isn't one so the margins on the buttons work better. 2015-01-30 11:07:47 +11:00
Shannon f32e47a363 fixes exception when rendering macros in rte in back office. 2015-01-30 10:59:11 +11:00
Shannon Deminick 3ea7f8a226 Merge pull request #628 from sparkalyn/dev-v7
Fixes: U4-4565 Add margin to bottom bar
2015-01-30 10:37:12 +11:00
Shannon 2617016e3b Merge branch 'umbUkFest-U4-4400' of https://github.com/ja0b/Umbraco-CMS into dev-v7 2015-01-30 10:33:07 +11:00
Shannon 90b3bf59e0 Fixes: U4-2038 Violation of PRIMARY KEY constraint 'PK_cmsContentPreviewXml' YSOD occurs when publishing content
Conflicts:
	src/Umbraco.Core/Umbraco.Core.csproj
2015-01-30 10:32:46 +11:00
Shannon aadae6334b Fixes: U4-2038 Violation of PRIMARY KEY constraint 'PK_cmsContentPreviewXml' YSOD occurs when publishing content
Conflicts:
	src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
	src/Umbraco.Core/Umbraco.Core.csproj
2015-01-30 10:13:04 +11:00
Shannon 0f7b902bba Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-01-29 17:50:18 +11:00
Shannon b899ab6557 Fixes: U4-5834 Change password description text is confusing 2015-01-29 17:49:58 +11:00
Shannon Deminick 7c3ff7d746 Fixes: U4-6165 Make Enum<T> public 2015-01-29 17:09:04 +11:00
SorenA 332a95a27a Support for multiple RTE classes
Added support for multiple RTE classes, "p.someclass.otherclass" would give a paragraph element with the classes "someclass" and "otherclass".
2015-01-28 11:42:08 +01:00
SorenA 4482879fc6 Added RTE composite block and class formatting
Added "block.class" and "block#id" formatting to the Rich Text Editor.

Example use include following formats:
"p.lead"
"h1#title"

Without this only "p" or ".lead" will work, not composites.
2015-01-28 11:38:11 +01:00
AndyButland 199bf0ff6e Minor code tidy of change content type 2015-01-28 09:22:33 +01:00
AndyButland 24915163ff Improved validation label for why a change of document type isn't available for a given node 2015-01-28 09:10:22 +01:00
AndyButland 1289d3255c Presentation improvements for confirmation page of change document type 2015-01-27 22:35:17 +01:00
AndyButland dc40b73fef When changing document type, added filter on populating list of available document types to include only those types that would permit the existing children to be created under them 2015-01-27 22:34:57 +01:00
Sunshine Lewis c1cc8a3824 U4-4565 Add margin to bottom bar 2015-01-27 09:57:51 -05:00
mattbrailsford 9c8e6ab864 Add "config" support to the macro grid property editor to allow predefining the macro to use 2015-01-26 12:35:01 +00:00
Stephan 9695ccea0a Merge pull request #623 from zpqrtbnk/dev-v7-6154
U4-6154 - fix unpublishing a document with changes
2015-01-21 16:03:33 +01:00
Shannon bbcca7f3e5 fixes test 2015-01-21 13:26:09 +11:00
Stephan 7b4a82eb8d U4-6154 - bugfix 2015-01-20 19:58:57 +01:00
bjarnef 8393465e8a Ensure first tablerow is header after save too
After the document type, media type or member type is saved, this will
ensure first tablerow is a tableheader, so sorting is limited to <tbody>
2015-01-20 02:10:20 +01:00
bjarnef 9ced66f208 U4-4418 - fix issue with tab sorting
Fixed issue with tab sorting, where you are able to drag the rows above
the table header. Ensured that <thead> / <th> is added, so the class
"ui-sortable" is added to <tbody> and only <tbody> will be the
drag-area.
I also added styling for delete button so it's more consistent with
other "delete"-buttons, e.g. for in settings for dropdown lists,
checkbox lists and radionbutton lists. Furthermore the delete-button is
moved inside the ItemTemplate, so the classes easily could be added to
the button and also make the button stay close to the fields.
2015-01-19 21:49:27 +01:00
bjarnef 633f56a7aa U4-5942 - change width of grid cell tools
Change width of grid cell tools, so it doesn't overlap the input
fields/texteditors.
2015-01-19 16:55:02 +01:00
Stephan 12d51b292c U4-6154 - fix unpublishing a document with changes
Conflicts:
	src/Umbraco.Core/Services/ContentService.cs
2015-01-19 14:03:58 +01:00
Shannon Deminick e85ef38218 Merge pull request #621 from AndyButland/u4-6135
Fixes U4-6135 (node name disappears in certain situations when tree is synched
2015-01-19 18:20:47 +11:00
AndyButland 4775b638a4 Reverted previous commit and changed anchor removal to target the correct tag (the elipsis) 2015-01-19 08:05:32 +01:00
Shannon db3b8a1acd Merge remote-tracking branch 'origin/dev-v6' into dev-v7
Conflicts:
	src/Umbraco.Tests/TreesAndSections/ApplicationTreeTest.cs
2015-01-19 12:53:54 +11:00
AndyButland 17906b505d Removed code in tree synchronisation that removes anchor tag containing node name for certain nodes 2015-01-18 21:13:24 +01:00
Sebastiaan Janssen 7a644b6681 U4-6133 Update builtin razor snippets to follow Query Builder conventions
#U4-6133 Fixed
2015-01-15 10:38:07 +01:00
Shannon Deminick 48c127fefd Merge pull request #619 from arknu/U4-6103
U4-6103: Replace style with ng-style (again)
2015-01-14 19:08:18 +11:00
Asbjørn Riis-Knudsen 778d8e0afa Added missing apostrophes 2015-01-14 09:00:12 +01:00
Sebastiaan Janssen 59aa28bf3b Update Installer.cs 2015-01-13 17:34:40 +01:00
Niels Hartvig cea002fd61 Typos in regards to previous commit (U4-6115) 2015-01-13 17:19:11 +01:00
Niels Hartvig f8c1cc684b U4-6115 Add which user installs/uninstalls packages to the audit trail 2015-01-13 17:14:54 +01:00
Shannon 3663fd9f99 Fixes: U4-6106 Threading/Performance issue with MappingResolver and LazyManyObjectsResolverbase/ManyObjectsResolverBase 2015-01-13 19:39:46 +11:00
arknu f8ed9e60f6 U4-6103: Replace style with ng-style (again) 2015-01-12 22:13:01 +01:00
Shannon 00895ff7a9 Fixes: U4-6096 Links in Translator emails incorrect - germain and danish were still incorrect. 2015-01-12 22:10:15 +11:00
Shannon da778e277f Fixes: U4-6093 ContentService.SaveAndPublishDo changes Culture 2015-01-12 21:45:52 +11:00
Shannon 6fcfd49cf0 Merge branch 'U4-5658' of https://github.com/leekelleher/Umbraco-CMS into leekelleher-U4-5658 2015-01-12 19:43:20 +11:00
Shannon 6457a1a2ca Fixes: U4-6088 Publicize all partial view methods on IFileService & U4-6087 Fix Partial View macro repository usage so that when a macro is created from the FileService, the MacroService events are raised
Conflicts:
	src/Umbraco.Core/Umbraco.Core.csproj
2015-01-09 19:15:01 +11:00
Shannon Deminick 4bbd278007 Merge pull request #618 from devinbost/dev-v7
Fixed a syntax error in the spelling of the name of a method.
2015-01-08 15:27:57 +11:00
devinbost f6677aa19e Merge pull request #1 from devinbost/master
Fixed a syntax error in the spelling of the name of a method.
2015-01-07 19:40:23 -08:00
unknown a1bca2eba1 Fixed a syntax error in the spelling of the name of the method GetAllManifestFileContents(..). 2015-01-07 19:25:09 -08:00
Sebastiaan Janssen 4c5cc93a67 U4-6052 Umbraco 7.2.1 web app installed with Nuget fails at start with error :"Cannot create an MVC Area path without the umbracoPath specified"
#U4-6052 In Progress
2015-01-07 11:28:23 +01:00
Shannon 7590bd86dd Merge branch 'dev-v6' of https://github.com/umbraco/Umbraco-CMS into dev-v6 2015-01-07 15:44:05 +11:00
Shannon 6b25e5299f fixes unit test 2015-01-07 15:43:47 +11:00
Shannon 76ab09bfc8 Fixes remaining tests 2015-01-07 15:36:17 +11:00
Shannon d6f47366d4 fixes how bytes are read with utf8 BOM for templates and master pages, fixes unit test 2015-01-07 15:11:27 +11:00
Shannon dc846e7ff6 Fixes installer email validation. Ensures all validation directives are registered under the correct module: umbraco.directives.validation, then we load this module in the installer so we can use the correct email validation directive. 2015-01-07 15:02:58 +11:00
Shannon 322bd4e41e Fixes: U4-5717 Member email validation does not allow valid domains (Umbraco 7.1.4) 2015-01-07 14:32:39 +11:00
Shannon 282550f402 Fixes: U4-6080 Server side email validation doesn't occur on existing members when they are saved 2015-01-07 13:17:44 +11:00
Shannon 699713346c Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-01-07 10:39:11 +11:00
Shannon d4f28fcd85 fixes a couple of tests 2015-01-07 10:39:00 +11:00
Shannon Deminick 11e946d61c Merge pull request #614 from Alain-es/patch-2
Fix bug U4-6071: Feature request - Add a specific section to all users
2015-01-07 10:24:54 +11:00
Shannon 341239648d bumps version 2015-01-07 09:17:22 +11:00
Alain f3b23a15c9 Update UserServiceTests.cs 2015-01-06 12:18:08 +00:00
Alain cc61c34cdf Update UserService.cs 2015-01-06 12:15:32 +00:00
Alain 91b599b213 Update IUserService.cs 2015-01-06 12:14:13 +00:00
Shannon ce6eb3d939 Merge branch 'dev-v7-upgradablemvc5webapi2' of https://github.com/Shazwazza/Umbraco-CMS into dev-v7-upgradablemvc5webapi2
Conflicts:
	src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs
2015-01-06 18:25:42 +11:00
Shannon ec5ca9087e Removes all references of Microsoft.Web.Helpers - we don't need to ship this, we don't reference it and it has compatibility problems. Also updates the version to 7.3.0 2015-01-06 18:24:27 +11:00
Shannon 8cfdcbdd05 Updates how the webapi reflection works to ensure the property info's are cached 2015-01-06 18:23:47 +11:00
Shannon 4a72e8c3df Creates ReflectedFixedRazorViewEngine and version checkers to dynamically update code depending on the major versions of MVC and WebApi 2015-01-06 17:40:28 +11:00
Shannon d747d16b75 Creates ReflectedFixedRazorViewEngine and version checkers to dynamically update code depending on the major versions of MVC and WebApi 2015-01-06 17:39:07 +11:00
Shannon Deminick 106873732c Merge pull request #615 from AndyButland/u4-6044
U4-6044 - prevent search engines from indexing login page
2015-01-06 15:48:40 +11:00
Shannon Deminick 462467a7d8 Merge pull request #616 from AndyButland/u4-6061
U4-6061 - NodeCount for tags is not populated
2015-01-06 15:44:47 +11:00
Shannon ea12da99ea moves RelateOnCopyHandler to Core and changes from ApplicationStarting to ApplicationStarted 2015-01-06 12:22:11 +11:00
Shannon 97a05008b3 Makes the umbProperty directive check optional since these validators can exist outside of an umbProperty directive (i.e. like in a dialog for a parameter editor) 2015-01-06 12:03:19 +11:00
Shannon Deminick 69e1dd1c73 Merge pull request #612 from gildebrand/patch-3
Fix for macrocontainer making it possible to edit
2015-01-06 11:50:31 +11:00
Shannon 95f68b8bde Another attempt at fixing: U4-4049 Some images fail when uploading multiple media files 2015-01-06 11:45:08 +11:00
Shannon 485621b03a Revert "Merge branch '7.2.0-U4-4049' into dev-v7"
This reverts commit 2ad86ec83d, reversing
changes made to 70ddf646be.
2015-01-06 11:22:40 +11:00
Shannon 3f1b031789 fixes OverridableAuthorizationAttribute to ensure that the class level filter is applied if there are no child filters 2015-01-06 11:19:44 +11:00
Shannon d0f125a51b moves file cleanup to outside of the loop 2015-01-06 11:19:19 +11:00
Shannon a4f7c49f50 Merge branch 'Alain-es-Fix_for_U4-5875' into dev-v7 - And updates quite a lot: changes directive name to valPropertyValidator and changes how it works to be ultra flexible for custom validation of property data. Updates umbProperty directive to expose an API for other directives to utilize (like the new set setPropertyError method). Updates valServer to use the better way to access the current property object from the umbProperty directive API. Updates both valServer and valPropertyMsg to only perform a watch when necessary when there has been server side errors, this will speed up client side performance quite a bit. Now the tags, color picker and upload property editors performs correct client side and server side validation for the required validation flag. 2015-01-06 10:55:38 +11:00
Alain a378d0c202 Update UserServiceTests.cs 2015-01-05 21:30:22 +00:00
AndyButland d235340ec6 Populated NodeCount property for tag queries retrieving tags across all types 2015-01-05 22:23:05 +01:00
AndyButland 93ca536b14 Added noindex, nofollow to default page to discourage search engines indexing the back-office 2015-01-05 21:20:50 +01:00
Alain dea78c5d13 Update UserServiceTests.cs 2015-01-05 19:04:59 +00:00
Alain d06ff5f108 Update IUserService.cs 2015-01-05 19:02:32 +00:00
Alain d94fe7df68 Update UserService.cs 2015-01-05 18:55:31 +00:00
Anton Gildebrand fec70fcf47 parseMacroSyntax accepts other characters than a-z
I had problems with parseMacroSyntax when `syntax` included Swedish characters. Now it works with other characters than a-z as well.
2015-01-05 17:13:50 +01:00
Anton Gildebrand 11b53a5dcc Fix for macrocontainer making it possible to edit 2015-01-05 15:17:50 +01:00
Shannon d4c0ea9c48 working on U4-5875 - Updated RequiredManifestValueValidator to automatically check for empty json strings if the value type is JSON. Updates the TagsPropertyEditor to check for empty json in it's required validator. Updated the tags JS to always update the model value so if there's a server side validation, it gets cleared on change. 2015-01-05 14:25:16 +11:00
Shannon 459d9b34e7 Fixes: U4-5974 User which is not administrator getting logged out when clicking recycle bin 2015-01-05 12:22:49 +11:00
Shannon 2ad86ec83d Merge branch '7.2.0-U4-4049' into dev-v7
Conflicts:
	src/Umbraco.Web/Umbraco.Web.csproj
2015-01-05 10:26:27 +11:00
Shannon 70ddf646be Changed the DefaultUrlProvider's warnings to Debug statements since this can get logged very often when there are unpublished pages and a URL is requested for them which can occur a ton, especially when searching in the back office since a URL is attempted to be created on each search for each result. 2015-01-05 10:08:36 +11:00
Shannon 4de31249fd removes some usages of singletons 2015-01-05 10:01:58 +11:00
Shannon 26c3bb05d6 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-01-05 09:48:08 +11:00
Shannon b1fe15ed56 fixes a null ref 2015-01-05 09:46:54 +11:00
Shannon Deminick 83f1613eb8 Merge pull request #611 from leekelleher/lk-contentservice-constants
ContentService - Replaced the hardcoded -1 and -20 values with Constants
2015-01-05 08:55:34 +11:00
leekelleher e8e6f5f807 Replaced the hardcoded integer values for -1 and -20 in ContentService with the Constants values.
I did this whilst working on PR #610 (U4-337), but separated out to its own branch so not to clutter the other PR.
2015-01-04 21:02:20 +00:00
Shannon 920084b7c3 Merge branch 'sitereactor-ascii-art' into dev-v7 2015-01-02 16:21:12 +11:00
Shannon ff2c71367f adds tests 2015-01-02 16:19:51 +11:00
Shannon Deminick 428efed7c3 Merge pull request #597 from chrisjsherm/issue-u4-4158
Fix for Truncate function stripping out content between tags. This issue...
2015-01-02 16:03:46 +11:00
Shannon 7c59c71261 updates PR for U4-6054 to just read directly from the file stream, no need to copy it first. 2015-01-02 15:58:31 +11:00
Shannon Deminick a0c2914ce6 Merge pull request #604 from csharpforevermore/dev-v7
Fixed: U4-6054 "Unit test 'Umbraco.Tests.IO.AbstractFileSystemTests.Can_...
2015-01-02 15:54:11 +11:00
Shannon Deminick dbb70a8646 Merge pull request #607 from gertdc/U4-6060
Added dutch translations for the grid layout
2015-01-02 15:49:50 +11:00
Shannon 6a423dd032 Fixes: U4-5940 Feature Request - Disable partial/macro caching when in debug mode 2015-01-02 15:45:33 +11:00
Shannon 73e9ff04e8 Fixes: U4-5943 Cannot render a macro on a virtual page when using UmbracoVirtualNodeRouteHandler and assigning virtual Ids 2015-01-02 15:34:51 +11:00
Shannon 201464cb44 Fixes: U4-5918 Update Underscore.js and also updates our usage of bower with the correct grunt-bower plugin, this massively simplifies bower usage and paves the way to start using bower for all JS components. 2015-01-02 14:25:11 +11:00
Shannon a68fed42ad Merge branch 'madsoulswe-7.2.1' into dev-v7 2015-01-02 11:58:56 +11:00
Shannon a427427564 fixes sql for sqlce for data integrity controller 2015-01-02 11:56:27 +11:00
Shannon 2286c0899c reverts UseTempStorage sync from examine settings on dev branch. 2015-01-02 11:55:18 +11:00
Shannon 55eea6e44f Merge branch '7.2.0' into 7.2.0-U4-4049 2015-01-02 11:44:29 +11:00
gertdc ae257d0f50 Added dutch translations for the grid layout 2014-12-30 10:18:54 +01:00
Shannon 28a01d61a6 Fixes: U4-5981 Umbraco 7.2 Text encoding when saving partial view template 2014-12-29 13:50:33 +11:00
Chris Randle bc776d787e Fixed: U4-6054 "Unit test 'Umbraco.Tests.IO.AbstractFileSystemTests.Can_Get_Size()' fails" by looking at the size of the string not the file which can vary - possibly dependent on encoding. 2014-12-27 00:11:59 +00:00
Shannon 2f74dfe5cb fixes missing using statement 2014-12-24 17:01:41 +11:00
Shannon 84d2caf5d8 Merge branch '21robin12-7.2.0-U4-6004' into dev-v7 2014-12-24 12:34:10 +11:00
Shannon 456e7d9fdf Merge branch '7.2.0-U4-6004' of https://github.com/21robin12/Umbraco-CMS into 21robin12-7.2.0-U4-6004 2014-12-24 12:33:35 +11:00
Shannon dae66ad2d0 Merge remote-tracking branch 'origin/dev-v6' into dev-v7
Conflicts:
	src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs
	src/Umbraco.Web/umbraco.presentation/library.cs
	src/umbraco.businesslogic/Application.cs
	src/umbraco.businesslogic/ApplicationRegistrar.cs
	src/umbraco.businesslogic/ApplicationTree.cs
	src/umbraco.businesslogic/ApplicationTreeRegistrar.cs
2014-12-24 11:56:28 +11:00
Stephan 69d254a198 Merge pull request #600 from solutionmania/dev-v7
Resolved U4-5193 and U4-6051
2014-12-23 17:44:39 +01:00
Stephan b30555f5a4 Merge pull request #599 from solutionmania/dev-v6
Merge into dev v6
2014-12-23 17:44:25 +01:00
Chris Roberts d5b6428cdc Fixed: U4-6051 HasAccces method tests the roles of the wrong user 2014-12-23 16:32:24 +00:00
Chris Roberts 7d5bce76c2 Fixed: U4-5193 HasAccess override method name error 2014-12-23 16:30:11 +00:00
Chris Roberts d4d77611eb Fixed: U4-5193 HasAccess override method name error 2014-12-23 16:27:51 +00:00
Chris Roberts 662ed03f0a Fixed: U4-6051 HasAccces method tests the roles of the wrong user 2014-12-23 16:23:47 +00:00
Shannon fdac0ede45 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2014-12-22 15:14:57 +11:00
Shannon 83aa30d2c5 Adds a VirtualPath property to IFile which is the relative path of the file to the root of the website. 2014-12-22 15:14:44 +11:00
chrisjsherm 34b524aabb Fix for Truncate function stripping out content between tags. This issue is referenced at issues.umbraco.org/issue/U4-4158. 2014-12-19 17:47:12 -05:00
per ploug 2e2ea57ba6 Fixes grid editor always rending 12 columns
When a user change grid cols, the editor keeps rendering 12 column
layouts - this fixes the 12 cols issue and falls back to 12 in case of
invalid/missing information
2014-12-19 16:11:33 +01:00
Sebastiaan Janssen 72004768cf U4-5981 Umbraco 7.2 Text encoding when saving partial view template
#U4-5981 In Progress Assignee Shandem
2014-12-18 13:56:50 +01:00
Sebastiaan Janssen b8e98ae017 No need to start a webserver for the Umbraco.Web.UI.Client project (correct me if I'm wrong) 2014-12-18 13:55:50 +01:00
Shannon 3c01dcb30c Fixes: U4-6030 2014-12-18 15:16:29 +11:00
Shannon 938b236f54 fixes initialized flag on section service 2014-12-18 15:12:22 +11:00
Shannon aa439cacda working on U4-6030 2014-12-18 14:58:49 +11:00
Shannon e643f2a0ba working on U4-6030 2014-12-18 14:20:41 +11:00
Shannon 5b9a98ad6a Simplifies the ILocalizedTextService to not have an extension method for null tokens, adds another extension method to accept an array of tokens, adds null checks. 2014-12-18 12:45:04 +11:00
Shannon 3323138232 Fixes up js localization service so that it doesn't make a ton of requests on first load, Fixes: U4-2675 Create new controller service to output the json for localization for use in angular service 2014-12-18 12:35:38 +11:00
Shannon cd0aa5e342 Fixed null checks and error checking for duplicates in the xml file store, added test 2014-12-18 12:33:34 +11:00
Shannon f63ec81c47 cleans up commented out code 2014-12-18 10:58:41 +11:00
Dennis Öhman 5b63a8e9d9 Colspan change
Changed colspan from fixed 5 to includeProperties.length + 3
2014-12-17 17:10:22 +01:00
Morten Christensen 71244b9bcd Smaller variation so text isn't pushed down 2014-12-17 16:17:49 +01:00
Morten Christensen fd1e369b2a Makes readme.txt for nuget packages awesome! 2014-12-17 15:59:37 +01:00
Robin Herd c256266432 isResized now determined by regex 2014-12-17 13:06:46 +00:00
Shannon db087a9e78 pretty much got 5966 working just need to do some more tests. 2014-12-17 17:08:12 +11:00
Shannon 4e33552a5c wip - working on U4-5966 2014-12-17 16:19:42 +11:00
Shannon da25970f79 wip - working on U4-5966 2014-12-17 15:19:03 +11:00
Shannon 0807597a3c Fixes: U4-5977 The debounce timeout on the main search is too big which produces a lag in searching & U4-5994 Global search needs to only show results for the 'last' search request made and ignore previous ones 2014-12-16 15:50:54 +11:00
Shannon d564866b07 Merge branch 'Aaen-7.2.0' into dev-v7 2014-12-16 14:34:13 +11:00
Shannon 99a45d26ae Merge branch '7.2.0' of https://github.com/Aaen/Umbraco-CMS into Aaen-7.2.0 2014-12-16 14:33:21 +11:00
Shannon a32d38f7ea Fixes: U4-5992 Caching of XPathNodeIterator in umbraco.library is not thread safe and will cause media errors like valueDictionary exception 2014-12-16 14:26:53 +11:00
Shannon Deminick 5bf9362c92 Merge pull request #586 from Alain-es/Fix-for-U4-5852
Fix for U4-5852
2014-12-16 11:24:56 +11:00
Shannon Deminick d9925e3453 Merge pull request #589 from teeto/patch-1
Update es.xml
2014-12-16 11:08:16 +11:00
Shannon e1106a9d67 Merge branch '7.2.1-doctype-fixes' into 7.2.1
Conflicts:
	src/Umbraco.Core/Models/PropertyGroupCollection.cs
	src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
	src/Umbraco.Core/Services/ContentTypeService.cs
	src/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs
	src/Umbraco.Tests/Services/ContentTypeServiceTests.cs
	src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs
2014-12-16 09:47:53 +11:00
Sebastiaan Janssen a8d7a1d01d Makes the test green: don't add the passed in composition as a dependency to itself.. also added another invariant check 2014-12-15 19:52:28 +01:00
Sebastiaan Janssen e62597521e Remove the renaming to 'title' which would cause a duplicate and make the next test fail 2014-12-15 19:51:37 +01:00
Sebastiaan Janssen fa91321299 Adds test for adding properties to a composition that has been saved and now doesn't allow a new property to be added 2014-12-15 18:56:58 +01:00
Morten Christensen 2d81691407 Adding new test case for renaming PropertyType aliases on indirect references 2014-12-15 16:34:41 +01:00
Morten Christensen 21f08ca491 Refactoring validation and adding new test case for renaming PropertyTypes 2014-12-15 15:33:05 +01:00
Morten Christensen e202f21934 Adds new test, fix, refactoring for adding duplicate PropertyType aliases 2014-12-15 14:29:48 +01:00
Shannon 2936ff0bf9 Makes provider user key type for new membership provider configurable, by default it is int 2014-12-15 20:44:00 +11:00
Alain 55dbc82d75 no-dirty-check all lower case 2014-12-15 09:11:21 +00:00
Sebastiaan Janssen 8e4e575276 Makes sure messages are shown in the user's configured language 2014-12-15 09:30:04 +01:00
Sebastiaan Janssen 84752babc8 Moved both new sections to the bottom so it's easier for upgraders to merge them 2014-12-15 09:04:25 +01:00
Shannon Deminick e1ec49fd3c Merge pull request #592 from Bitmapped/7.2.1-U4-5564
Better fix for U4-5564
2014-12-15 13:24:24 +11:00
Shannon 60a1116acd Fixes: U4-6009 Distributed calls not working in 7.2 2014-12-15 11:45:55 +11:00
Sebastiaan Janssen a480d7bbe6 U4-5959 Getting YSOD when wanting to create partial view in a subfolder in the backoffie
#U4-5959 Fixed Due in version 7.2.1
2014-12-14 17:22:10 +01:00
Sebastiaan Janssen 7316c5462a U4-5928 Umbraco 7.2 RC GetCurrentMemberProfileModel Null Ref
#U4-5928 Fixed Due in version 7.2.1
2014-12-14 16:50:11 +01:00
Morten Christensen 2a9960afb3 Adding UI feedback for invalid compositions 2014-12-12 17:04:53 +01:00
Morten Christensen ed899ec73d Adding additional test coverage for Compositions and updating PropertyTypes and PropertyGroups 2014-12-12 17:04:11 +01:00
Morten Christensen 8f26f9385d Refactoring the logic around saving updates to PropertyTypes and PropertyGroups 2014-12-12 17:02:03 +01:00
Robin Herd 599d367343 Fixed bug U4-6004, MediaService.GetMediaByPath now returns IMedia for paths containing 'x' and '_' 2014-12-11 17:59:52 +00:00
teeto 45241788b3 Update es.xml
I have updated the es.xml file adding the values for grid section and the values marked as version="7.2" which were not translated
2014-12-11 18:16:35 +01:00
Morten Christensen a446cc224d Refactoring the logic in the validation method for when ContentTypes are saved 2014-12-11 17:14:01 +01:00
Alain-es 8bfcd4ce3f using noDirtyCheck directive instead of removing valFormManager directive 2014-12-11 11:41:17 +00:00
Morten Christensen 07f9a9700d Ensures that inherited PropertyType aliases are also checked for indirect references 2014-12-11 12:22:49 +01:00
Sebastiaan Janssen 7e7acd0049 Correcting my mistakes to the unit test, using the wrong alias 2014-12-11 11:02:51 +01:00
Morten Christensen 57985c26a2 Updating the name of PropertyGroups in DB to ensure renaming is done properly 2014-12-11 10:55:33 +01:00
Morten Christensen 504c1f7254 Updating tests related to #U4-5986
Conflicts:
	src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs
2014-12-11 10:55:21 +01:00
Shannon 52ad36a6c2 removes commented out code form PR 2014-12-11 10:49:41 +01:00
Peter Gregory 01670e0832 Fixes issue U4-5925 GetMedia returning nothing
Removed the use of FromXElement that was only used by GetMedia.  The change introduced in commit f3f6504398 caused GetMedia to return nothing due to the introduction of the FromXElement method.
2014-12-11 10:49:30 +01:00
Shannon e1a93e9b3f updates the cdf mvc version to match the one in the nuspec 2014-12-11 19:57:59 +11:00
Shannon 2203db548a updates port 2014-12-11 19:01:32 +11:00
Shannon ff66c90855 doh, fixed nuspec, there's no mvc cdf 1.8.1. updates the port 2014-12-11 18:49:40 +11:00
Shannon b0779cb330 updates examine local storage logic for when there are no indexes and they need to be created 2014-12-11 18:43:39 +11:00
Shannon e3f043794b removes commented out code form PR 2014-12-11 18:42:51 +11:00
Shannon 25c021d0a9 Merge branch '7.2.1' of https://github.com/umbraco/Umbraco-CMS into 7.2.1 2014-12-11 17:56:04 +11:00
Shannon 8f35c8fb57 Fixes: U4-5996 CDF reference issue 2014-12-11 17:55:53 +11:00
Shannon Deminick 45e3b2acf4 Merge pull request #587 from pgregorynz/7.2.1
Fixes issue U4-5925 GetMedia returning nothing
2014-12-11 17:47:00 +11:00
Shannon 082d116924 updates nuspec with examine and cdf updates 2014-12-11 17:46:06 +11:00
Peter Gregory 85ccea60ab Fixes issue U4-5925 GetMedia returning nothing
Removed the use of FromXElement that was only used by GetMedia.  The change introduced in commit f3f6504398 caused GetMedia to return nothing due to the introduction of the FromXElement method.
2014-12-11 16:27:06 +10:00
Shannon 49e5493d52 Merge branch '7.2.1' of https://github.com/umbraco/Umbraco-CMS into 7.2.1 2014-12-11 15:59:06 +11:00
Shannon a700258d92 WIP - updates to latest examine which exposes some methods needed to get this syncing done. This will not build until i put that examine version on nuget (soon). Ensures all readers/writers uses the same deletion policy, ensure segments file is copied across on sync restore. Changes the config to use an enum instead of a boolean which will give us some more flexibility. 2014-12-11 15:58:54 +11:00
Morten Christensen 712fb9f11a Merge branch '7.2.1' of https://github.com/umbraco/Umbraco-CMS into 7.2.1
Conflicts:
	src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs
2014-12-10 22:22:29 +01:00
Morten Christensen c16a1c727d Updating the name of PropertyGroups in DB to ensure renaming is done properly 2014-12-10 22:20:00 +01:00
Morten Christensen 78bc12eb77 Updating tests related to #U4-5986 2014-12-10 22:19:17 +01:00
Alain-es 9c10145869 Fix for U4-5852 2014-12-10 15:18:41 +00:00
Stephan 99c96bce86 U4-5986 - reject ppty alias used by ancestor 2014-12-10 13:01:51 +01:00
Stephan 70424183fa U4-5986 - reject ppty alias used by ancestor 2014-12-10 13:00:56 +01:00
Sebastiaan Janssen da2bc6764b Version also updates in the csproj 2014-12-10 12:59:08 +01:00
Shannon d11a377f0f bump version 2014-12-10 12:28:06 +01:00
Stephan d445f7cb0d U4-5986 - reject ppty alias used by descendant 2014-12-10 12:27:55 +01:00
Stephan d02235b997 U4-5986 - reject ppty alias used by descendant 2014-12-10 12:04:13 +01:00
Sebastiaan Janssen 899d325ca1 Updates unit tests to use the newer new ContentType method and obsoletes the old one 2014-12-10 11:52:03 +01:00
Sebastiaan Janssen f1107b7a91 Fixes U4-5986 Compositions: Possible to get stuck in document type ysod's
#U4-5986 Fixed Due in version 7.2.1
2014-12-10 11:51:53 +01:00
Stephan a3f171e7b3 U4-5931 - fix DocType inheritance issue 2014-12-10 11:51:42 +01:00
Sebastiaan Janssen 8b3e80a001 Updates unit tests to use the newer new ContentType method and obsoletes the old one 2014-12-10 11:42:45 +01:00
Brian Powell 13a2d845c6 Clean up comments. 2014-12-10 03:13:49 -05:00
Sebastiaan Janssen c20c93e648 Fixes merge issue 2014-12-09 21:14:22 +01:00
Brian Powell 2c212cb16a Better fix for U4-5564 - replaces reverted part of Pull #492 2014-12-09 13:38:59 -05:00
Sebastiaan Janssen 848e8a6248 Fixes U4-5986 Compositions: Possible to get stuck in document type ysod's
#U4-5986 Fixed Due in version 7.2.1
2014-12-09 19:30:48 +01:00
Stephan 9dcba6a679 U4-5931 - fix DocType inheritance issue 2014-12-09 17:58:54 +01:00
Mark Drake accded4dfc Resolves Bug #U4-5568 Allow 0 for numeric data type
Please see this bug for more detail:
http://issues.umbraco.org/issue/U4-5568
2014-12-09 11:51:27 -05:00
Stephan c8f80453b9 U4-5929 - support IDN in hostnames 2014-12-09 09:34:58 +01:00
Shannon d857743bf3 moves the local storage logic to the BaseUmbracoIndexer 2014-12-09 19:15:47 +11:00
Shannon 78bee017ca Updates nuspec to have a min examine version of 0.1.58 and prettifies their structure. 2014-12-09 19:10:57 +11:00
Shannon f08320bd81 Fixes: U4-5976 When no Examine indexes exist they are rebuilt at startup, however the rebuilding happens too soon before any Examine event handlers are actually wired up.
Updates examine version to facilitate this. Adds ability to tokenize the {machinename} in an examine index path.
2014-12-09 19:07:14 +11:00
Shannon a1fcdac896 Merge branch '7.2.1' of https://github.com/umbraco/Umbraco-CMS into 7.2.1 2014-12-09 19:05:11 +11:00
Shannon ae2d9e6c55 Fixes: U4-5977 The debounce timeout on the main search is too big which produces a lag in searching 2014-12-09 19:05:00 +11:00
Shannon 451be273a5 bump version 2014-12-09 18:55:54 +11:00
Shannon Deminick bf7473145f Merge pull request #577 from abjerner/patch-4
Moved the right click action for the tree header
2014-12-09 16:06:56 +11:00
Shannon Deminick 01a309ef42 Merge pull request #582 from arknu/propertyeditor-localization
U4-5101: Localize property editors (updated)
2014-12-09 13:08:19 +11:00
Shannon Deminick bf4d0a8d01 Merge pull request #581 from readingdancer/Fix_for_5364_Second_Version
Fix for issue U4-5364 without trying to fix the localization of error msg.
2014-12-09 12:54:37 +11:00
Dennis Aaen 3a919b67ea U4-5973 Fix casing of word XSLT when saving a XSLT file 2014-12-08 20:09:05 +01:00
arknu 77fd2c9444 Update translations for Grid 2014-12-08 18:36:51 +01:00
arknu 30042aae6d U4-5101: Localize Grid property editor 2014-12-08 17:46:32 +01:00
arknu 8bc9fb9242 U4-5101: Localize Image Cropper property editor 2014-12-08 17:41:03 +01:00
arknu 482e90dbc0 U4-5101: Localize Content Picker property editor 2014-12-08 17:41:02 +01:00
arknu 0b61546633 U4-5101: Localize Tags property editor 2014-12-08 17:41:01 +01:00
arknu ca69e64846 U4-5101: Localize Related Link property editor 2014-12-08 17:37:47 +01:00
Chris Houston 6e60aa17dc Fix for issue U4-5364 without trying to fix the localization of the error text. 2014-12-08 15:16:37 +00:00
Shannon f60884e796 reverts change to umbraco module to set the original URL when using SSL... there should be no need to specify anything differently here. If there's an explicity base path and url then use the basePath config option. 2014-12-08 17:34:54 +11:00
Shannon d2dbd91b17 Fixes merge issues 2014-12-08 17:19:48 +11:00
Shannon 0a7bbfb1ca Merge remote-tracking branch 'origin/6.2.5' into 7.2.1
Conflicts:
	src/Umbraco.Core/Configuration/UmbracoSettings.cs
	src/Umbraco.Core/Sync/ServerEnvironmentHelper.cs
	src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs
	src/Umbraco.Tests/Umbraco.Tests.csproj
	src/Umbraco.Web.UI/install/steps/defaultUser.ascx
	src/Umbraco.Web.UI/web.Template.Debug.config
	src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs
	src/Umbraco.Web/Scheduling/IBackgroundTask.cs
	src/Umbraco.Web/Scheduling/KeepAlive.cs
	src/Umbraco.Web/Scheduling/LogScrubber.cs
	src/Umbraco.Web/Scheduling/ScheduledPublishing.cs
	src/Umbraco.Web/Scheduling/ScheduledTasks.cs
	src/Umbraco.Web/Scheduling/Scheduler.cs
	src/Umbraco.Web/Scheduling/TaskEventArgs.cs
	src/Umbraco.Web/Umbraco.Web.csproj
2014-12-08 17:16:16 +11:00
Shannon 864994a56e updates error msgs when sending requests to the same server pointing to docs on baseUrl 2014-12-08 17:04:22 +11:00
Shannon 3405c5001b working on U4-5964, U4-5907, U4-5965 2014-12-08 15:18:32 +11:00
Shannon 4d8732d925 The only way i could get this project to build and run was to change the transform to explicitly target 4.0.0.1 for mvc and webapi, otherwise nothing works and horribly cryptic build errors. Added the tests for the BackgroundTaskRunner 2014-12-08 14:59:32 +11:00
Mark Drake 6751f108f0 Resolves bug U4-5944
This change resolves an issue with the media picker / RTE where an image
inserted with no alt title provided is inserted with it equal to
"undefined". See: http://issues.umbraco.org/issue/U4-5944
2014-12-07 21:55:06 -05:00
Anders Bjerner 0feb65c455 Moved the right click action for the tree header
See http://issues.umbraco.org/issue/U4-5961
2014-12-07 17:21:30 +01:00
Sebastiaan Janssen 4eb9a54fa5 Ports v7 changes for U4-5728 - OriginalRequestUrl not initialized, KeepAlive or ScheduledPublishing run too soon
#U4-5728
2014-12-07 16:16:29 +01:00
Shannon 3b2a27dfb2 Merge branch '7.2.1' of https://github.com/umbraco/Umbraco-CMS into 7.2.1 2014-12-05 10:29:35 +11:00
Shannon ad66613011 Updates ValidateCurrentUser so that it doesn't re-decrypt the cookie since that is already done, it just needs to check if the current user is authenticated and if it is a back office identity. Added lots of notes for extension points when we start looking at extending how the back office auth works. 2014-12-05 10:29:18 +11:00
Shannon Deminick a1de100a93 Merge pull request #575 from greystate/typo-buster
Just a teeny-tiny typo change ("differnt" -> "different")
2014-12-05 10:02:18 +11:00
Chriztian Steinmeier cbcbc128ff Typo change "differnt" -> "different" 2014-12-04 23:40:28 +01:00
Shannon 6555fd5791 Updated U4-4049 - we now use media formatters instead of IModelBinder (this is actually the preferred way anyways). The validation is then moved to just a filter instead of done in the model binder. This way a media formatter is pure async, so we can ReadFromStreamAsync in a completely native async operation which should hopefuly fix this issue. 2014-12-03 21:06:01 +11:00
Shannon 71ca90d74b Merge remote-tracking branch 'origin/6.2.2' into 6.2.4 2014-11-21 09:14:22 +11:00
Shannon Deminick fb42472f31 Merge pull request #554 from cloud46limited/umbUKFest-3556
Fixed type in Step 4 install wizard - U4-3556.
2014-11-21 09:13:10 +11:00
Gareth Evans - Cloud46 Limited b6695b6953 Fixed type in Step 4 install wizard - U4-3556. 2014-11-20 14:48:26 +00:00
Alejandro Ocampo 8820fa1fdf U4-4400 Make upload new media item button bit clearer 2014-11-20 14:27:33 +00:00
575 changed files with 20926 additions and 15532 deletions
+5 -15
View File
@@ -23,14 +23,15 @@ ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %rel
ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
SET nuGetFolder=%CD%\..\src\packages\
..\src\.nuget\NuGet.exe sources Remove -Name MyGetUmbracoCore
..\src\.nuget\NuGet.exe sources Remove -Name MyGetUmbracoCore >NUL
..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder%
..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder%
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder%
ECHO Removing the belle build folder to make sure everything is clean as a whistle
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
ECHO Removing existing built files to make sure everything is clean as a whistle
RMDIR /Q /S _BuildOutput
@@ -44,18 +45,8 @@ CALL InstallGit.cmd
ECHO Performing MSBuild and producing Umbraco binaries zip files
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
ECHO Adding dummy files to include in the NuGet package so that empty folders actually get created
SET dummytext=This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete.
ECHO %dummytext% > .\_BuildOutput\WebApp\App_Code\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\App_Data\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\App_Plugins\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\css\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\masterpages\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\media\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\scripts\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\usercontrols\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\Views\Partials\dummy.txt
ECHO %dummytext% > .\_BuildOutput\WebApp\Views\MacroPartials\dummy.txt
ECHO Setting node_modules folder to hidden to prevent VS13 from crashing on it while loading the websites project
attrib +h ..\src\Umbraco.Web.UI.Client\node_modules
ECHO Adding Web.config transform files to the NuGet package
REN .\_BuildOutput\WebApp\MacroScripts\Web.config Web.config.transform
@@ -65,7 +56,6 @@ REN .\_BuildOutput\WebApp\Xslt\Web.config Web.config.transform
ECHO Packing the NuGet release files
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %version%
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoExamine.PDF.nuspec
IF ERRORLEVEL 1 GOTO :showerror
+90 -113
View File
@@ -1,4 +1,3 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
@@ -14,18 +13,18 @@
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<OutputFile ParameterType="System.String" Required="true" />
<InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<OutputFile ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System.IO" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Security.Cryptography" />
<Code Type="Fragment" Language="cs">
<![CDATA[
<Using Namespace="System.IO" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Security.Cryptography" />
<Code Type="Fragment" Language="cs">
<![CDATA[
using (var ms = new MemoryStream())
{
foreach (var item in InputFiles)
@@ -48,11 +47,11 @@
}
}
]]>
</Code>
</Code>
</Task>
</UsingTask>
</UsingTask>
<!--
****************************************************
VARIABLES
@@ -76,23 +75,19 @@
<BuildZipFileName>UmbracoCms$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileName>
<BuildZipFileNameBin>UmbracoCms.AllBinaries$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameBin>
<BuildZipFileNameWebPi>UmbracoCms.WebPI$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameWebPi>
<BuildZipExaminePDFName>UmbracoExamine.PDF.0.6.0.zip</BuildZipExaminePDFName>
<IncludeSymbols>False</IncludeSymbols>
<BuildFolderRelativeToProjects>..\..\build\$(BuildFolder)</BuildFolderRelativeToProjects>
<BuildFolderAbsolutePath>$(MSBuildProjectDirectory)\$(BuildFolder)</BuildFolderAbsolutePath>
<SolutionBinFolder>$(BuildFolder)bin\</SolutionBinFolder>
<WebAppFolder>$(BuildFolder)WebApp\</WebAppFolder>
<WebPiFolder>$(BuildFolder)WebPi\</WebPiFolder>
<ConfigsFolder>$(BuildFolder)Configs\</ConfigsFolder>
<ConfigsFolder>$(BuildFolder)Configs\</ConfigsFolder>
<SolutionBinFolderRelativeToProjects>$(BuildFolderRelativeToProjects)bin\</SolutionBinFolderRelativeToProjects>
<SolutionBinFolderAbsolutePath>$(BuildFolderAbsolutePath)bin\</SolutionBinFolderAbsolutePath>
<WebAppFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebApp\</WebAppFolderRelativeToProjects>
<WebAppFolderAbsolutePath>$(BuildFolderAbsolutePath)WebApp\</WebAppFolderAbsolutePath>
<WebPiFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebPi\</WebPiFolderRelativeToProjects>
<WebPiFolderAbsolutePath>$(BuildFolderAbsolutePath)WebPi\</WebPiFolderAbsolutePath>
<ExaminePDFPath>$(BuildFolderAbsolutePath)UmbracoExamine.PDF\</ExaminePDFPath>
<ExamineAzurePath>$(BuildFolderAbsolutePath)UmbracoExamine.Azure\</ExamineAzurePath>
<ExaminePDFAzurePath>$(BuildFolderAbsolutePath)UmbracoExamine.PDF.Azure\</ExaminePDFAzurePath>
</PropertyGroup>
<ItemGroup>
@@ -114,16 +109,16 @@
*****************************************************
-->
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
<Message Text="Build finished" />
</Target>
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
<ItemGroup>
</Target>
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
<ItemGroup>
<WebPiFile Include="$(BuildZipFileNameWebPi)" />
</ItemGroup>
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
</ItemGroup>
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
</Target>
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
@@ -153,7 +148,7 @@
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
</Target>
<Target Name="ZipWebApp" DependsOnTargets="ZipUmbracoExaminePDF" >
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
<Message Text="Starting to zip to $(buildDate)-$(BuildZipFileName)" Importance="high" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
@@ -162,14 +157,6 @@
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
</Target>
<Target Name="ZipUmbracoExaminePDF" DependsOnTargets="CreateSystemFolders" >
<Message Text="Starting to zip to $(buildDate)-$(BuildZipExaminePDFName)" Importance="high" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipExaminePDFName)%22 %22$(ExaminePDFPath)*%22" />
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipExaminePDFName)" Importance="high" />
</Target>
<Target Name="CreateSystemFolders" DependsOnTargets="CopyBelleBuild" Inputs="@(SystemFolders)" Outputs="%(Identity).Dummy">
<MakeDir Directories="@(SystemFolders)" />
</Target>
@@ -177,14 +164,14 @@
<Target Name="CopyBelleBuild" DependsOnTargets="CopyLibraries" >
<ItemGroup>
<BelleFiles Include="..\src\Umbraco.Web.UI.Client\build\belle\**\*.*" Exclude="..\src\Umbraco.Web.UI.Client\build\belle\index.html" />
</ItemGroup>
<Copy SourceFiles="@(BelleFiles)"
DestinationFiles="@(BelleFiles->'$(WebAppFolder)umbraco\%(RecursiveDir)%(Filename)%(Extension)')"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
</ItemGroup>
<Copy SourceFiles="@(BelleFiles)"
DestinationFiles="@(BelleFiles->'$(WebAppFolder)umbraco\%(RecursiveDir)%(Filename)%(Extension)')"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
</Target>
<Target Name="CopyLibraries" DependsOnTargets="OffsetTimestamps" >
<!-- Copy SQL CE -->
<ItemGroup>
@@ -217,7 +204,7 @@
</Target>
<!-- Copy the transformed web.config file to the root -->
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyTransformedConfig">
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyTransformedConfig">
<ItemGroup>
<WebConfigFile Include="..\src\Umbraco.Web.UI\web.$(BuildConfiguration).Config.transformed" />
</ItemGroup>
@@ -226,24 +213,24 @@
DestinationFiles="$(WebAppFolder)Web.config"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
</Target>
<!-- Copy the config files and rename them to *.config.transform -->
<Target Name="CopyTransformedConfig" DependsOnTargets="CopyXmlDocumentation">
</Target>
<!-- Copy the config files and rename them to *.config.transform -->
<Target Name="CopyTransformedConfig" DependsOnTargets="CopyXmlDocumentation">
<ItemGroup>
<ConfigFiles Include="$(WebAppFolder)config\*.config;$(WebAppFolder)config\*.js" />
<WebConfigTransformFile Include="$(WebAppFolder)Web.config" />
</ItemGroup>
<Copy SourceFiles="@(ConfigFiles)"
DestinationFiles="@(ConfigFiles->'$(ConfigsFolder)\%(RecursiveDir)%(Filename)%(Extension)')"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
<Copy SourceFiles="@(WebConfigTransformFile)"
DestinationFiles="$(ConfigsFolder)Web.config.transform"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
<ConfigFiles Include="$(WebAppFolder)config\*.config;$(WebAppFolder)config\*.js" />
<WebConfigTransformFile Include="$(WebAppFolder)Web.config" />
</ItemGroup>
<Copy SourceFiles="@(ConfigFiles)"
DestinationFiles="@(ConfigFiles->'$(ConfigsFolder)\%(RecursiveDir)%(Filename)%(Extension)')"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
<Copy SourceFiles="@(WebConfigTransformFile)"
DestinationFiles="$(ConfigsFolder)Web.config.transform"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
</Target>
<!-- Copy the xml documentation to the bin folder -->
@@ -261,78 +248,68 @@
<!-- Unlike 2010, the VS2012 build targets file doesn't clean up the umbraco.presentation dir, do it manually -->
<Target Name="CleanupPresentation" DependsOnTargets="CompileProjects">
<ItemGroup>
<PresentationFolderToDelete Include="$(WebAppFolder)umbraco.presentation" />
<ItemGroup>
<PresentationFolderToDelete Include="$(WebAppFolder)umbraco.presentation" />
</ItemGroup>
<RemoveDir Directories="@(PresentationFolderToDelete)" />
<RemoveDir Directories="@(PresentationFolderToDelete)" />
</Target>
<Target Name="CompileProjects" DependsOnTargets="CompileExternalExamineProjects">
<Target Name="CompileProjects" DependsOnTargets="SetVersionNumber">
<Message Text="Compiling web project to build\$(BuildFolder)" Importance="high" />
<!-- For UseWPP_CopyWebApplication=True see http://stackoverflow.com/questions/1983575/copywebapplication-with-web-config-transformations -->
<!-- Build the Umbraco.Web.UI project -->
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath)" Targets="Clean;Rebuild;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
</MSBuild>
<!-- DONE -->
<Message Text="Finished compiling projects" Importance="high" />
</Target>
<Target Name="CompileExternalExamineProjects" DependsOnTargets="SetVersionNumber">
<Message Text="Building externally shipped examine projects" Importance="high" />
<!-- First remove old files from the examine builds -->
<ItemGroup>
<FilesToDeleteBeforeBuild Include="$(ExaminePDFPath)*;$(ExamineAzurePath)*"/>
</ItemGroup>
<Delete Files="@(FilesToDeleteBeforeBuild)" />
<!--
Build the UmbracoExamine.PDF.Azure library ... this builds the 3 projects that we want to bundle separately so no need to build each one separately .
We'll just build this one and then manually copy the DLLs to where we want them.
-->
<MSBuild Projects="..\src\UmbracoExamine.PDF.Azure\UmbracoExamine.PDF.Azure.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);PipelineDependsOnBuild=False;OutDir=$(ExaminePDFAzurePath);" Targets="Clean;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
</MSBuild>
<ItemGroup>
<ExaminePDFFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.pdf;$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.xml;$(ExaminePDFAzurePath)**\itextsharp.dll" />
<ExamineAzureFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.pdb;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.xml" />
<ExaminePDFAzureFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.pdb;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.xml" />
</ItemGroup>
<!-- Now copy the built files to their correct deployment folders-->
<Copy SourceFiles="@(ExaminePDFFiles)"
DestinationFolder="$(ExaminePDFPath)"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
<Copy SourceFiles="@(ExamineAzureFiles)"
DestinationFolder="$(ExamineAzurePath)"
OverwriteReadOnlyFiles="true"
SkipUnchangedFiles="false" />
<!-- Then just delete the files we don't want to ship in the UmbracoExamine.Azure.PDF folder -->
<ItemGroup>
<FilesToDeleteAfterBuild Include="$(ExaminePDFAzurePath)*" Exclude="$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.dll;$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.pdb;$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.xml"/>
</ItemGroup>
<Delete Files="@(FilesToDeleteAfterBuild)" />
</Target>
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
<PropertyGroup>
<NewVersion>$(BUILD_RELEASE)</NewVersion>
<NewVersion Condition="'$(BUILD_COMMENT)'!=''">$(BUILD_RELEASE)-$(BUILD_COMMENT)</NewVersion>
</PropertyGroup>
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
<PropertyGroup>
<NewVersion>$(BUILD_RELEASE)</NewVersion>
<NewVersion Condition="'$(BUILD_COMMENT)'!=''">$(BUILD_RELEASE)-$(BUILD_COMMENT)</NewVersion>
</PropertyGroup>
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
<FileUpdate
Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
Regex="(\d+)\.(\d+)\.(\d+)(.(\d+))?"
ReplacementText="$(BUILD_RELEASE)"/>
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
Regex="CurrentComment { get { return &quot;([a-zA-Z]+)?&quot;"
Regex="CurrentComment { get { return &quot;(.+)?&quot;"
ReplacementText="CurrentComment { get { return &quot;$(BUILD_COMMENT)&quot;"/>
<XmlPoke XmlInputPath=".\NuSpecs\build\UmbracoCms.props"
Namespaces="&lt;Namespace Prefix='x' Uri='http://schemas.microsoft.com/developer/msbuild/2003' /&gt;"
Query="//x:UmbracoVersion"
Value="$(NewVersion)" />
<!--This updates the AssemblyFileVersion for the solution to the umbraco version-->
<FileUpdate
Files="..\src\SolutionInfo.cs"
Regex="AssemblyFileVersion\(&quot;(.+)?&quot;\)"
ReplacementText="AssemblyFileVersion(&quot;$(BUILD_RELEASE)&quot;)"/>
<!--This updates the AssemblyInformationalVersion for the solution to the umbraco version and comment-->
<FileUpdate
Condition="'$(BUILD_COMMENT)'!=''"
Files="..\src\SolutionInfo.cs"
Regex="AssemblyInformationalVersion\(&quot;(.+)?&quot;\)"
ReplacementText="AssemblyInformationalVersion(&quot;$(BUILD_RELEASE)-$(BUILD_COMMENT)&quot;)"/>
<FileUpdate
Condition="'$(BUILD_COMMENT)'==''"
Files="..\src\SolutionInfo.cs"
Regex="AssemblyInformationalVersion\(&quot;(.+)?&quot;\)"
ReplacementText="AssemblyInformationalVersion(&quot;$(BUILD_RELEASE)&quot;)"/>
<!--This updates the copyright year-->
<FileUpdate
Condition="'$(BUILD_COMMENT)'==''"
Files="..\src\SolutionInfo.cs"
Regex="AssemblyCopyright\(&quot;Copyright © Umbraco (\d{4})&quot;\)"
ReplacementText="AssemblyCopyright(&quot;Copyright © Umbraco $([System.DateTime]::Now.ToString(`yyyy`))&quot;)"/>
<XmlPoke XmlInputPath=".\NuSpecs\build\UmbracoCms.props"
Namespaces="&lt;Namespace Prefix='x' Uri='http://schemas.microsoft.com/developer/msbuild/2003' /&gt;"
Query="//x:UmbracoVersion"
Value="$(NewVersion)" />
</Target>
</Project>
@@ -1,74 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>UmbracoCms.Core.AllBinaries</id>
<version>6.1.2</version>
<title>Umbraco Cms Core All Binaries</title>
<authors>Morten Christensen</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
</metadata>
<files>
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\bin\AutoMapper.dll" target="lib\AutoMapper.dll" />
<file src="..\_BuildOutput\bin\AutoMapper.Net4.dll" target="lib\AutoMapper.Net4.dll" />
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\bin\ClientDependency.Core.dll" target="lib\ClientDependency.Core.dll" />
<file src="..\_BuildOutput\bin\ClientDependency.Core.Mvc.dll" target="lib\ClientDependency.Core.Mvc.dll" />
<file src="..\_BuildOutput\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\bin\CookComputing.XmlRpcV2.dll" target="lib\CookComputing.XmlRpcV2.dll" />
<file src="..\_BuildOutput\bin\Examine.dll" target="lib\Examine.dll" />
<file src="..\_BuildOutput\bin\HtmlAgilityPack.dll" target="lib\HtmlAgilityPack.dll" />
<file src="..\_BuildOutput\bin\ICSharpCode.SharpZipLib.dll" target="lib\ICSharpCode.SharpZipLib.dll" />
<file src="..\_BuildOutput\bin\ImageProcessor.dll" target="lib\ImageProcessor.dll" />
<file src="..\_BuildOutput\bin\ImageProcessor.Web.dll" target="lib\ImageProcessor.Web.dll" />
<file src="..\_BuildOutput\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\bin\Lucene.Net.dll" target="lib\Lucene.Net.dll" />
<file src="..\_BuildOutput\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.dll" target="lib\Microsoft.Threading.Tasks.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.Extensions.dll" target="lib\Microsoft.Threading.Tasks.Extensions.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Helpers.dll" target="lib\Microsoft.Web.Helpers.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Infrastructure.dll" target="lib\Microsoft.Web.Infrastructure.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Mvc.FixedDisplayModes.dll" target="lib\Microsoft.Web.Mvc.FixedDisplayModes.dll" />
<file src="..\_BuildOutput\bin\MiniProfiler.dll" target="lib\MiniProfiler.dll" />
<file src="..\_BuildOutput\bin\MySql.Data.dll" target="lib\MySql.Data.dll" />
<file src="..\_BuildOutput\bin\Newtonsoft.Json.dll" target="lib\Newtonsoft.Json.dll" />
<file src="..\_BuildOutput\bin\NuGet.Core.dll" target="lib\NuGet.Core.dll" />
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.dll" target="lib\System.Net.Http.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Extensions.dll" target="lib\System.Net.Http.Extensions.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Formatting.dll" target="lib\System.Net.Http.Formatting.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Primitives.dll" target="lib\System.Net.Http.Primitives.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.WebRequest.dll" target="lib\System.Net.Http.WebRequest.dll" />
<file src="..\_BuildOutput\bin\System.Web.Helpers.dll" target="lib\System.Web.Helpers.dll" />
<file src="..\_BuildOutput\bin\System.Web.Http.dll" target="lib\System.Web.Http.dll" />
<file src="..\_BuildOutput\bin\System.Web.Http.WebHost.dll" target="lib\System.Web.Http.WebHost.dll" />
<file src="..\_BuildOutput\bin\System.Web.Mvc.dll" target="lib\System.Web.Mvc.dll" />
<file src="..\_BuildOutput\bin\System.Web.Razor.dll" target="lib\System.Web.Razor.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Administration.dll" target="lib\System.Web.WebPages.Administration.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Deployment.dll" target="lib\System.Web.WebPages.Deployment.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.dll" target="lib\System.Web.WebPages.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Razor.dll" target="lib\System.Web.WebPages.Razor.dll" />
<file src="..\_BuildOutput\bin\TidyNet.dll" target="lib\TidyNet.dll" />
<file src="..\_BuildOutput\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
<file src="..\_BuildOutput\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\bin\umbraco.dll" target="lib\umbraco.dll" />
<file src="..\_BuildOutput\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
</files>
<metadata>
<id>UmbracoCms.Core.AllBinaries</id>
<version>6.1.2</version>
<title>Umbraco Cms Core All Binaries</title>
<authors>Morten Christensen</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
</metadata>
<files>
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\bin\AutoMapper.dll" target="lib\AutoMapper.dll" />
<file src="..\_BuildOutput\bin\AutoMapper.Net4.dll" target="lib\AutoMapper.Net4.dll" />
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\bin\ClientDependency.Core.dll" target="lib\ClientDependency.Core.dll" />
<file src="..\_BuildOutput\bin\ClientDependency.Core.Mvc.dll" target="lib\ClientDependency.Core.Mvc.dll" />
<file src="..\_BuildOutput\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\bin\CookComputing.XmlRpcV2.dll" target="lib\CookComputing.XmlRpcV2.dll" />
<file src="..\_BuildOutput\bin\Examine.dll" target="lib\Examine.dll" />
<file src="..\_BuildOutput\bin\HtmlAgilityPack.dll" target="lib\HtmlAgilityPack.dll" />
<file src="..\_BuildOutput\bin\ICSharpCode.SharpZipLib.dll" target="lib\ICSharpCode.SharpZipLib.dll" />
<file src="..\_BuildOutput\bin\ImageProcessor.dll" target="lib\ImageProcessor.dll" />
<file src="..\_BuildOutput\bin\ImageProcessor.Web.dll" target="lib\ImageProcessor.Web.dll" />
<file src="..\_BuildOutput\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\bin\Lucene.Net.dll" target="lib\Lucene.Net.dll" />
<file src="..\_BuildOutput\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.dll" target="lib\Microsoft.Threading.Tasks.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.Extensions.dll" target="lib\Microsoft.Threading.Tasks.Extensions.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Infrastructure.dll" target="lib\Microsoft.Web.Infrastructure.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Mvc.FixedDisplayModes.dll" target="lib\Microsoft.Web.Mvc.FixedDisplayModes.dll" />
<file src="..\_BuildOutput\bin\MiniProfiler.dll" target="lib\MiniProfiler.dll" />
<file src="..\_BuildOutput\bin\MySql.Data.dll" target="lib\MySql.Data.dll" />
<file src="..\_BuildOutput\bin\Newtonsoft.Json.dll" target="lib\Newtonsoft.Json.dll" />
<file src="..\_BuildOutput\bin\NuGet.Core.dll" target="lib\NuGet.Core.dll" />
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.dll" target="lib\System.Net.Http.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Extensions.dll" target="lib\System.Net.Http.Extensions.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Formatting.dll" target="lib\System.Net.Http.Formatting.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Primitives.dll" target="lib\System.Net.Http.Primitives.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.WebRequest.dll" target="lib\System.Net.Http.WebRequest.dll" />
<file src="..\_BuildOutput\bin\System.Web.Helpers.dll" target="lib\System.Web.Helpers.dll" />
<file src="..\_BuildOutput\bin\System.Web.Http.dll" target="lib\System.Web.Http.dll" />
<file src="..\_BuildOutput\bin\System.Web.Http.WebHost.dll" target="lib\System.Web.Http.WebHost.dll" />
<file src="..\_BuildOutput\bin\System.Web.Mvc.dll" target="lib\System.Web.Mvc.dll" />
<file src="..\_BuildOutput\bin\System.Web.Razor.dll" target="lib\System.Web.Razor.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Administration.dll" target="lib\System.Web.WebPages.Administration.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Deployment.dll" target="lib\System.Web.WebPages.Deployment.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.dll" target="lib\System.Web.WebPages.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Razor.dll" target="lib\System.Web.WebPages.Razor.dll" />
<file src="..\_BuildOutput\bin\TidyNet.dll" target="lib\TidyNet.dll" />
<file src="..\_BuildOutput\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
<file src="..\_BuildOutput\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\bin\umbraco.dll" target="lib\umbraco.dll" />
<file src="..\_BuildOutput\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
</files>
</package>
+68 -68
View File
@@ -1,71 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>UmbracoCms.Core</id>
<version>7.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
</metadata>
<files>
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.dll" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.pdb" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.dll" target="lib" />
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.pdb" target="lib" />
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
<file src="..\..\src\umbraco.cms\obj\Debug\cms.dll" target="lib" />
<file src="..\..\src\umbraco.cms\obj\Debug\cms.pdb" target="lib" />
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
<file src="..\..\src\umbraco.controls\obj\Debug\controls.dll" target="lib" />
<file src="..\..\src\umbraco.controls\obj\Debug\controls.pdb" target="lib" />
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.dll" target="lib" />
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.pdb" target="lib" />
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.dll" target="lib" />
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.pdb" target="lib" />
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.dll" target="lib" />
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.pdb" target="lib" />
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.dll" target="lib" />
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.pdb" target="lib" />
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.dll" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.pdb" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.dll" target="lib" />
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.pdb" target="lib" />
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.dll" target="lib" />
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.dll" target="lib" />
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.dll" target="lib" />
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.pdb" target="lib" />
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
</files>
<metadata>
<id>UmbracoCms.Core</id>
<version>7.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
</metadata>
<files>
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.dll" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.pdb" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.dll" target="lib" />
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.pdb" target="lib" />
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
<file src="..\..\src\umbraco.cms\obj\Debug\cms.dll" target="lib" />
<file src="..\..\src\umbraco.cms\obj\Debug\cms.pdb" target="lib" />
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
<file src="..\..\src\umbraco.controls\obj\Debug\controls.dll" target="lib" />
<file src="..\..\src\umbraco.controls\obj\Debug\controls.pdb" target="lib" />
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.dll" target="lib" />
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.pdb" target="lib" />
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.dll" target="lib" />
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.pdb" target="lib" />
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.dll" target="lib" />
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.pdb" target="lib" />
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.dll" target="lib" />
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.pdb" target="lib" />
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.dll" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.pdb" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.dll" target="lib" />
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.pdb" target="lib" />
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.dll" target="lib" />
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.dll" target="lib" />
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.dll" target="lib" />
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.pdb" target="lib" />
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
</files>
</package>
+69 -70
View File
@@ -1,73 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>UmbracoCms.Core</id>
<version>7.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.30506.0,5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi" version="[4.0.30506,5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.WebHost" version="[4.0.30506, 5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.Core" version="[4.0.30506, 5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.Client" version="[4.0.30506, 5.0.0)" />
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.1" />
<dependency id="Microsoft.Net.Http" version="[2.0.20710.0, 3.0.0)" />
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
<dependency id="MySql.Data" version="[6.6.5]" />
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.8.0, 2.0.0)" />
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
<dependency id="Examine" version="[0.1.57, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
</dependencies>
</metadata>
<files>
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\WebApp\bin\Microsoft.Web.Helpers.dll" target="lib\Microsoft.Web.Helpers.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\umbraco.DataLayer.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
</files>
<metadata>
<id>UmbracoCms.Core</id>
<version>7.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.30506.0,6.0.0)" />
<dependency id="Microsoft.AspNet.WebApi" version="[4.0.30506,6.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.WebHost" version="[4.0.30506, 6.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.Core" version="[4.0.30506, 6.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.Client" version="[4.0.30506, 6.0.0)" />
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.1" />
<dependency id="Microsoft.Net.Http" version="[2.0.20710.0, 3.0.0)" />
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
<dependency id="MySql.Data" version="[6.6.5]" />
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.8.3.1, 2.0.0)" />
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
<dependency id="Examine" version="[0.1.62, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
</dependencies>
</metadata>
<files>
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\umbraco.DataLayer.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
</files>
</package>
+32 -37
View File
@@ -1,45 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="2.8">
<id>UmbracoCms</id>
<version>7.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
</dependencies>
</metadata>
<metadata minClientVersion="2.8">
<id>UmbracoCms</id>
<version>7.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
</dependencies>
</metadata>
<files>
<file src="..\_BuildOutput\Configs\**" target="Content\config" exclude="..\_BuildOutput\Configs\Web.config.transform" />
<file src="..\_BuildOutput\WebApp\css\**" target="Content\css" />
<file src="..\_BuildOutput\WebApp\masterpages\**" target="Content\masterpages" />
<file src="..\_BuildOutput\WebApp\media\**" target="Content\media" />
<file src="..\_BuildOutput\WebApp\scripts\**" target="Content\scripts" />
<file src="..\_BuildOutput\WebApp\usercontrols\**" target="Content\usercontrols" />
<file src="..\_BuildOutput\WebApp\Views\**" target="Content\Views" exclude="..\_BuildOutput\WebApp\Views\Web.config" />
<file src="..\_BuildOutput\WebApp\xslt\**" target="Content\xslt" />
<file src="..\_BuildOutput\WebApp\default.aspx" target="Content\default.aspx" />
<file src="..\_BuildOutput\WebApp\Global.asax" target="Content\Global.asax" />
<file src="..\_BuildOutput\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="..\_BuildOutput\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
<file src="..\_BuildOutput\WebApp\App_Plugins\**" target="UmbracoFiles\App_Plugins" />
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="UmbracoFiles\bin\amd64" />
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="UmbracoFiles\bin\x86" />
<file src="..\_BuildOutput\WebApp\config\splashes\**" target="UmbracoFiles\config\splashes" />
<file src="..\_BuildOutput\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="..\_BuildOutput\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
<file src="..\_BuildOutput\Configs\**" target="Content\Config" exclude="..\_BuildOutput\Configs\Web.config.transform" />
<file src="..\_BuildOutput\WebApp\Views\**" target="Content\Views" exclude="..\_BuildOutput\WebApp\Views\Web.config" />
<file src="..\_BuildOutput\WebApp\default.aspx" target="Content\default.aspx" />
<file src="..\_BuildOutput\WebApp\Global.asax" target="Content\Global.asax" />
<file src="..\_BuildOutput\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="..\_BuildOutput\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
<file src="..\_BuildOutput\WebApp\App_Plugins\**" target="UmbracoFiles\App_Plugins" />
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="UmbracoFiles\bin\amd64" />
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="UmbracoFiles\bin\x86" />
<file src="..\_BuildOutput\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="..\_BuildOutput\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="..\_BuildOutput\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
+20 -20
View File
@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>UmbracoExamine.PDF</id>
<version>0.7.0</version>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://umbraco.codeplex.com/license</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>UmbracoExmine.PDF</description>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[7.0.0, 8.0.0)" />
<dependency id="iTextSharp" version="[5.5.3, 6.0.0)" />
</dependencies>
</metadata>
<files>
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.dll" target="lib\UmbracoExamine.PDF.dll" />
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.XML" target="lib\UmbracoExamine.PDF.XML" />
</files>
<metadata>
<id>UmbracoExamine.PDF</id>
<version>0.7.0</version>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>UmbracoExmine.PDF</description>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[7.0.0, 8.0.0)" />
<dependency id="iTextSharp" version="[5.5.3, 6.0.0)" />
</dependencies>
</metadata>
<files>
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.dll" target="lib\UmbracoExamine.PDF.dll" />
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.XML" target="lib\UmbracoExamine.PDF.XML" />
</files>
</package>
+9 -9
View File
@@ -1,18 +1,18 @@
A note about running Umbraco from Visual Studio.
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
| | | | \ / | |_) | |__) | / \ | | | | | |
| | | | |\/| | _ <| _ / / /\ \| | | | | |
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
----------------------------------------------------
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
sure to do a compare and merge with the NuGetBackup folder.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
+33
View File
@@ -0,0 +1,33 @@
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
| | | | \ / | |_) | |__) | / \ | | | | | |
| | | | |\/| | _ <| _ / / /\ \| | | | | |
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
----------------------------------------------------
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
sure to do a compare and merge with the NuGetBackup folder.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, umbraco_client, config\splashes and global.asax.
Please read the release notes on our.umbraco.org:
http://our.umbraco.org/contribute/releases
- Umbraco
-2
View File
@@ -27,7 +27,6 @@ if ($project) {
if(Test-Path $umbracoBinFolder\interfaces.dll) { Remove-Item $umbracoBinFolder\interfaces.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\log4net.dll) { Remove-Item $umbracoBinFolder\log4net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\SQLCE4Umbraco.dll) { Remove-Item $umbracoBinFolder\SQLCE4Umbraco.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
@@ -64,7 +63,6 @@ if ($project) {
if(Test-Path $umbracoBinFolder\MySql.Data.dll) { Remove-Item $umbracoBinFolder\MySql.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\System.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.WebHost.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.WebHost.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Mvc.dll) { Remove-Item $umbracoBinFolder\System.Web.Mvc.dll -Force -Confirm:$false }
+31 -93
View File
@@ -47,108 +47,46 @@ if ($project) {
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
}
$copyWebconfig = $false
try
{
# SJ - What can I say: big up for James Newton King for teaching us a hack for detecting if this is a new install vs. an upgrade!
# https://github.com/JamesNK/Newtonsoft.Json/pull/387 - would never have seen this without the controversial pull request..
$dte2 = Get-Interface $dte ([EnvDTE80.DTE2])
if ($dte2.ActiveWindow.Caption -eq "Package Manager Console")
{
# user is installing from VS NuGet console
# get reference to the window, the console host and the input history
# copy web.config if "install-package UmbracoCms" was last input
$consoleWindow = $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow])
$props = $consoleWindow.GetType().GetProperties([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
$prop = $props | ? { $_.Name -eq "ActiveHostInfo" } | select -first 1
if ($prop -eq $null) { return }
$hostInfo = $prop.GetValue($consoleWindow)
if ($hostInfo -eq $null) { return }
$history = $hostInfo.WpfConsole.InputHistory.History
$lastCommand = $history | select -last 1
if ($lastCommand)
{
$lastCommand = $lastCommand.Trim().ToLower()
if ($lastCommand.StartsWith("install-package") -and $lastCommand.Contains("umbracocms"))
{
$copyWebconfig = $true
}
}
}
else
{
# user is installing from VS NuGet dialog
# get reference to the window, then smart output console provider
# copy web.config if messages in buffered console contains "installing...UmbracoCms" in last operation
$instanceField = [NuGet.Dialog.PackageManagerWindow].GetField("CurrentInstance", [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::NonPublic)
$consoleField = [NuGet.Dialog.PackageManagerWindow].GetField("_smartOutputConsoleProvider", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
if ($instanceField -eq $null -or $consoleField -eq $null) { return }
$instance = $instanceField.GetValue($null)
if ($instance -eq $null) { return }
$consoleProvider = $consoleField.GetValue($instance)
if ($consoleProvider -eq $null) { return }
$console = $consoleProvider.CreateOutputConsole($false)
$messagesField = $console.GetType().GetField("_messages", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
if ($messagesField -eq $null) { return }
$messages = $messagesField.GetValue($console)
if ($messages -eq $null) { return }
$operations = $messages -split "=============================="
$lastOperation = $operations | select -last 1
if ($lastOperation)
{
$lastOperation = $lastOperation.ToLower()
$lines = $lastOperation -split "`r`n"
$installMatch = $lines | ? { $_.StartsWith("------- installing...umbracocms ") } | select -first 1
if ($installMatch)
{
$copyWebconfig = $true
}
}
}
}
catch
{
# stop potential errors from bubbling up
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
$installLogFile = Join-Path $projectDestinationPath "NuGetInstallError.log"
$text = "Error occurred: " + $ErrorMessage + " failure: " + $FailedItem
$text | Out-File $installLogFile
}
$copyWebconfig = $true
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
if(Test-Path $destinationWebConfig)
{
Try
{
[xml]$config = Get-Content $destinationWebConfig
$config.configuration.appSettings.ChildNodes | ForEach-Object {
if($_.key -eq "umbracoConfigurationStatus")
{
# The web.config has an umbraco-specific appSetting in it
# don't overwrite it and let config transforms do their thing
$copyWebconfig = $false
}
}
}
Catch { }
}
if($copyWebconfig -eq $true)
{
$packageWebConfigSource = Join-Path $rootPath "UmbracoFiles\Web.config"
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
}
}
$installFolder = Join-Path $projectDestinationPath "Install"
if(Test-Path $installFolder) {
Remove-Item $installFolder -Force -Recurse -Confirm:$false
}
# Open readme.txt file
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
# Open appropriate readme
if($copyWebconfig -eq $true)
{
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
}
else
{
$DTE.ItemOperations.OpenFile($toolsPath + '\ReadmeUpgrade.txt')
}
}
+2 -1
View File
@@ -1,2 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.2.0
7.2.5
RC
-13
View File
@@ -1,13 +0,0 @@
Umbraco CMS version 4.5 is licensed under the OSI approved MIT License:
Copyright (c) 2007-2010 umbraco I/S.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Umbraco versions prior to 4.5 were licensed under a combination of MIT and a propriatary UI license. The license history can be found here:
http://umbraco.codeplex.com/license
-33
View File
@@ -1,33 +0,0 @@
Umbraco - the simple, flexible and friendly ASP.NET CMS
=======================================================
For the first time on the Microsoft platform a free user and developer friendly cms that makes it quick and easy to create websites - or a breeze to build complex web applications. umbraco got award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too. Used by more than 57.000 active websites including Heinz.com, Peugeot.com, NAIAS.com and Microsofts documentinteropinitiative.org website you can be sure that the technology is proven, stable and scales.
More info at http://umbraco.com
Exploring the repository
========================
Most contributors will work on their own fork and should pick the branch in which they need their fix. For more information see:
http://our.umbraco.org/contribute/guidelines-for-core-contribution
Exploring the source
====================
The Umbraco source code is never required for you to start building sites. If you are not using the source code for debugging purposes or to contribute to the source then please download the binaries listed at http://umbraco.codeplex.com
With that said, the Umbraco solution can be opened in Visual Studio 2010 with SP1 installed or Visual Studio 2012.
Contributing
============
Umbraco is Open Source which means you can contribute to make it great!
Read all about it at http://our.umbraco.org/contribute
Forums
======
We have a forum running on http://our.umbraco.org for friendly community support.
Documentation
=============
Our documentation section provides help on installing and using Umbraco including API reference documentation: http://our.umbraco.org/documentation
Submitting Issues
=================
Another way you can contribute to Umbraco is by providing issue reports, for information on how to submit an issue report refer to our online guide at http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature
+6 -3
View File
@@ -1,8 +1,8 @@
using System.Reflection;
using System.Reflection;
using System.Resources;
[assembly: AssemblyCompany("umbraco")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2012")]
[assembly: AssemblyCompany("Umbraco")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -10,3 +10,6 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.2.5")]
[assembly: AssemblyInformationalVersion("7.2.5-RC")]
+198
View File
@@ -0,0 +1,198 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Threading;
using System.Threading.Tasks;
namespace Umbraco.Core
{
// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
//
// notes:
// - this is NOT a reader/writer lock
// - this is NOT a recursive lock
//
internal class AsyncLock
{
private readonly SemaphoreSlim _semaphore;
private readonly Semaphore _semaphore2;
private readonly IDisposable _releaser;
private readonly Task<IDisposable> _releaserTask;
public AsyncLock()
: this (null)
{ }
public AsyncLock(string name)
{
// WaitOne() waits until count > 0 then decrements count
// Release() increments count
// initial count: the initial count value
// maximum count: the max value of count, and then Release() throws
if (string.IsNullOrWhiteSpace(name))
{
// anonymous semaphore
// use one unique releaser, that will not release the semaphore when finalized
// because the semaphore is destroyed anyway if the app goes down
_semaphore = new SemaphoreSlim(1, 1); // create a local (to the app domain) semaphore
_releaser = new SemaphoreSlimReleaser(_semaphore);
_releaserTask = Task.FromResult(_releaser);
}
else
{
// named semaphore
// use dedicated releasers, that will release the semaphore when finalized
// because the semaphore is system-wide and we cannot leak counts
_semaphore2 = new Semaphore(1, 1, name); // create a system-wide named semaphore
}
}
private IDisposable CreateReleaser()
{
// for anonymous semaphore, use the unique releaser, else create a new one
return _semaphore != null
? _releaser // (IDisposable)new SemaphoreSlimReleaser(_semaphore)
: (IDisposable)new NamedSemaphoreReleaser(_semaphore2);
}
public Task<IDisposable> LockAsync()
{
var wait = _semaphore != null
? _semaphore.WaitAsync()
: WaitOneAsync(_semaphore2);
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IDisposable Lock()
{
if (_semaphore != null)
_semaphore.Wait();
else
_semaphore2.WaitOne();
return _releaser ?? CreateReleaser(); // anonymous vs named
}
public IDisposable Lock(int millisecondsTimeout)
{
var entered = _semaphore != null
? _semaphore.Wait(millisecondsTimeout)
: _semaphore2.WaitOne(millisecondsTimeout);
if (entered == false)
throw new TimeoutException("Failed to enter the lock within timeout.");
return _releaser ?? CreateReleaser(); // anonymous vs named
}
// note - before making those classes some structs, read
// about "impure methods" and mutating readonly structs...
private class NamedSemaphoreReleaser : CriticalFinalizerObject, IDisposable
{
private readonly Semaphore _semaphore;
internal NamedSemaphoreReleaser(Semaphore semaphore)
{
_semaphore = semaphore;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
// critical
_semaphore.Release();
}
// we WANT to release the semaphore because it's a system object
// ie a critical non-managed resource - so we inherit from CriticalFinalizerObject
// which means that the finalizer "should" run in all situations
// however... that can fail with System.ObjectDisposedException because the
// underlying handle was closed... because we cannot guarantee that the semaphore
// is not gone already... unless we get a GCHandle = GCHandle.Alloc(_semaphore);
// which should keep it around and then we free the handle?
// so... I'm not sure this is safe really...
~NamedSemaphoreReleaser()
{
Dispose(false);
}
}
private class SemaphoreSlimReleaser : IDisposable
{
private readonly SemaphoreSlim _semaphore;
internal SemaphoreSlimReleaser(SemaphoreSlim semaphore)
{
_semaphore = semaphore;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
// normal
_semaphore.Release();
}
}
~SemaphoreSlimReleaser()
{
Dispose(false);
}
}
// http://stackoverflow.com/questions/25382583/waiting-on-a-named-semaphore-with-waitone100-vs-waitone0-task-delay100
// http://blog.nerdbank.net/2011/07/c-await-for-waithandle.html
// F# has a AwaitWaitHandle method that accepts a time out... and seems pretty complex...
// version below should be OK
private static Task WaitOneAsync(WaitHandle handle)
{
var tcs = new TaskCompletionSource<object>();
var callbackHandleInitLock = new object();
lock (callbackHandleInitLock)
{
RegisteredWaitHandle callbackHandle = null;
// ReSharper disable once RedundantAssignment
callbackHandle = ThreadPool.RegisterWaitForSingleObject(
handle,
(state, timedOut) =>
{
tcs.SetResult(null);
// we take a lock here to make sure the outer method has completed setting the local variable callbackHandle.
lock (callbackHandleInitLock)
{
// ReSharper disable once PossibleNullReferenceException
// ReSharper disable once AccessToModifiedClosure
callbackHandle.Unregister(null);
}
},
/*state:*/ null,
/*millisecondsTimeOutInterval:*/ Timeout.Infinite,
/*executeOnlyOnce:*/ true);
}
return tcs.Task;
}
}
}
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Cache
/// <summary>
/// Extensions for strongly typed access
/// </summary>
internal static class CacheProviderExtensions
public static class CacheProviderExtensions
{
public static T GetCacheItem<T>(this IRuntimeCacheProvider provider,
string cacheKey,
@@ -6,6 +6,10 @@
bool InternalRedirectPreservesTemplate { get; }
bool DisableAlternativeTemplates { get; }
bool DisableFindContentByIdPath { get; }
string UrlProviderMode { get; }
}
@@ -16,6 +16,17 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return (bool) base["internalRedirectPreservesTemplate"]; }
}
[ConfigurationProperty("disableAlternativeTemplates", DefaultValue = "false")]
public bool DisableAlternativeTemplates
{
get { return (bool) base["disableAlternativeTemplates"]; }
}
[ConfigurationProperty("disableFindContentByIdPath", DefaultValue = "false")]
public bool DisableFindContentByIdPath
{
get { return (bool) base["disableFindContentByIdPath"]; }
}
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
public string UrlProviderMode
{
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.2.0");
private static readonly Version Version = new Version("7.2.5");
/// <summary>
/// Gets the current version of Umbraco.
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return ""; } }
public static string CurrentComment { get { return "RC"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
+9 -18
View File
@@ -192,73 +192,64 @@ namespace Umbraco.Core
{
{
Comments,
new PropertyType(PropertyEditors.TextboxMultipleAlias, DataTypeDatabaseType.Ntext, true)
new PropertyType(PropertyEditors.TextboxMultipleAlias, DataTypeDatabaseType.Ntext, true, Comments)
{
Alias = Comments,
Name = CommentsLabel
}
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Integer, true)
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Integer, true, FailedPasswordAttempts)
{
Alias = FailedPasswordAttempts,
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer, true)
new PropertyType(PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer, true, IsApproved)
{
Alias = IsApproved,
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer, true)
new PropertyType(PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer, true, IsLockedOut)
{
Alias = IsLockedOut,
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, true)
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, true, LastLockoutDate)
{
Alias = LastLockoutDate,
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, true)
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, true, LastLoginDate)
{
Alias = LastLoginDate,
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, true)
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date, true, LastPasswordChangeDate)
{
Alias = LastPasswordChangeDate,
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Nvarchar, true)
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Nvarchar, true, PasswordAnswer)
{
Alias = PasswordAnswer,
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Nvarchar, true)
new PropertyType(PropertyEditors.NoEditAlias, DataTypeDatabaseType.Nvarchar, true, PasswordQuestion)
{
Alias = PasswordQuestion,
Name = PasswordQuestionLabel
}
}
+9 -2
View File
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using AutoMapper;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Mapping;
using Umbraco.Core.Models.PublishedContent;
@@ -21,6 +23,7 @@ using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Publishing;
using Umbraco.Core.Macros;
using Umbraco.Core.Manifest;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Core.Strings;
@@ -259,8 +262,12 @@ namespace Umbraco.Core
/// </summary>
protected virtual void InitializeResolvers()
{
PropertyEditorResolver.Current = new PropertyEditorResolver(() => PluginManager.Current.ResolvePropertyEditors());
ParameterEditorResolver.Current = new ParameterEditorResolver(() => PluginManager.Current.ResolveParameterEditors());
var builder = new ManifestBuilder(
ApplicationCache.RuntimeCache,
new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), ApplicationCache.RuntimeCache));
PropertyEditorResolver.Current = new PropertyEditorResolver(() => PluginManager.Current.ResolvePropertyEditors(), builder);
ParameterEditorResolver.Current = new ParameterEditorResolver(() => PluginManager.Current.ResolveParameterEditors(), builder);
//setup the validators resolver with our predefined validators
ValidatorsResolver.Current = new ValidatorsResolver(new[]
@@ -5,6 +5,7 @@ using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Dynamics
@@ -34,38 +35,42 @@ namespace Umbraco.Core.Dynamics
FoundExtensionMethod
}
/// <summary>
/// Attempts to invoke a member based on the dynamic instance
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="thisObject">The object instance to invoke the extension method for</param>
/// <param name="binder"></param>
/// <param name="args"></param>
/// <returns></returns>
/// <remarks>
/// First tries to find a property with the binder name, if that fails it will try to find a static or instance method
/// on the object that matches the binder name
/// </remarks>
public static Attempt<TryInvokeMemberResult> TryInvokeMember<T>(T thisObject, InvokeMemberBinder binder, object[] args)
/// <summary>
/// Attempts to invoke a member based on the dynamic instance
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="runtimeCache"></param>
/// <param name="thisObject">The object instance to invoke the extension method for</param>
/// <param name="binder"></param>
/// <param name="args"></param>
/// <returns></returns>
/// <remarks>
/// First tries to find a property with the binder name, if that fails it will try to find a static or instance method
/// on the object that matches the binder name
/// </remarks>
public static Attempt<TryInvokeMemberResult> TryInvokeMember<T>(IRuntimeCacheProvider runtimeCache, T thisObject, InvokeMemberBinder binder, object[] args)
{
return TryInvokeMember<T>(thisObject, binder, args, null);
return TryInvokeMember<T>(runtimeCache, thisObject, binder, args, null);
}
/// <summary>
/// Attempts to invoke a member based on the dynamic instance
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="thisObject">The object instance to invoke the extension method for</param>
/// <param name="binder"></param>
/// <param name="args"></param>
/// <param name="findExtensionMethodsOnTypes">The types to scan for extension methods </param>
/// <returns></returns>
/// <remarks>
/// First tries to find a property with the binder name, if that fails it will try to find a static or instance method
/// on the object that matches the binder name, if that fails it will then attempt to invoke an extension method
/// based on the binder name and the extension method types to scan.
/// </remarks>
public static Attempt<TryInvokeMemberResult> TryInvokeMember<T>(T thisObject,
/// <summary>
/// Attempts to invoke a member based on the dynamic instance
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="runtimeCache"></param>
/// <param name="thisObject">The object instance to invoke the extension method for</param>
/// <param name="binder"></param>
/// <param name="args"></param>
/// <param name="findExtensionMethodsOnTypes">The types to scan for extension methods </param>
/// <returns></returns>
/// <remarks>
/// First tries to find a property with the binder name, if that fails it will try to find a static or instance method
/// on the object that matches the binder name, if that fails it will then attempt to invoke an extension method
/// based on the binder name and the extension method types to scan.
/// </remarks>
public static Attempt<TryInvokeMemberResult> TryInvokeMember<T>(
IRuntimeCacheProvider runtimeCache,
T thisObject,
InvokeMemberBinder binder,
object[] args,
IEnumerable<Type> findExtensionMethodsOnTypes)
@@ -76,9 +81,9 @@ namespace Umbraco.Core.Dynamics
{
//Property?
result = typeof(T).InvokeMember(binder.Name,
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.GetProperty,
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.GetProperty,
null,
thisObject,
args);
@@ -90,10 +95,10 @@ namespace Umbraco.Core.Dynamics
{
//Static or Instance Method?
result = typeof(T).InvokeMember(binder.Name,
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.InvokeMethod,
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.InvokeMethod,
null,
thisObject,
args);
@@ -105,7 +110,7 @@ namespace Umbraco.Core.Dynamics
{
try
{
result = FindAndExecuteExtensionMethod(thisObject, args, binder.Name, findExtensionMethodsOnTypes);
result = FindAndExecuteExtensionMethod(runtimeCache, thisObject, args, binder.Name, findExtensionMethodsOnTypes);
return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod));
}
catch (TargetInvocationException ext)
@@ -138,16 +143,19 @@ namespace Umbraco.Core.Dynamics
}
}
/// <summary>
/// Attempts to find an extension method that matches the name and arguments based on scanning the Type's passed in
/// to the findMethodsOnTypes parameter
/// </summary>
/// <param name="thisObject">The instance object to execute the extension method for</param>
/// <param name="args"></param>
/// <param name="name"></param>
/// <param name="findMethodsOnTypes"></param>
/// <returns></returns>
internal static object FindAndExecuteExtensionMethod<T>(T thisObject,
/// <summary>
/// Attempts to find an extension method that matches the name and arguments based on scanning the Type's passed in
/// to the findMethodsOnTypes parameter
/// </summary>
/// <param name="runtimeCache"></param>
/// <param name="thisObject">The instance object to execute the extension method for</param>
/// <param name="args"></param>
/// <param name="name"></param>
/// <param name="findMethodsOnTypes"></param>
/// <returns></returns>
internal static object FindAndExecuteExtensionMethod<T>(
IRuntimeCacheProvider runtimeCache,
T thisObject,
object[] args,
string name,
IEnumerable<Type> findMethodsOnTypes)
@@ -158,7 +166,7 @@ namespace Umbraco.Core.Dynamics
MethodInfo toExecute = null;
foreach (var t in findMethodsOnTypes)
{
toExecute = ExtensionMethodFinder.FindExtensionMethod(t, args, name, false);
toExecute = ExtensionMethodFinder.FindExtensionMethod(runtimeCache, t, args, name, false);
if (toExecute != null)
break;
}
@@ -166,6 +174,13 @@ namespace Umbraco.Core.Dynamics
if (toExecute != null)
{
var genericArgs = (new[] { (object)thisObject }).Concat(args);
// else we'd get an exception w/ message "Late bound operations cannot
// be performed on types or methods for which ContainsGenericParameters is true."
// because MakeGenericMethod must be used to obtain an actual method that can run
if (toExecute.ContainsGenericParameters)
throw new InvalidOperationException("Method contains generic parameters, something's wrong.");
result = toExecute.Invoke(null, genericArgs.ToArray());
}
else
+4 -1
View File
@@ -10,6 +10,7 @@ using System.Collections;
using System.IO;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Cache;
namespace Umbraco.Core.Dynamics
{
@@ -162,8 +163,10 @@ namespace Umbraco.Core.Dynamics
return true; //anyway
}
var runtimeCache = ApplicationContext.Current != null ? ApplicationContext.Current.ApplicationCache.RuntimeCache : new NullCacheProvider();
//ok, now lets try to match by member, property, extensino method
var attempt = DynamicInstanceHelper.TryInvokeMember(this, binder, args, new[]
var attempt = DynamicInstanceHelper.TryInvokeMember(runtimeCache, this, binder, args, new[]
{
typeof (IEnumerable<DynamicXml>),
typeof (IEnumerable<XElement>),
+126 -252
View File
@@ -1,11 +1,12 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using System.Runtime.CompilerServices;
using System.Collections;
using System.Linq.Expressions;
using System.Web.Services.Description;
using Umbraco.Core.Cache;
namespace Umbraco.Core.Dynamics
{
@@ -14,279 +15,152 @@ namespace Umbraco.Core.Dynamics
/// </summary>
internal static class ExtensionMethodFinder
{
private static readonly MethodInfo[] AllExtensionMethods;
/// <summary>
/// The static cache for extension methods found that match the criteria that we are looking for
/// </summary>
private static readonly ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]> MethodCache = new ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]>();
static ExtensionMethodFinder()
{
AllExtensionMethods = TypeFinder.GetAssembliesWithKnownExclusions()
/// <summary>
/// Returns the enumerable of all extension method info's in the app domain = USE SPARINGLY!!!
/// </summary>
/// <returns></returns>
/// <remarks>
/// We cache this as a sliding 5 minute exiration, in unit tests there's over 1100 methods found, surely that will eat up a bit of memory so we want
/// to make sure we give it back.
/// </remarks>
private static IEnumerable<MethodInfo> GetAllExtensionMethodsInAppDomain(IRuntimeCacheProvider runtimeCacheProvider)
{
if (runtimeCacheProvider == null) throw new ArgumentNullException("runtimeCacheProvider");
return runtimeCacheProvider.GetCacheItem<MethodInfo[]>(typeof (ExtensionMethodFinder).Name, () => TypeFinder.GetAssembliesWithKnownExclusions()
// assemblies that contain extension methods
.Where(a => a.IsDefined(typeof(ExtensionAttribute), false))
.Where(a => a.IsDefined(typeof (ExtensionAttribute), false))
// types that contain extension methods
.SelectMany(a => a.GetTypes()
.Where(t => t.IsDefined(typeof(ExtensionAttribute), false) && t.IsSealed && t.IsGenericType == false && t.IsNested == false))
.Where(t => t.IsDefined(typeof (ExtensionAttribute), false) && t.IsSealed && t.IsGenericType == false && t.IsNested == false))
// actual extension methods
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.IsDefined(typeof(ExtensionAttribute), false)))
.Where(m => m.IsDefined(typeof (ExtensionAttribute), false)))
// and also IEnumerable<T> extension methods - because the assembly is excluded
.Concat(typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public))
.ToArray();
}
.Concat(typeof (Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public))
//If we don't do this then we'll be scanning all assemblies each time!
.ToArray(),
//only cache for 5 minutes
timeout: TimeSpan.FromMinutes(5),
// ORIGINAL CODE IS NOT COMPLETE, DOES NOT HANDLE GENERICS, ETC...
// so this is an attempt at fixing things, but it's not done yet
// and do we really want to do this? extension methods are not supported on dynamics, period
// we should use strongly typed content instead of dynamics.
/*
// get all extension methods for type thisType, with name name,
// accepting argsCount arguments (not counting the instance of thisType).
private static IEnumerable<MethodInfo> GetExtensionMethods(Type thisType, string name, int argsCount)
{
var key = string.Format("{0}.{1}::{2}", thisType.FullName, name, argsCount);
var types = thisType.GetBaseTypes(true); // either do this OR have MatchFirstParameter handle the stuff... F*XME
var methods = AllExtensionMethods
.Where(m => m.Name == name)
.Where(m => m.GetParameters().Length == argsCount)
.Where(m => MatchFirstParameter(thisType, m.GetParameters()[0].ParameterType));
// f*xme - is this what we should cache?
return methods;
//each time this is accessed it will be for 5 minutes longer
isSliding:true);
}
// find out whether the first parameter is a match for thisType
private static bool MatchFirstParameter(Type thisType, Type firstParameterType)
{
return MethodArgZeroHasCorrectTargetType(null, firstParameterType, thisType);
}
// get the single extension method for type thisType, with name name,
// that accepts the arguments in args (which does not contain the instance of thisType).
public static MethodInfo GetExtensionMethod(Type thisType, string name, object[] args)
{
MethodInfo result = null;
foreach (var method in GetExtensionMethods(thisType, name, args.Length).Where(m => MatchParameters(m, args)))
{
if (result == null)
result = method;
else
throw new AmbiguousMatchException("More than one matching extension method was found.");
}
return result;
}
// find out whether the method can accept the arguments
private static bool MatchParameters(MethodInfo method, IList<object> args)
{
var parameters = method.GetParameters();
var i = 0;
for (; i < parameters.Length; ++i)
{
if (MatchParameter(parameters[i].ParameterType, args[i].GetType()) == false)
break;
}
return (i == parameters.Length);
}
internal static bool MatchParameter(Type parameterType, Type argumentType)
{
// public static int DoSomething<T>(Foo foo, T t1, T t2)
// DoSomething(foo, t1, t2) => how can we match?!
return parameterType == argumentType; // f*xme of course!
}
*
*/
// BELOW IS THE ORIGINAL CODE...
/// <summary>
/// Returns all extension methods found matching the definition
/// </summary>
/// <param name="thisType"></param>
/// <param name="name"></param>
/// <param name="argumentCount"></param>
/// <param name="argsContainsThis"></param>
/// <returns></returns>
/// <remarks>
/// TODO: NOTE: This will be an intensive method to call!! Results should be cached!
/// </remarks>
private static IEnumerable<MethodInfo> GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
{
// at *least* we can cache the extension methods discovery
var candidates = AllExtensionMethods;
/*
//only scan assemblies we know to contain extension methods (user assemblies)
var assembliesToScan = TypeFinder.GetAssembliesWithKnownExclusions();
//get extension methods from runtime
var candidates = (
from assembly in assembliesToScan
where assembly.IsDefined(typeof(ExtensionAttribute), false)
from type in assembly.GetTypes()
where (type.IsDefined(typeof(ExtensionAttribute), false)
&& type.IsSealed && !type.IsGenericType && !type.IsNested)
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)
// this filters extension methods
where method.IsDefined(typeof(ExtensionAttribute), false)
select method
);
//add the extension methods defined in IEnumerable
candidates = candidates.Concat(typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public));
*/
//filter by name
var methodsByName = candidates.Where(m => m.Name == name);
var isGenericAndRightParamCount = methodsByName.Where(m => m.GetParameters().Length == argumentCount + (argsContainsThis ? 0 : 1));
//find the right overload that can take genericParameterType
//which will be either DynamicNodeList or List<DynamicNode> which is IEnumerable`
var withGenericParameterType = isGenericAndRightParamCount.Select(m => new { m, t = FirstParameterType(m) });
var methodsWhereArgZeroIsTargetType = (from method in withGenericParameterType
where
method.t != null && MethodArgZeroHasCorrectTargetType(method.m, method.t, thisType)
select method);
return methodsWhereArgZeroIsTargetType.Select(mt => mt.m);
}
private static bool MethodArgZeroHasCorrectTargetType(MethodInfo method, Type firstArgumentType, Type thisType)
{
//This is done with seperate method calls because you can't debug/watch lamdas - if you're trying to figure
//out why the wrong method is returned, it helps to be able to see each boolean result
return
// is it defined on me?
MethodArgZeroHasCorrectTargetTypeTypeMatchesExactly(method, firstArgumentType, thisType) ||
// or on any of my interfaces?
MethodArgZeroHasCorrectTargetTypeAnInterfaceMatches(method, firstArgumentType, thisType) ||
// or on any of my base types?
MethodArgZeroHasCorrectTargetTypeIsASubclassOf(method, firstArgumentType, thisType) ||
//share a common interface (e.g. IEnumerable)
MethodArgZeroHasCorrectTargetTypeShareACommonInterface(method, firstArgumentType, thisType);
}
private static bool MethodArgZeroHasCorrectTargetTypeShareACommonInterface(MethodInfo method, Type firstArgumentType, Type thisType)
{
Type[] interfaces = firstArgumentType.GetInterfaces();
if (interfaces.Length == 0)
{
return false;
}
bool result = interfaces.All(i => thisType.GetInterfaces().Contains(i));
return result;
}
private static bool MethodArgZeroHasCorrectTargetTypeIsASubclassOf(MethodInfo method, Type firstArgumentType, Type thisType)
{
bool result = thisType.IsSubclassOf(firstArgumentType);
return result;
}
private static bool MethodArgZeroHasCorrectTargetTypeAnInterfaceMatches(MethodInfo method, Type firstArgumentType, Type thisType)
{
bool result = thisType.GetInterfaces().Contains(firstArgumentType);
return result;
}
private static bool MethodArgZeroHasCorrectTargetTypeTypeMatchesExactly(MethodInfo method, Type firstArgumentType, Type thisType)
{
bool result = (thisType == firstArgumentType);
return result;
}
private static Type FirstParameterType(MethodInfo m)
{
ParameterInfo[] p = m.GetParameters();
if (p.Any())
{
return p.First().ParameterType;
}
return null;
}
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
/// <summary>
/// Returns all extension methods found matching the definition
/// </summary>
/// <param name="runtimeCache">
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
/// while we search for individual extension methods, the process will be reasonably 'quick'. We then statically
/// cache the MethodInfo's that we are looking for and then the runtime cache will expire and give back all that memory.
/// </param>
/// <param name="thisType"></param>
/// <param name="name"></param>
/// <param name="argumentCount">
/// The arguments EXCLUDING the 'this' argument in an extension method
/// </param>
/// <returns></returns>
/// <remarks>
/// NOTE: This will be an intensive method to call! Results will be cached based on the key (args) of this method
/// </remarks>
internal static IEnumerable<MethodInfo> GetAllExtensionMethods(IRuntimeCacheProvider runtimeCache, Type thisType, string name, int argumentCount)
{
var key = new Tuple<Type, string, int>(thisType, name, argumentCount);
return MethodCache.GetOrAdd(key, tuple =>
{
var candidates = GetAllExtensionMethodsInAppDomain(runtimeCache);
// filter by name
var filtr1 = candidates.Where(m => m.Name == name);
// filter by args count
// ensure we add + 1 to the arg count because the 'this' arg is not included in the count above!
var filtr2 = filtr1.Where(m => m.GetParameters().Length == argumentCount + 1);
// filter by first parameter type (target of the extension method)
// ie find the right overload that can take genericParameterType
// (which will be either DynamicNodeList or List<DynamicNode> which is IEnumerable)
var filtr3 = filtr2.Select(x =>
{
var t = x.GetParameters()[0].ParameterType; // exists because of +1 above
var bindings = new Dictionary<string, Type>();
if (TypeHelper.MatchType(thisType, t, bindings) == false) return null;
// create the generic method if necessary
if (x.ContainsGenericParameters == false) return x;
var targs = t.GetGenericArguments().Select(y => bindings[y.Name]).ToArray();
return x.MakeGenericMethod(targs);
}).Where(x => x != null);
return filtr3.ToArray();
});
}
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
{
if (!methods.Any())
{
return null;
}
MethodInfo methodToExecute = null;
if (methods.Count() > 1)
{
//Given the args, lets get the types and compare the type sequence to try and find the correct overload
var argTypes = args.ToList().ConvertAll(o =>
{
var oe = (o as Expression);
if (oe != null)
{
return oe.Type.FullName;
}
return o.GetType().FullName;
});
var methodsWithArgTypes = methods.Select(method => new { method, types = method.GetParameters().Select(pi => pi.ParameterType.FullName) });
var firstMatchingOverload = methodsWithArgTypes.FirstOrDefault(m => m.types.SequenceEqual(argTypes));
if (firstMatchingOverload != null)
{
methodToExecute = firstMatchingOverload.method;
}
}
if (methodToExecute == null)
{
var firstMethod = methods.FirstOrDefault();
// NH: this is to ensure that it's always the correct one being chosen when using the LINQ extension methods
if (methods.Count() > 1)
{
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
if (firstGenericMethod != null)
{
firstMethod = firstGenericMethod;
}
}
//Given the args, lets get the types and compare the type sequence to try and find the correct overload
var argTypes = args.Select(o =>
{
var oe = (o as Expression);
return oe != null ? oe.Type : o.GetType();
});
var methodsWithArgTypes = methods.Select(method => new
{
method,
//skip the first arg because that is the extension method type ('this') that we are looking for
types = method.GetParameters().Select(pi => pi.ParameterType).Skip(1)
});
//This type comparer will check
var typeComparer = new DelegateEqualityComparer<Type>(
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
// example, if the argument type is HtmlHelper<MyModel> but the method parameter type is HtmlHelper then
// it will match because the argument is assignable to that parameter type and will be able to execute
TypeHelper.IsTypeAssignableFrom,
//This will not ever execute but if it does we need to get the hash code of the string because the hash
// code of a type is random
type => type.FullName.GetHashCode());
var firstMatchingOverload = methodsWithArgTypes
.FirstOrDefault(m => m.types.SequenceEqual(argTypes, typeComparer));
if (firstMatchingOverload != null)
{
methodToExecute = firstMatchingOverload.method;
}
if (firstMethod != null)
{
if (firstMethod.IsGenericMethodDefinition)
{
if (genericType != null)
{
methodToExecute = firstMethod.MakeGenericMethod(genericType);
}
}
else
{
methodToExecute = firstMethod;
}
}
}
return methodToExecute;
}
public static MethodInfo FindExtensionMethod(Type thisType, object[] args, string name, bool argsContainsThis)
public static MethodInfo FindExtensionMethod(IRuntimeCacheProvider runtimeCache, Type thisType, object[] args, string name, bool argsContainsThis)
{
Type genericType = null;
if (thisType.IsGenericType)
{
genericType = thisType.GetGenericArguments()[0];
}
}
var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis).ToArray();
return DetermineMethodFromParams(methods, genericType, args);
args = args
//if the args contains 'this', remove the first one since that is 'this' and we don't want to use
//that in the method searching
.Skip(argsContainsThis ? 1 : 0)
.ToArray();
var methods = GetAllExtensionMethods(runtimeCache, thisType, name, args.Length).ToArray();
return DetermineMethodFromParams(methods, genericType, args);
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Umbraco.Core
/// <remarks>
/// Taken from http://damieng.com/blog/2010/10/17/enums-better-syntax-improved-performance-and-tryparse-in-net-3-5
/// </remarks>
internal static class Enum<T> where T : struct
public static class Enum<T> where T : struct
{
private static readonly IEnumerable<T> All = Enum.GetValues(typeof(T)).Cast<T>();
private static readonly Dictionary<string, T> InsensitiveNames = All.ToDictionary(k => Enum.GetName(typeof(T), k).ToLowerInvariant());
+33 -10
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
@@ -114,13 +115,7 @@ namespace Umbraco.Core
/// <returns></returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> other)
{
var matches = true;
foreach (var i in other)
{
matches = source.Contains(i);
if (!matches) break;
}
return matches;
return other.Except(source).Any() == false;
}
/// <summary>
@@ -132,7 +127,7 @@ namespace Umbraco.Core
/// <returns></returns>
public static bool ContainsAny<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> other)
{
return other.Any(i => source.Contains(i));
return other.Any(source.Contains);
}
/// <summary>
@@ -224,7 +219,7 @@ namespace Umbraco.Core
return sequence.Select(
x =>
{
if (typeof(TActual).IsAssignableFrom(x.GetType()))
if (x is TActual)
{
var casted = x as TActual;
projection.Invoke(casted);
@@ -276,6 +271,34 @@ namespace Umbraco.Core
///<param name="items">The enumerable to search.</param>
///<param name="item">The item to find.</param>
///<returns>The index of the first matching item, or -1 if the item was not found.</returns>
public static int IndexOf<T>(this IEnumerable<T> items, T item) { return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i)); }
public static int IndexOf<T>(this IEnumerable<T> items, T item)
{
return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i));
}
/// <summary>
/// Determines if 2 lists have equal elements within them regardless of how they are sorted
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="other"></param>
/// <returns></returns>
/// <remarks>
/// The logic for this is taken from:
/// http://stackoverflow.com/questions/4576723/test-whether-two-ienumerablet-have-the-same-values-with-the-same-frequencies
///
/// There's a few answers, this one seems the best for it's simplicity and based on the comment of Eamon
/// </remarks>
public static bool UnsortedSequenceEqual<T>(this IEnumerable<T> source, IEnumerable<T> other)
{
if (source == null && other == null) return true;
if (source == null || other == null) return false;
var list1Groups = source.ToLookup(i => i);
var list2Groups = other.ToLookup(i => i);
return list1Groups.Count == list2Groups.Count
&& list1Groups.All(g => g.Count() == list2Groups[g.Key].Count());
}
}
}
+47 -14
View File
@@ -1,18 +1,51 @@
using System;
using System.IO;
using System.Threading;
namespace Umbraco.Core.IO
{
{
public static class FileSystemExtensions
{
public static long GetSize(this IFileSystem fs, string path)
{
using (var s = fs.OpenFile(path))
{
var size = s.Length;
s.Close();
return size;
/// <summary>
/// Attempts to open the file at <code>filePath</code> up to <code>maxRetries</code> times,
/// with a thread sleep time of <code>sleepPerRetryInMilliseconds</code> between retries.
/// </summary>
public static FileStream OpenReadWithRetry(this FileInfo file, int maxRetries = 5, int sleepPerRetryInMilliseconds = 50)
{
var retries = maxRetries;
while (retries > 0)
{
try
{
return File.OpenRead(file.FullName);
}
catch(IOException)
{
retries--;
if (retries == 0)
{
throw;
}
Thread.Sleep(sleepPerRetryInMilliseconds);
}
}
throw new ArgumentException("Retries must be greater than zero");
}
public static long GetSize(this IFileSystem fs, string path)
{
using (var file = fs.OpenFile(path))
{
using (var sr = new StreamReader(file))
{
var str = sr.ReadToEnd();
return str.Length;
}
}
}
@@ -25,14 +58,14 @@ namespace Umbraco.Core.IO
}
public static string GetExtension(this IFileSystem fs, string path)
{
return Path.GetExtension(fs.GetFullPath(path));
}
{
return Path.GetExtension(fs.GetFullPath(path));
}
public static string GetFileName(this IFileSystem fs, string path)
{
return Path.GetFileName(fs.GetFullPath(path));
}
{
return Path.GetFileName(fs.GetFullPath(path));
}
//TODO: Currently this is the only way to do this
internal static void CreateFolder(this IFileSystem fs, string folderPath)
+1 -5
View File
@@ -154,12 +154,8 @@ namespace Umbraco.Core.IO
EnsureFileSupportsResizing();
using (var fs = _fs.OpenFile(Path))
using (var image = Image.FromStream(fs))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
_size = new Size(fileWidth, fileHeight);
_size = ImageHelper.GetDimensions(fs);
}
}
else
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Macros
internal class MacroTagParser
{
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""']([\w\.]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
/// <summary>
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
@@ -0,0 +1,35 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.IO;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Serialization;
namespace Umbraco.Core.Manifest
{
/// <summary>
/// Ensures that virtual paths are taken care of
/// </summary>
internal class GridEditorConverter : JsonCreationConverter<GridEditor>
{
protected override GridEditor Create(Type objectType, JObject jObject)
{
return new GridEditor();
}
protected override void Deserialize(JObject jObject, GridEditor target, JsonSerializer serializer)
{
base.Deserialize(jObject, target, serializer);
if (target.View.IsNullOrWhiteSpace() == false && target.View.StartsWith("~/"))
{
target.View = IOHelper.ResolveUrl(target.View);
}
if (target.Render.IsNullOrWhiteSpace() == false && target.Render.StartsWith("~/"))
{
target.Render = IOHelper.ResolveUrl(target.Render);
}
}
}
}
+59 -38
View File
@@ -1,6 +1,8 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using Umbraco.Core.Cache;
using Umbraco.Core.IO;
using Umbraco.Core.PropertyEditors;
@@ -11,73 +13,92 @@ namespace Umbraco.Core.Manifest
/// </summary>
internal class ManifestBuilder
{
private readonly IRuntimeCacheProvider _cache;
private readonly ManifestParser _parser;
private static readonly ConcurrentDictionary<string, object> StaticCache = new ConcurrentDictionary<string, object>();
private const string ManifestKey = "manifests";
public ManifestBuilder(IRuntimeCacheProvider cache, ManifestParser parser)
{
_cache = cache;
_parser = parser;
}
private const string GridEditorsKey = "grideditors";
private const string PropertyEditorsKey = "propertyeditors";
private const string ParameterEditorsKey = "parametereditors";
/// <summary>
/// Returns all property editors found in the manfifests
/// Returns all grid editors found in the manfifests
/// </summary>
internal static IEnumerable<PropertyEditor> PropertyEditors
internal IEnumerable<GridEditor> GridEditors
{
get
{
return (IEnumerable<PropertyEditor>) StaticCache.GetOrAdd(
PropertyEditorsKey,
s =>
return _cache.GetCacheItem<IEnumerable<GridEditor>>(
typeof (ManifestBuilder) + GridEditorsKey,
() =>
{
var editors = new List<GridEditor>();
foreach (var manifest in _parser.GetManifests())
{
var editors = new List<PropertyEditor>();
foreach (var manifest in GetManifests())
if (manifest.GridEditors != null)
{
if (manifest.PropertyEditors != null)
{
editors.AddRange(ManifestParser.GetPropertyEditors(manifest.PropertyEditors));
}
editors.AddRange(ManifestParser.GetGridEditors(manifest.GridEditors));
}
return editors;
});
}
return editors;
}, new TimeSpan(0, 10, 0));
}
}
/// <summary>
/// Returns all property editors found in the manfifests
/// </summary>
internal IEnumerable<PropertyEditor> PropertyEditors
{
get
{
return _cache.GetCacheItem<IEnumerable<PropertyEditor>>(
typeof(ManifestBuilder) + PropertyEditorsKey,
() =>
{
var editors = new List<PropertyEditor>();
foreach (var manifest in _parser.GetManifests())
{
if (manifest.PropertyEditors != null)
{
editors.AddRange(ManifestParser.GetPropertyEditors(manifest.PropertyEditors));
}
}
return editors;
}, new TimeSpan(0, 10, 0));
}
}
/// <summary>
/// Returns all parameter editors found in the manfifests and all property editors that are flagged to be parameter editors
/// </summary>
internal static IEnumerable<ParameterEditor> ParameterEditors
internal IEnumerable<ParameterEditor> ParameterEditors
{
get
{
return (IEnumerable<ParameterEditor>)StaticCache.GetOrAdd(
ParameterEditorsKey,
s =>
return _cache.GetCacheItem<IEnumerable<ParameterEditor>>(
typeof (ManifestBuilder) + ParameterEditorsKey,
() =>
{
var editors = new List<ParameterEditor>();
foreach (var manifest in GetManifests())
foreach (var manifest in _parser.GetManifests())
{
if (manifest.ParameterEditors != null)
{
editors.AddRange(ManifestParser.GetParameterEditors(manifest.ParameterEditors));
editors.AddRange(ManifestParser.GetParameterEditors(manifest.ParameterEditors));
}
}
return editors;
});
}, new TimeSpan(0, 10, 0));
}
}
/// <summary>
/// Ensures the manifests are found and loaded into memory
/// </summary>
private static IEnumerable<PackageManifest> GetManifests()
{
return (IEnumerable<PackageManifest>) StaticCache.GetOrAdd(ManifestKey, s =>
{
var parser = new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")));
return parser.GetManifests();
});
}
}
}
+61 -9
View File
@@ -5,6 +5,7 @@ using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
@@ -17,15 +18,29 @@ namespace Umbraco.Core.Manifest
internal class ManifestParser
{
private readonly DirectoryInfo _pluginsDir;
private readonly IRuntimeCacheProvider _cache;
//used to strip comments
private static readonly Regex CommentsSurround = new Regex(@"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/", RegexOptions.Compiled);
private static readonly Regex CommentsLine = new Regex(@"//.*?$", RegexOptions.Compiled | RegexOptions.Multiline);
private static readonly Regex CommentsLine = new Regex(@"^\s*//.*?$", RegexOptions.Compiled | RegexOptions.Multiline);
public ManifestParser(DirectoryInfo pluginsDir)
public ManifestParser(DirectoryInfo pluginsDir, IRuntimeCacheProvider cache)
{
if (pluginsDir == null) throw new ArgumentNullException("pluginsDir");
_pluginsDir = pluginsDir;
_cache = cache;
}
/// <summary>
/// Parse the grid editors from the json array
/// </summary>
/// <param name="jsonEditors"></param>
/// <returns></returns>
internal static IEnumerable<GridEditor> GetGridEditors(JArray jsonEditors)
{
return JsonConvert.DeserializeObject<IEnumerable<GridEditor>>(
jsonEditors.ToString(),
new GridEditorConverter());
}
/// <summary>
@@ -57,11 +72,17 @@ namespace Umbraco.Core.Manifest
/// Get all registered manifests
/// </summary>
/// <returns></returns>
/// <remarks>
/// This ensures that we only build and look for all manifests once per Web app (based on the IRuntimeCache)
/// </remarks>
public IEnumerable<PackageManifest> GetManifests()
{
//get all Manifest.js files in the appropriate folders
var manifestFileContents = GetAllManfifestFileContents(_pluginsDir);
return CreateManifests(manifestFileContents.ToArray());
return _cache.GetCacheItem<IEnumerable<PackageManifest>>(typeof (ManifestParser) + "GetManifests", () =>
{
//get all Manifest.js files in the appropriate folders
var manifestFileContents = GetAllManifestFileContents(_pluginsDir);
return CreateManifests(manifestFileContents.ToArray());
}, new TimeSpan(0, 10, 0));
}
/// <summary>
@@ -69,7 +90,7 @@ namespace Umbraco.Core.Manifest
/// </summary>
/// <param name="currDir"></param>
/// <returns></returns>
private IEnumerable<string> GetAllManfifestFileContents(DirectoryInfo currDir)
private IEnumerable<string> GetAllManifestFileContents(DirectoryInfo currDir)
{
var depth = FolderDepth(_pluginsDir, currDir);
@@ -79,7 +100,7 @@ namespace Umbraco.Core.Manifest
var result = new List<string>();
foreach (var d in dirs)
{
result.AddRange(GetAllManfifestFileContents(d));
result.AddRange(GetAllManifestFileContents(d));
}
return result;
}
@@ -154,6 +175,20 @@ namespace Umbraco.Core.Manifest
throw new FormatException("The manifest is not formatted correctly contains more than one 'propertyEditors' element");
}
//validate the parameterEditors section
var paramEditors = deserialized.Properties().Where(x => x.Name == "parameterEditors").ToArray();
if (paramEditors.Length > 1)
{
throw new FormatException("The manifest is not formatted correctly contains more than one 'parameterEditors' element");
}
//validate the gridEditors section
var gridEditors = deserialized.Properties().Where(x => x.Name == "gridEditors").ToArray();
if (gridEditors.Length > 1)
{
throw new FormatException("The manifest is not formatted correctly contains more than one 'gridEditors' element");
}
var jConfig = init.Any() ? (JArray)deserialized["javascript"] : new JArray();
ReplaceVirtualPaths(jConfig);
@@ -175,13 +210,30 @@ namespace Umbraco.Core.Manifest
}
}
}
//replace virtual paths for each property editor
if (deserialized["gridEditors"] != null)
{
foreach (JObject p in deserialized["gridEditors"])
{
if (p["view"] != null)
{
ReplaceVirtualPaths(p["view"]);
}
if (p["render"] != null)
{
ReplaceVirtualPaths(p["render"]);
}
}
}
var manifest = new PackageManifest()
{
JavaScriptInitialize = jConfig,
StylesheetInitialize = cssConfig,
PropertyEditors = propEditors.Any() ? (JArray)deserialized["propertyEditors"] : new JArray(),
ParameterEditors = propEditors.Any() ? (JArray)deserialized["parameterEditors"] : new JArray()
ParameterEditors = paramEditors.Any() ? (JArray)deserialized["parameterEditors"] : new JArray(),
GridEditors = gridEditors.Any() ? (JArray)deserialized["gridEditors"] : new JArray()
};
result.Add(manifest);
}
@@ -26,5 +26,10 @@ namespace Umbraco.Core.Manifest
/// The json array of parameter editors
/// </summary>
public JArray ParameterEditors { get; set; }
/// <summary>
/// The json array of grid editors
/// </summary>
public JArray GridEditors { get; set; }
}
}
@@ -0,0 +1,405 @@
using System;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// An endian-aware converter for converting between base data types
/// and an array of bytes.
/// </summary>
internal class BitConverterEx
{
#region Public Enums
/// <summary>
/// Represents the byte order.
/// </summary>
public enum ByteOrder
{
LittleEndian = 1,
BigEndian = 2,
}
#endregion
#region Member Variables
private ByteOrder mFrom, mTo;
#endregion
#region Constructors
public BitConverterEx(ByteOrder from, ByteOrder to)
{
mFrom = from;
mTo = to;
}
#endregion
#region Properties
/// <summary>
/// Indicates the byte order in which data is stored in this platform.
/// </summary>
public static ByteOrder SystemByteOrder
{
get
{
return (BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian);
}
}
#endregion
#region Predefined Values
/// <summary>
/// Returns a bit converter that converts between little-endian and system byte-order.
/// </summary>
public static BitConverterEx LittleEndian
{
get
{
return new BitConverterEx(ByteOrder.LittleEndian, BitConverterEx.SystemByteOrder);
}
}
/// <summary>
/// Returns a bit converter that converts between big-endian and system byte-order.
/// </summary>
public static BitConverterEx BigEndian
{
get
{
return new BitConverterEx(ByteOrder.BigEndian, BitConverterEx.SystemByteOrder);
}
}
/// <summary>
/// Returns a bit converter that does not do any byte-order conversion.
/// </summary>
public static BitConverterEx SystemEndian
{
get
{
return new BitConverterEx(BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder);
}
}
#endregion
#region Static Methods
/// <summary>
/// Converts the given array of bytes to a Unicode character.
/// </summary>
public static char ToChar(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToChar(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public static ushort ToUInt16(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToUInt16(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit unsigned integer.
/// </summary>
public static uint ToUInt32(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToUInt32(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit unsigned integer.
/// </summary>
public static ulong ToUInt64(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToUInt64(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit signed integer.
/// </summary>
public static short ToInt16(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 2, from, to);
return BitConverter.ToInt16(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit signed integer.
/// </summary>
public static int ToInt32(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToInt32(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit signed integer.
/// </summary>
public static long ToInt64(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToInt64(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a single precision floating number.
/// </summary>
public static float ToSingle(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 4, from, to);
return BitConverter.ToSingle(data, 0);
}
/// <summary>
/// Converts the given array of bytes to a double precision floating number.
/// </summary>
public static double ToDouble(byte[] value, long startIndex, ByteOrder from, ByteOrder to)
{
byte[] data = CheckData(value, startIndex, 8, from, to);
return BitConverter.ToDouble(data, 0);
}
/// <summary>
/// Converts the given 16-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(ushort value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 32-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(uint value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 64-bit unsigned integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(ulong value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 16-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(short value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 32-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(int value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given 64-bit signed integer to an array of bytes.
/// </summary>
public static byte[] GetBytes(long value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given single precision floating-point number to an array of bytes.
/// </summary>
public static byte[] GetBytes(float value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
/// <summary>
/// Converts the given double precision floating-point number to an array of bytes.
/// </summary>
public static byte[] GetBytes(double value, ByteOrder from, ByteOrder to)
{
byte[] data = BitConverter.GetBytes(value);
data = CheckData(data, from, to);
return data;
}
#endregion
#region Instance Methods
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public char ToChar(byte[] value, long startIndex)
{
return BitConverterEx.ToChar(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit unsigned integer.
/// </summary>
public ushort ToUInt16(byte[] value, long startIndex)
{
return BitConverterEx.ToUInt16(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit unsigned integer.
/// </summary>
public uint ToUInt32(byte[] value, long startIndex)
{
return BitConverterEx.ToUInt32(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit unsigned integer.
/// </summary>
public ulong ToUInt64(byte[] value, long startIndex)
{
return BitConverterEx.ToUInt64(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 16-bit signed integer.
/// </summary>
public short ToInt16(byte[] value, long startIndex)
{
return BitConverterEx.ToInt16(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 32-bit signed integer.
/// </summary>
public int ToInt32(byte[] value, long startIndex)
{
return BitConverterEx.ToInt32(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a 64-bit signed integer.
/// </summary>
public long ToInt64(byte[] value, long startIndex)
{
return BitConverterEx.ToInt64(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a single precision floating number.
/// </summary>
public float ToSingle(byte[] value, long startIndex)
{
return BitConverterEx.ToSingle(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given array of bytes to a double precision floating number.
/// </summary>
public double ToDouble(byte[] value, long startIndex)
{
return BitConverterEx.ToDouble(value, startIndex, mFrom, mTo);
}
/// <summary>
/// Converts the given 16-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(ushort value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 32-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(uint value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 64-bit unsigned integer to an array of bytes.
/// </summary>
public byte[] GetBytes(ulong value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 16-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(short value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 32-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(int value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given 64-bit signed integer to an array of bytes.
/// </summary>
public byte[] GetBytes(long value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given single precision floating-point number to an array of bytes.
/// </summary>
public byte[] GetBytes(float value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
/// <summary>
/// Converts the given double precision floating-point number to an array of bytes.
/// </summary>
public byte[] GetBytes(double value)
{
return BitConverterEx.GetBytes(value, mFrom, mTo);
}
#endregion
#region Private Helpers
/// <summary>
/// Reverse the array of bytes as needed.
/// </summary>
private static byte[] CheckData(byte[] value, long startIndex, long length, ByteOrder from, ByteOrder to)
{
byte[] data = new byte[length];
Array.Copy(value, startIndex, data, 0, length);
if (from != to)
Array.Reverse(data);
return data;
}
/// <summary>
/// Reverse the array of bytes as needed.
/// </summary>
private static byte[] CheckData(byte[] value, ByteOrder from, ByteOrder to)
{
return CheckData(value, 0, value.Length, from, to);
}
#endregion
}
}
@@ -0,0 +1,357 @@
using System;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Converts between exif data types and array of bytes.
/// </summary>
internal class ExifBitConverter : BitConverterEx
{
#region Constructors
public ExifBitConverter(ByteOrder from, ByteOrder to)
: base(from, to)
{
;
}
#endregion
#region Static Methods
/// <summary>
/// Returns an ASCII string converted from the given byte array.
/// </summary>
public static string ToAscii(byte[] data, bool endatfirstnull, Encoding encoding)
{
int len = data.Length;
if (endatfirstnull)
{
len = Array.IndexOf(data, (byte)0);
if (len == -1) len = data.Length;
}
return encoding.GetString(data, 0, len);
}
/// <summary>
/// Returns an ASCII string converted from the given byte array.
/// </summary>
public static string ToAscii(byte[] data, Encoding encoding)
{
return ToAscii(data, true, encoding);
}
/// <summary>
/// Returns a string converted from the given byte array.
/// from the numeric value of each byte.
/// </summary>
public static string ToString(byte[] data)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in data)
sb.Append(b);
return sb.ToString();
}
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data, bool hastime)
{
string str = ToAscii(data, Encoding.ASCII);
string[] parts = str.Split(new char[] { ':', ' ' });
try
{
if (hastime && parts.Length == 6)
{
// yyyy:MM:dd HH:mm:ss
// This is the expected format though some cameras
// can use single digits. See Issue 21.
return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), int.Parse(parts[5]));
}
else if (!hastime && parts.Length == 3)
{
// yyyy:MM:dd
return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
}
else
{
return DateTime.MinValue;
}
}
catch (ArgumentOutOfRangeException)
{
return DateTime.MinValue;
}
catch (ArgumentException)
{
return DateTime.MinValue;
}
}
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data)
{
return ToDateTime(data, true);
}
/// <summary>
/// Returns an unsigned rational number converted from the first
/// eight bytes of the given byte array. The first four bytes are
/// assumed to be the numerator and the next four bytes are the
/// denumerator.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.UFraction32 ToURational(byte[] data, ByteOrder frombyteorder)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, 0, num, 0, 4);
Array.Copy(data, 4, den, 0, 4);
return new MathEx.UFraction32(ToUInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToUInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
/// <summary>
/// Returns a signed rational number converted from the first
/// eight bytes of the given byte array. The first four bytes are
/// assumed to be the numerator and the next four bytes are the
/// denumerator.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.Fraction32 ToSRational(byte[] data, ByteOrder frombyteorder)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, 0, num, 0, 4);
Array.Copy(data, 4, den, 0, 4);
return new MathEx.Fraction32(ToInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
/// <summary>
/// Returns an array of 16-bit unsigned integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static ushort[] ToUShortArray(byte[] data, int count, ByteOrder frombyteorder)
{
ushort[] numbers = new ushort[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[2];
Array.Copy(data, i * 2, num, 0, 2);
numbers[i] = ToUInt16(num, 0, frombyteorder, BitConverterEx.SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of 32-bit unsigned integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static uint[] ToUIntArray(byte[] data, int count, ByteOrder frombyteorder)
{
uint[] numbers = new uint[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
Array.Copy(data, i * 4, num, 0, 4);
numbers[i] = ToUInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of 32-bit signed integers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static int[] ToSIntArray(byte[] data, int count, ByteOrder byteorder)
{
int[] numbers = new int[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
Array.Copy(data, i * 4, num, 0, 4);
numbers[i] = ToInt32(num, 0, byteorder, BitConverterEx.SystemByteOrder);
}
return numbers;
}
/// <summary>
/// Returns an array of unsigned rational numbers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.UFraction32[] ToURationalArray(byte[] data, int count, ByteOrder frombyteorder)
{
MathEx.UFraction32[] numbers = new MathEx.UFraction32[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, i * 8, num, 0, 4);
Array.Copy(data, i * 8 + 4, den, 0, 4);
numbers[i].Set(ToUInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToUInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
return numbers;
}
/// <summary>
/// Returns an array of signed rational numbers converted from
/// the given byte array.
/// Numbers are converted from the given byte-order to platform byte-order.
/// </summary>
public static MathEx.Fraction32[] ToSRationalArray(byte[] data, int count, ByteOrder frombyteorder)
{
MathEx.Fraction32[] numbers = new MathEx.Fraction32[count];
for (uint i = 0; i < count; i++)
{
byte[] num = new byte[4];
byte[] den = new byte[4];
Array.Copy(data, i * 8, num, 0, 4);
Array.Copy(data, i * 8 + 4, den, 0, 4);
numbers[i].Set(ToInt32(num, 0, frombyteorder, BitConverterEx.SystemByteOrder), ToInt32(den, 0, frombyteorder, BitConverterEx.SystemByteOrder));
}
return numbers;
}
/// <summary>
/// Converts the given ascii string to an array of bytes optionally adding a null terminator.
/// </summary>
public static byte[] GetBytes(string value, bool addnull, Encoding encoding)
{
if (addnull) value += '\0';
return encoding.GetBytes(value);
}
/// <summary>
/// Converts the given ascii string to an array of bytes without adding a null terminator.
/// </summary>
public static byte[] GetBytes(string value, Encoding encoding)
{
return GetBytes(value, false, encoding);
}
/// <summary>
/// Converts the given datetime to an array of bytes with a null terminator.
/// </summary>
public static byte[] GetBytes(DateTime value, bool hastime)
{
string str = "";
if (hastime)
str = value.ToString("yyyy:MM:dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
else
str = value.ToString("yyyy:MM:dd", System.Globalization.CultureInfo.InvariantCulture);
return GetBytes(str, true, Encoding.ASCII);
}
/// <summary>
/// Converts the given unsigned rational number to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.UFraction32 value, ByteOrder tobyteorder)
{
byte[] num = GetBytes(value.Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value.Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] data = new byte[8];
Array.Copy(num, 0, data, 0, 4);
Array.Copy(den, 0, data, 4, 4);
return data;
}
/// <summary>
/// Converts the given signed rational number to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.Fraction32 value, ByteOrder tobyteorder)
{
byte[] num = GetBytes(value.Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value.Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] data = new byte[8];
Array.Copy(num, 0, data, 0, 4);
Array.Copy(den, 0, data, 4, 4);
return data;
}
/// <summary>
/// Converts the given array of 16-bit unsigned integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(ushort[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[2 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 2, 2);
}
return data;
}
/// <summary>
/// Converts the given array of 32-bit unsigned integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(uint[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[4 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of 32-bit signed integers to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(int[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[4 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of unsigned rationals to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.UFraction32[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[8 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i].Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value[i].Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 8, 4);
Array.Copy(den, 0, data, i * 8 + 4, 4);
}
return data;
}
/// <summary>
/// Converts the given array of signed rationals to an array of bytes.
/// Numbers are converted from the platform byte-order to the given byte-order.
/// </summary>
public static byte[] GetBytes(MathEx.Fraction32[] value, ByteOrder tobyteorder)
{
byte[] data = new byte[8 * value.Length];
for (int i = 0; i < value.Length; i++)
{
byte[] num = GetBytes(value[i].Numerator, BitConverterEx.SystemByteOrder, tobyteorder);
byte[] den = GetBytes(value[i].Denominator, BitConverterEx.SystemByteOrder, tobyteorder);
Array.Copy(num, 0, data, i * 8, 4);
Array.Copy(den, 0, data, i * 8 + 4, 4);
}
return data;
}
#endregion
}
}
+292
View File
@@ -0,0 +1,292 @@
using System;
namespace Umbraco.Core.Media.Exif
{
internal enum Compression : ushort
{
Uncompressed = 1,
CCITT1D = 2,
Group3Fax = 3,
Group4Fax = 4,
LZW = 5,
JPEG = 6,
PackBits = 32773,
}
internal enum PhotometricInterpretation : ushort
{
WhiteIsZero = 0,
BlackIsZero = 1,
RGB = 2,
RGBPalette = 3,
TransparencyMask = 4,
CMYK = 5,
YCbCr = 6,
CIELab = 8,
}
internal enum Orientation : ushort
{
Normal = 1,
MirroredVertically = 2,
Rotated180 = 3,
MirroredHorizontally = 4,
RotatedLeftAndMirroredVertically = 5,
RotatedRight = 6,
RotatedLeft = 7,
RotatedRightAndMirroredVertically = 8,
}
internal enum PlanarConfiguration : ushort
{
ChunkyFormat = 1,
PlanarFormat = 2,
}
internal enum YCbCrPositioning : ushort
{
Centered = 1,
CoSited = 2,
}
internal enum ResolutionUnit : ushort
{
Inches = 2,
Centimeters = 3,
}
internal enum ColorSpace : ushort
{
sRGB = 1,
Uncalibrated = 0xfff,
}
internal enum ExposureProgram : ushort
{
NotDefined = 0,
Manual = 1,
Normal = 2,
AperturePriority = 3,
ShutterPriority = 4,
/// <summary>
/// Biased toward depth of field.
/// </summary>
Creative = 5,
/// <summary>
/// Biased toward fast shutter speed.
/// </summary>
Action = 6,
/// <summary>
/// For closeup photos with the background out of focus.
/// </summary>
Portrait = 7,
/// <summary>
/// For landscape photos with the background in focus.
/// </summary>
Landscape = 8,
}
internal enum MeteringMode : ushort
{
Unknown = 0,
Average = 1,
CenterWeightedAverage = 2,
Spot = 3,
MultiSpot = 4,
Pattern = 5,
Partial = 6,
Other = 255,
}
internal enum LightSource : ushort
{
Unknown = 0,
Daylight = 1,
Fluorescent = 2,
Tungsten = 3,
Flash = 4,
FineWeather = 9,
CloudyWeather = 10,
Shade = 11,
/// <summary>
/// D 5700 7100K
/// </summary>
DaylightFluorescent = 12,
/// <summary>
/// N 4600 5400K
/// </summary>
DayWhiteFluorescent = 13,
/// <summary>
/// W 3900 4500K
/// </summary>
CoolWhiteFluorescent = 14,
/// <summary>
/// WW 3200 3700K
/// </summary>
WhiteFluorescent = 15,
StandardLightA = 17,
StandardLightB = 18,
StandardLightC = 19,
D55 = 20,
D65 = 21,
D75 = 22,
D50 = 23,
ISOStudioTungsten = 24,
OtherLightSource = 255,
}
[Flags]
internal enum Flash : ushort
{
FlashDidNotFire = 0,
StrobeReturnLightNotDetected = 4,
StrobeReturnLightDetected = 2,
FlashFired = 1,
CompulsoryFlashMode = 8,
AutoMode = 16,
NoFlashFunction = 32,
RedEyeReductionMode = 64,
}
internal enum SensingMethod : ushort
{
NotDefined = 1,
OneChipColorAreaSensor = 2,
TwoChipColorAreaSensor = 3,
ThreeChipColorAreaSensor = 4,
ColorSequentialAreaSensor = 5,
TriLinearSensor = 7,
ColorSequentialLinearSensor = 8,
}
internal enum FileSource : byte // UNDEFINED
{
DSC = 3,
}
internal enum SceneType : byte // UNDEFINED
{
DirectlyPhotographedImage = 1,
}
internal enum CustomRendered : ushort
{
NormalProcess = 0,
CustomProcess = 1,
}
internal enum ExposureMode : ushort
{
Auto = 0,
Manual = 1,
AutoBracket = 2,
}
internal enum WhiteBalance : ushort
{
Auto = 0,
Manual = 1,
}
internal enum SceneCaptureType : ushort
{
Standard = 0,
Landscape = 1,
Portrait = 2,
NightScene = 3,
}
internal enum GainControl : ushort
{
None = 0,
LowGainUp = 1,
HighGainUp = 2,
LowGainDown = 3,
HighGainDown = 4,
}
internal enum Contrast : ushort
{
Normal = 0,
Soft = 1,
Hard = 2,
}
internal enum Saturation : ushort
{
Normal = 0,
Low = 1,
High = 2,
}
internal enum Sharpness : ushort
{
Normal = 0,
Soft = 1,
Hard = 2,
}
internal enum SubjectDistanceRange : ushort
{
Unknown = 0,
Macro = 1,
CloseView = 2,
DistantView = 3,
}
internal enum GPSLatitudeRef : byte // ASCII
{
North = 78, // 'N'
South = 83, // 'S'
}
internal enum GPSLongitudeRef : byte // ASCII
{
West = 87, // 'W'
East = 69, // 'E'
}
internal enum GPSAltitudeRef : byte
{
AboveSeaLevel = 0,
BelowSeaLevel = 1,
}
internal enum GPSStatus : byte // ASCII
{
MeasurementInProgress = 65, // 'A'
MeasurementInteroperability = 86, // 'V'
}
internal enum GPSMeasureMode : byte // ASCII
{
TwoDimensional = 50, // '2'
ThreeDimensional = 51, // '3'
}
internal enum GPSSpeedRef : byte // ASCII
{
KilometersPerHour = 75, // 'K'
MilesPerHour = 77, // 'M'
Knots = 78, // 'N'
}
internal enum GPSDirectionRef : byte // ASCII
{
TrueDirection = 84, // 'T'
MagneticDirection = 77, // 'M'
}
internal enum GPSDistanceRef : byte // ASCII
{
Kilometers = 75, // 'K'
Miles = 77, // 'M'
Knots = 78, // 'N'
}
internal enum GPSDifferential : ushort
{
MeasurementWithoutDifferentialCorrection = 0,
DifferentialCorrectionApplied = 1,
}
}
@@ -0,0 +1,78 @@
using System;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// The exception that is thrown when the format of the JPEG/Exif file
/// could not be understood.
/// </summary>
internal class NotValidExifFileException : Exception
{
public NotValidExifFileException()
: base("Not a valid JPEG/Exif file.")
{
;
}
public NotValidExifFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the IFD section ID could not be understood.
/// </summary>
internal class UnknownIFDSectionException : Exception
{
public UnknownIFDSectionException()
: base("Unknown IFD section.")
{
;
}
public UnknownIFDSectionException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when an invalid enum type is given to an
/// ExifEnumProperty.
/// </summary>
internal class UnknownEnumTypeException : Exception
{
public UnknownEnumTypeException()
: base("Unknown enum type.")
{
;
}
public UnknownEnumTypeException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the 0th IFD section does not contain any fields.
/// </summary>
internal class IFD0IsEmptyException : Exception
{
public IFD0IsEmptyException()
: base("0th IFD section cannot be empty.")
{
;
}
public IFD0IsEmptyException(string message)
: base(message)
{
;
}
}
}
@@ -0,0 +1,373 @@
using System;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents an enumerated value.
/// </summary>
internal class ExifEnumProperty<T> : ExifProperty
{
protected T mValue;
protected bool mIsBitField;
protected override object _Value { get { return Value; } set { Value = (T)value; } }
public new T Value { get { return mValue; } set { mValue = value; } }
public bool IsBitField { get { return mIsBitField; } }
static public implicit operator T(ExifEnumProperty<T> obj) { return (T)obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifEnumProperty(ExifTag tag, T value, bool isbitfield)
: base(tag)
{
mValue = value;
mIsBitField = isbitfield;
}
public ExifEnumProperty(ExifTag tag, T value)
: this(tag, value, false)
{
;
}
public override ExifInterOperability Interoperability
{
get
{
ushort tagid = ExifTagFactory.GetTagID(mTag);
Type type = typeof(T);
Type basetype = Enum.GetUnderlyingType(type);
if (type == typeof(FileSource) || type == typeof(SceneType))
{
// UNDEFINED
return new ExifInterOperability(tagid, 7, 1, new byte[] { (byte)((object)mValue) });
}
else if (type == typeof(GPSLatitudeRef) || type == typeof(GPSLongitudeRef) ||
type == typeof(GPSStatus) || type == typeof(GPSMeasureMode) ||
type == typeof(GPSSpeedRef) || type == typeof(GPSDirectionRef) ||
type == typeof(GPSDistanceRef))
{
// ASCII
return new ExifInterOperability(tagid, 2, 2, new byte[] { (byte)((object)mValue), 0 });
}
else if (basetype == typeof(byte))
{
// BYTE
return new ExifInterOperability(tagid, 1, 1, new byte[] { (byte)((object)mValue) });
}
else if (basetype == typeof(ushort))
{
// SHORT
return new ExifInterOperability(tagid, 3, 1, ExifBitConverter.GetBytes((ushort)((object)mValue), BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
else
throw new UnknownEnumTypeException();
}
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: UNDEFINED) Used for the UserComment field.
/// </summary>
internal class ExifEncodedString : ExifProperty
{
protected string mValue;
private Encoding mEncoding;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value; } }
public Encoding Encoding { get { return mEncoding; } set { mEncoding = value; } }
static public implicit operator string(ExifEncodedString obj) { return obj.mValue; }
public override string ToString() { return mValue; }
public ExifEncodedString(ExifTag tag, string value, Encoding encoding)
: base(tag)
{
mValue = value;
mEncoding = encoding;
}
public override ExifInterOperability Interoperability
{
get
{
string enc = "";
if (mEncoding == null)
enc = "\0\0\0\0\0\0\0\0";
else if (mEncoding.EncodingName == "US-ASCII")
enc = "ASCII\0\0\0";
else if (mEncoding.EncodingName == "Japanese (JIS 0208-1990 and 0212-1990)")
enc = "JIS\0\0\0\0\0";
else if (mEncoding.EncodingName == "Unicode")
enc = "Unicode\0";
else
enc = "\0\0\0\0\0\0\0\0";
byte[] benc = Encoding.ASCII.GetBytes(enc);
byte[] bstr = (mEncoding == null ? Encoding.ASCII.GetBytes(mValue) : mEncoding.GetBytes(mValue));
byte[] data = new byte[benc.Length + bstr.Length];
Array.Copy(benc, 0, data, 0, benc.Length);
Array.Copy(bstr, 0, data, benc.Length, bstr.Length);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, (uint)data.Length, data);
}
}
}
/// <summary>
/// Represents an ASCII string formatted as DateTime. (EXIF Specification: ASCII) Used for the date time fields.
/// </summary>
internal class ExifDateTime : ExifProperty
{
protected DateTime mValue;
protected override object _Value { get { return Value; } set { Value = (DateTime)value; } }
public new DateTime Value { get { return mValue; } set { mValue = value; } }
static public implicit operator DateTime(ExifDateTime obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString("yyyy.MM.dd HH:mm:ss"); }
public ExifDateTime(ExifTag tag, DateTime value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 2, (uint)20, ExifBitConverter.GetBytes(mValue, true));
}
}
}
/// <summary>
/// Represents the exif version as a 4 byte ASCII string. (EXIF Specification: UNDEFINED)
/// Used for the ExifVersion, FlashpixVersion, InteroperabilityVersion and GPSVersionID fields.
/// </summary>
internal class ExifVersion : ExifProperty
{
protected string mValue;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value.Substring(0, 4); } }
public ExifVersion(ExifTag tag, string value)
: base(tag)
{
if (value.Length > 4)
mValue = value.Substring(0, 4);
else if (value.Length < 4)
mValue = value + new string(' ', 4 - value.Length);
else
mValue = value;
}
public override string ToString()
{
return mValue;
}
public override ExifInterOperability Interoperability
{
get
{
if (mTag == ExifTag.ExifVersion || mTag == ExifTag.FlashpixVersion || mTag == ExifTag.InteroperabilityVersion)
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, 4, Encoding.ASCII.GetBytes(mValue));
else
{
byte[] data = new byte[4];
for (int i = 0; i < 4; i++)
data[i] = byte.Parse(mValue[0].ToString());
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, 4, data);
}
}
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 2xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifPointSubjectArea : ExifUShortArray
{
protected new ushort[] Value { get { return mValue; } set { mValue = value; } }
public ushort X { get { return mValue[0]; } set { mValue[0] = value; } }
public ushort Y { get { return mValue[1]; } set { mValue[1] = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d})", mValue[0], mValue[1]);
return sb.ToString();
}
public ExifPointSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
;
}
public ExifPointSubjectArea(ExifTag tag, ushort x, ushort y)
: base(tag, new ushort[] { x, y })
{
;
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 3xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifCircularSubjectArea : ExifPointSubjectArea
{
public ushort Diamater { get { return mValue[2]; } set { mValue[2] = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d}) {2:d}", mValue[0], mValue[1], mValue[2]);
return sb.ToString();
}
public ExifCircularSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
;
}
public ExifCircularSubjectArea(ExifTag tag, ushort x, ushort y, ushort d)
: base(tag, new ushort[] { x, y, d })
{
;
}
}
/// <summary>
/// Represents the location and area of the subject (EXIF Specification: 4xSHORT)
/// The coordinate values, width, and height are expressed in relation to the
/// upper left as origin, prior to rotation processing as per the Rotation tag.
/// </summary>
internal class ExifRectangularSubjectArea : ExifPointSubjectArea
{
public ushort Width { get { return mValue[2]; } set { mValue[2] = value; } }
public ushort Height { get { return mValue[3]; } set { mValue[3] = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("({0:d}, {1:d}) ({2:d} x {3:d})", mValue[0], mValue[1], mValue[2], mValue[3]);
return sb.ToString();
}
public ExifRectangularSubjectArea(ExifTag tag, ushort[] value)
: base(tag, value)
{
;
}
public ExifRectangularSubjectArea(ExifTag tag, ushort x, ushort y, ushort w, ushort h)
: base(tag, new ushort[] { x, y, w, h })
{
;
}
}
/// <summary>
/// Represents GPS latitudes and longitudes (EXIF Specification: 3xRATIONAL)
/// </summary>
internal class GPSLatitudeLongitude : ExifURationalArray
{
protected new MathEx.UFraction32[] Value { get { return mValue; } set { mValue = value; } }
public MathEx.UFraction32 Degrees { get { return mValue[0]; } set { mValue[0] = value; } }
public MathEx.UFraction32 Minutes { get { return mValue[1]; } set { mValue[1] = value; } }
public MathEx.UFraction32 Seconds { get { return mValue[2]; } set { mValue[2] = value; } }
public static explicit operator float(GPSLatitudeLongitude obj) { return obj.ToFloat(); }
public float ToFloat()
{
return (float)Degrees + ((float)Minutes) / 60.0f + ((float)Seconds) / 3600.0f;
}
public override string ToString()
{
return string.Format("{0:F2}°{1:F2}'{2:F2}\"", (float)Degrees, (float)Minutes, (float)Seconds);
}
public GPSLatitudeLongitude(ExifTag tag, MathEx.UFraction32[] value)
: base(tag, value)
{
;
}
public GPSLatitudeLongitude(ExifTag tag, float d, float m, float s)
: base(tag, new MathEx.UFraction32[] { new MathEx.UFraction32(d), new MathEx.UFraction32(m), new MathEx.UFraction32(s) })
{
;
}
}
/// <summary>
/// Represents a GPS time stamp as UTC (EXIF Specification: 3xRATIONAL)
/// </summary>
internal class GPSTimeStamp : ExifURationalArray
{
protected new MathEx.UFraction32[] Value { get { return mValue; } set { mValue = value; } }
public MathEx.UFraction32 Hour { get { return mValue[0]; } set { mValue[0] = value; } }
public MathEx.UFraction32 Minute { get { return mValue[1]; } set { mValue[1] = value; } }
public MathEx.UFraction32 Second { get { return mValue[2]; } set { mValue[2] = value; } }
public override string ToString()
{
return string.Format("{0:F2}:{1:F2}:{2:F2}\"", (float)Hour, (float)Minute, (float)Second);
}
public GPSTimeStamp(ExifTag tag, MathEx.UFraction32[] value)
: base(tag, value)
{
;
}
public GPSTimeStamp(ExifTag tag, float h, float m, float s)
: base(tag, new MathEx.UFraction32[] { new MathEx.UFraction32(h), new MathEx.UFraction32(m), new MathEx.UFraction32(s) })
{
;
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: BYTE)
/// Used by Windows XP.
/// </summary>
internal class WindowsByteString : ExifProperty
{
protected string mValue;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value; } }
static public implicit operator string(WindowsByteString obj) { return obj.mValue; }
public override string ToString() { return mValue; }
public WindowsByteString(ExifTag tag, string value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
byte[] data = Encoding.Unicode.GetBytes(mValue);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)data.Length, data);
}
}
}
}
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Provides a custom type descriptor for an ExifFile instance.
/// </summary>
internal sealed class ExifFileTypeDescriptionProvider : TypeDescriptionProvider
{
public ExifFileTypeDescriptionProvider()
: this(TypeDescriptor.GetProvider(typeof(ImageFile)))
{
}
public ExifFileTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{
}
/// <summary>
/// Gets a custom type descriptor for the given type and object.
/// </summary>
/// <param name="objectType">The type of object for which to retrieve the type descriptor.</param>
/// <param name="instance">An instance of the type. Can be null if no instance was passed to the <see cref="T:System.ComponentModel.TypeDescriptor"/>.</param>
/// <returns>
/// An <see cref="T:System.ComponentModel.ICustomTypeDescriptor"/> that can provide metadata for the type.
/// </returns>
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new ExifFileTypeDescriptor(base.GetTypeDescriptor(objectType, instance), instance);
}
}
/// <summary>
/// Expands ExifProperty objects contained in an ExifFile as seperate properties.
/// </summary>
internal sealed class ExifFileTypeDescriptor : CustomTypeDescriptor
{
ImageFile owner;
public ExifFileTypeDescriptor(ICustomTypeDescriptor parent, object instance)
: base(parent)
{
owner = (ImageFile)instance;
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return GetProperties();
}
/// <summary>
/// Returns a collection of property descriptors for the object represented by this type descriptor.
/// </summary>
/// <returns>
/// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> containing the property descriptions for the object represented by this type descriptor. The default is <see cref="F:System.ComponentModel.PropertyDescriptorCollection.Empty"/>.
/// </returns>
public override PropertyDescriptorCollection GetProperties()
{
// Enumerate the original set of properties and create our new set with it
List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
foreach (ExifProperty prop in owner.Properties)
{
ExifPropertyDescriptor pd = new ExifPropertyDescriptor(prop);
properties.Add(pd);
}
// Finally return the list
return new PropertyDescriptorCollection(properties.ToArray(), true);
}
}
internal sealed class ExifPropertyDescriptor : PropertyDescriptor
{
object originalValue;
ExifProperty linkedProperty;
public ExifPropertyDescriptor(ExifProperty property)
: base(property.Name, new Attribute[] { new BrowsableAttribute(true) })
{
linkedProperty = property;
originalValue = property.Value;
}
public override bool CanResetValue(object component)
{
return true;
}
public override Type ComponentType
{
get { return typeof(JPEGFile); }
}
public override object GetValue(object component)
{
return linkedProperty.Value;
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type PropertyType
{
get { return linkedProperty.Value.GetType(); }
}
public override void ResetValue(object component)
{
linkedProperty.Value = originalValue;
}
public override void SetValue(object component, object value)
{
linkedProperty.Value = value;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
}
@@ -0,0 +1,60 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents interoperability data for an exif tag in the platform byte order.
/// </summary>
internal struct ExifInterOperability
{
private ushort mTagID;
private ushort mTypeID;
private uint mCount;
private byte[] mData;
/// <summary>
/// Gets the tag ID defined in the Exif standard.
/// </summary>
public ushort TagID { get { return mTagID; } }
/// <summary>
/// Gets the type code defined in the Exif standard.
/// <list type="bullet">
/// <item>1 = BYTE (byte)</item>
/// <item>2 = ASCII (byte array)</item>
/// <item>3 = SHORT (ushort)</item>
/// <item>4 = LONG (uint)</item>
/// <item>5 = RATIONAL (2 x uint: numerator, denominator)</item>
/// <item>6 = BYTE (sbyte)</item>
/// <item>7 = UNDEFINED (byte array)</item>
/// <item>8 = SSHORT (short)</item>
/// <item>9 = SLONG (int)</item>
/// <item>10 = SRATIONAL (2 x int: numerator, denominator)</item>
/// <item>11 = FLOAT (float)</item>
/// <item>12 = DOUBLE (double)</item>
/// </list>
/// </summary>
public ushort TypeID { get { return mTypeID; } }
/// <summary>
/// Gets the byte count or number of components.
/// </summary>
public uint Count { get { return mCount; } }
/// <summary>
/// Gets the field value as an array of bytes.
/// </summary>
public byte[] Data { get { return mData; } }
/// <summary>
/// Returns the string representation of this instance.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("Tag: {0}, Type: {1}, Count: {2}, Data Length: {3}", mTagID, mTypeID, mCount, mData.Length);
}
public ExifInterOperability(ushort tagid, ushort typeid, uint count, byte[] data)
{
mTagID = tagid;
mTypeID = typeid;
mCount = count;
mData = data;
}
}
}
+578
View File
@@ -0,0 +1,578 @@
using System;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the abstract base class for an Exif property.
/// </summary>
internal abstract class ExifProperty
{
protected ExifTag mTag;
protected IFD mIFD;
protected string mName;
/// <summary>
/// Gets the Exif tag associated with this property.
/// </summary>
public ExifTag Tag { get { return mTag; } }
/// <summary>
/// Gets the IFD section contaning this property.
/// </summary>
public IFD IFD { get { return mIFD; } }
/// <summary>
/// Gets or sets the name of this property.
/// </summary>
public string Name
{
get
{
if (mName == null || mName.Length == 0)
return ExifTagFactory.GetTagName(mTag);
else
return mName;
}
set
{
mName = value;
}
}
protected abstract object _Value { get; set; }
/// <summary>
/// Gets or sets the value of this property.
/// </summary>
public object Value { get { return _Value; } set { _Value = value; } }
/// <summary>
/// Gets interoperability data for this property.
/// </summary>
public abstract ExifInterOperability Interoperability { get; }
public ExifProperty(ExifTag tag)
{
mTag = tag;
mIFD = ExifTagFactory.GetTagIFD(tag);
}
}
/// <summary>
/// Represents an 8-bit unsigned integer. (EXIF Specification: BYTE)
/// </summary>
internal class ExifByte : ExifProperty
{
protected byte mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToByte(value); } }
public new byte Value { get { return mValue; } set { mValue = value; } }
static public implicit operator byte(ExifByte obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifByte(ExifTag tag, byte value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, 1, new byte[] { mValue });
}
}
}
/// <summary>
/// Represents an array of 8-bit unsigned integers. (EXIF Specification: BYTE with count > 1)
/// </summary>
internal class ExifByteArray : ExifProperty
{
protected byte[] mValue;
protected override object _Value { get { return Value; } set { Value = (byte[])value; } }
public new byte[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator byte[](ExifByteArray obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (byte b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifByteArray(ExifTag tag, byte[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.Length, mValue);
}
}
}
/// <summary>
/// Represents an ASCII string. (EXIF Specification: ASCII)
/// </summary>
internal class ExifAscii : ExifProperty
{
protected string mValue;
protected override object _Value { get { return Value; } set { Value = (string)value; } }
public new string Value { get { return mValue; } set { mValue = value; } }
public Encoding Encoding { get; private set; }
static public implicit operator string(ExifAscii obj) { return obj.mValue; }
public override string ToString() { return mValue; }
public ExifAscii(ExifTag tag, string value, Encoding encoding)
: base(tag)
{
mValue = value;
Encoding = encoding;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 2, (uint)mValue.Length + 1, ExifBitConverter.GetBytes(mValue, true, Encoding));
}
}
}
/// <summary>
/// Represents a 16-bit unsigned integer. (EXIF Specification: SHORT)
/// </summary>
internal class ExifUShort : ExifProperty
{
protected ushort mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToUInt16(value); } }
public new ushort Value { get { return mValue; } set { mValue = value; } }
static public implicit operator ushort(ExifUShort obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifUShort(ExifTag tag, ushort value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of 16-bit unsigned integers.
/// (EXIF Specification: SHORT with count > 1)
/// </summary>
internal class ExifUShortArray : ExifProperty
{
protected ushort[] mValue;
protected override object _Value { get { return Value; } set { Value = (ushort[])value; } }
public new ushort[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator ushort[](ExifUShortArray obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (ushort b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifUShortArray(ExifTag tag, ushort[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a 32-bit unsigned integer. (EXIF Specification: LONG)
/// </summary>
internal class ExifUInt : ExifProperty
{
protected uint mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToUInt32(value); } }
public new uint Value { get { return mValue; } set { mValue = value; } }
static public implicit operator uint(ExifUInt obj) { return obj.mValue; }
public override string ToString() { return mValue.ToString(); }
public ExifUInt(ExifTag tag, uint value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 4, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of 16-bit unsigned integers.
/// (EXIF Specification: LONG with count > 1)
/// </summary>
internal class ExifUIntArray : ExifProperty
{
protected uint[] mValue;
protected override object _Value { get { return Value; } set { Value = (uint[])value; } }
public new uint[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator uint[](ExifUIntArray obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (uint b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifUIntArray(ExifTag tag, uint[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 3, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a rational number defined with a 32-bit unsigned numerator
/// and denominator. (EXIF Specification: RATIONAL)
/// </summary>
internal class ExifURational : ExifProperty
{
protected MathEx.UFraction32 mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.UFraction32)value; } }
public new MathEx.UFraction32 Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.ToString(); }
public float ToFloat() { return (float)mValue; }
static public explicit operator float(ExifURational obj) { return (float)obj.mValue; }
public uint[] ToArray()
{
return new uint[] { mValue.Numerator, mValue.Denominator };
}
public ExifURational(ExifTag tag, uint numerator, uint denominator)
: base(tag)
{
mValue = new MathEx.UFraction32(numerator, denominator);
}
public ExifURational(ExifTag tag, MathEx.UFraction32 value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 5, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of unsigned rational numbers.
/// (EXIF Specification: RATIONAL with count > 1)
/// </summary>
internal class ExifURationalArray : ExifProperty
{
protected MathEx.UFraction32[] mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.UFraction32[])value; } }
public new MathEx.UFraction32[] Value { get { return mValue; } set { mValue = value; } }
static public explicit operator float[](ExifURationalArray obj)
{
float[] result = new float[obj.mValue.Length];
for (int i = 0; i < obj.mValue.Length; i++)
result[i] = (float)obj.mValue[i];
return result;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (MathEx.UFraction32 b in mValue)
{
sb.Append(b.ToString());
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifURationalArray(ExifTag tag, MathEx.UFraction32[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 5, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a byte array that can take any value. (EXIF Specification: UNDEFINED)
/// </summary>
internal class ExifUndefined : ExifProperty
{
protected byte[] mValue;
protected override object _Value { get { return Value; } set { Value = (byte[])value; } }
public new byte[] Value { get { return mValue; } set { mValue = value; } }
static public implicit operator byte[](ExifUndefined obj) { return obj.mValue; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (byte b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifUndefined(ExifTag tag, byte[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 7, (uint)mValue.Length, mValue);
}
}
}
/// <summary>
/// Represents a 32-bit signed integer. (EXIF Specification: SLONG)
/// </summary>
internal class ExifSInt : ExifProperty
{
protected int mValue;
protected override object _Value { get { return Value; } set { Value = Convert.ToInt32(value); } }
public new int Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.ToString(); }
static public implicit operator int(ExifSInt obj) { return obj.mValue; }
public ExifSInt(ExifTag tag, int value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 9, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of 32-bit signed integers.
/// (EXIF Specification: SLONG with count > 1)
/// </summary>
internal class ExifSIntArray : ExifProperty
{
protected int[] mValue;
protected override object _Value { get { return Value; } set { Value = (int[])value; } }
public new int[] Value { get { return mValue; } set { mValue = value; } }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (int b in mValue)
{
sb.Append(b);
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
static public implicit operator int[](ExifSIntArray obj) { return obj.mValue; }
public ExifSIntArray(ExifTag tag, int[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 9, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents a rational number defined with a 32-bit signed numerator
/// and denominator. (EXIF Specification: SRATIONAL)
/// </summary>
internal class ExifSRational : ExifProperty
{
protected MathEx.Fraction32 mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.Fraction32)value; } }
public new MathEx.Fraction32 Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.ToString(); }
public float ToFloat() { return (float)mValue; }
static public explicit operator float(ExifSRational obj) { return (float)obj.mValue; }
public int[] ToArray()
{
return new int[] { mValue.Numerator, mValue.Denominator };
}
public ExifSRational(ExifTag tag, int numerator, int denominator)
: base(tag)
{
mValue = new MathEx.Fraction32(numerator, denominator);
}
public ExifSRational(ExifTag tag, MathEx.Fraction32 value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 10, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
/// <summary>
/// Represents an array of signed rational numbers.
/// (EXIF Specification: SRATIONAL with count > 1)
/// </summary>
internal class ExifSRationalArray : ExifProperty
{
protected MathEx.Fraction32[] mValue;
protected override object _Value { get { return Value; } set { Value = (MathEx.Fraction32[])value; } }
public new MathEx.Fraction32[] Value { get { return mValue; } set { mValue = value; } }
static public explicit operator float[](ExifSRationalArray obj)
{
float[] result = new float[obj.mValue.Length];
for (int i = 0; i < obj.mValue.Length; i++)
result[i] = (float)obj.mValue[i];
return result;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('[');
foreach (MathEx.Fraction32 b in mValue)
{
sb.Append(b.ToString());
sb.Append(' ');
}
sb.Remove(sb.Length - 1, 1);
sb.Append(']');
return sb.ToString();
}
public ExifSRationalArray(ExifTag tag, MathEx.Fraction32[] value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 10, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder));
}
}
}
}
@@ -0,0 +1,380 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents a collection of <see cref="ExifProperty"/> objects.
/// </summary>
internal class ExifPropertyCollection : IDictionary<ExifTag, ExifProperty>
{
#region Member Variables
private ImageFile parent;
private Dictionary<ExifTag, ExifProperty> items;
#endregion
#region Constructor
internal ExifPropertyCollection (ImageFile parentFile)
{
parent = parentFile;
items = new Dictionary<ExifTag, ExifProperty> ();
}
#endregion
#region Properties
/// <summary>
/// Gets the number of elements contained in the collection.
/// </summary>
public int Count {
get { return items.Count; }
}
/// <summary>
/// Gets a collection containing the keys in this collection.
/// </summary>
public ICollection<ExifTag> Keys {
get { return items.Keys; }
}
/// <summary>
/// Gets a collection containing the values in this collection.
/// </summary>
public ICollection<ExifProperty> Values {
get { return items.Values; }
}
/// <summary>
/// Gets or sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
public ExifProperty this[ExifTag key] {
get { return items[key]; }
set {
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, value);
}
}
#endregion
#region ExifProperty Collection Setters
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, byte value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifByte (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, string value)
{
if (items.ContainsKey (key))
items.Remove (key);
if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) {
items.Add (key, new WindowsByteString (key, value));
} else {
items.Add (key, new ExifAscii (key, value, parent.Encoding));
}
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, ushort value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifUShort (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, int value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifSInt (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, uint value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifUInt (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, float value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifURational (key, new MathEx.UFraction32 (value)));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, double value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifURational (key, new MathEx.UFraction32 (value)));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, object value)
{
Type type = value.GetType ();
if (type.IsEnum) {
Type etype = typeof(ExifEnumProperty<>).MakeGenericType (new Type[] { type });
object prop = Activator.CreateInstance (etype, new object[] { key, value });
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, (ExifProperty)prop);
} else
throw new ArgumentException ("No exif property exists for this tag.", "value");
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
/// <param name="encoding">String encoding.</param>
public void Set (ExifTag key, string value, Encoding encoding)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifEncodedString (key, value, encoding));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set (ExifTag key, DateTime value)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifDateTime (key, value));
}
/// <summary>
/// Sets the <see cref="ExifProperty"/> with the specified key.
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="d">Angular degrees (or clock hours for a timestamp).</param>
/// <param name="m">Angular minutes (or clock minutes for a timestamp).</param>
/// <param name="s">Angular seconds (or clock seconds for a timestamp).</param>
public void Set (ExifTag key, float d, float m, float s)
{
if (items.ContainsKey (key))
items.Remove (key);
items.Add (key, new ExifURationalArray (key, new MathEx.UFraction32[] { new MathEx.UFraction32 (d), new MathEx.UFraction32 (m), new MathEx.UFraction32 (s) }));
}
#endregion
#region Instance Methods
/// <summary>
/// Adds the specified item to the collection.
/// </summary>
/// <param name="item">The <see cref="ExifProperty"/> to add to the collection.</param>
public void Add (ExifProperty item)
{
ExifProperty oldItem = null;
if (items.TryGetValue (item.Tag, out oldItem))
items[item.Tag] = item;
else
items.Add (item.Tag, item);
}
/// <summary>
/// Removes all items from the collection.
/// </summary>
public void Clear ()
{
items.Clear ();
}
/// <summary>
/// Determines whether the collection contains an element with the specified key.
/// </summary>
/// <param name="key">The key to locate in the collection.</param>
/// <returns>
/// true if the collection contains an element with the key; otherwise, false.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
public bool ContainsKey (ExifTag key)
{
return items.ContainsKey (key);
}
/// <summary>
/// Removes the element with the specified key from the collection.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
/// <returns>
/// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not found in the original collection.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
public bool Remove (ExifTag key)
{
return items.Remove (key);
}
/// <summary>
/// Removes all items with the given IFD from the collection.
/// </summary>
/// <param name="ifd">The IFD section to remove.</param>
public void Remove (IFD ifd)
{
List<ExifTag> toRemove = new List<ExifTag> ();
foreach (KeyValuePair<ExifTag, ExifProperty> item in items) {
if (item.Value.IFD == ifd)
toRemove.Add (item.Key);
}
foreach (ExifTag tag in toRemove)
items.Remove (tag);
}
/// <summary>
/// Gets the value associated with the specified key.
/// </summary>
/// <param name="key">The key whose value to get.</param>
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param>
/// <returns>
/// true if the collection contains an element with the specified key; otherwise, false.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
public bool TryGetValue (ExifTag key, out ExifProperty value)
{
return items.TryGetValue (key, out value);
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
public IEnumerator<ExifProperty> GetEnumerator ()
{
return Values.GetEnumerator ();
}
#endregion
#region Hidden Interface
/// <summary>
/// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
/// </summary>
/// <param name="key">The object to use as the key of the element to add.</param>
/// <param name="value">The object to use as the value of the element to add.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null.</exception>
/// <exception cref="T:System.ArgumentException">An element with the same key already exists in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</exception>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception>
void IDictionary<ExifTag, ExifProperty>.Add (ExifTag key, ExifProperty value)
{
Add (value);
}
/// <summary>
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
void ICollection<KeyValuePair<ExifTag, ExifProperty>>.Add (KeyValuePair<ExifTag, ExifProperty> item)
{
Add (item.Value);
}
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.Contains (KeyValuePair<ExifTag, ExifProperty> item)
{
throw new NotSupportedException ();
}
/// <summary>
/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="array"/> is null.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="arrayIndex"/> is less than 0.</exception>
/// <exception cref="T:System.ArgumentException">
/// <paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type <paramref name="T"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
void ICollection<KeyValuePair<ExifTag, ExifProperty>>.CopyTo (KeyValuePair<ExifTag, ExifProperty>[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException ("array");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException ("arrayIndex");
if (array.Rank > 1)
throw new ArgumentException ("Destination array is multidimensional.", "array");
if (arrayIndex >= array.Length)
throw new ArgumentException ("arrayIndex is equal to or greater than the length of destination array", "array");
if (arrayIndex + items.Count > array.Length)
throw new ArgumentException ("There is not enough space in destination array.", "array");
int i = 0;
foreach (KeyValuePair<ExifTag, ExifProperty> item in items) {
if (i >= arrayIndex) {
array[i] = item;
}
i++;
}
}
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </summary>
/// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.</returns>
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.IsReadOnly {
get { return false; }
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
/// <returns>
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
bool ICollection<KeyValuePair<ExifTag, ExifProperty>>.Remove (KeyValuePair<ExifTag, ExifProperty> item)
{
throw new NotSupportedException ();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
IEnumerator<KeyValuePair<ExifTag, ExifProperty>> IEnumerable<KeyValuePair<ExifTag, ExifProperty>>.GetEnumerator ()
{
return items.GetEnumerator ();
}
#endregion
}
}
@@ -0,0 +1,253 @@
using System;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Creates exif properties from interoperability parameters.
/// </summary>
internal static class ExifPropertyFactory
{
#region Static Methods
/// <summary>
/// Creates an ExifProperty from the given interoperability parameters.
/// </summary>
/// <param name="tag">The tag id of the exif property.</param>
/// <param name="type">The type id of the exif property.</param>
/// <param name="count">Byte or component count.</param>
/// <param name="value">Field data as an array of bytes.</param>
/// <param name="byteOrder">Byte order of value.</param>
/// <param name="ifd">IFD section containing this propery.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>an ExifProperty initialized from the interoperability parameters.</returns>
public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value, BitConverterEx.ByteOrder byteOrder, IFD ifd, Encoding encoding)
{
BitConverterEx conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder);
// Find the exif tag corresponding to given tag id
ExifTag etag = ExifTagFactory.GetExifTag(ifd, tag);
if (ifd == IFD.Zeroth)
{
if (tag == 0x103) // Compression
return new ExifEnumProperty<Compression>(ExifTag.Compression, (Compression)conv.ToUInt16(value, 0));
else if (tag == 0x106) // PhotometricInterpretation
return new ExifEnumProperty<PhotometricInterpretation>(ExifTag.PhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0));
else if (tag == 0x112) // Orientation
return new ExifEnumProperty<Orientation>(ExifTag.Orientation, (Orientation)conv.ToUInt16(value, 0));
else if (tag == 0x11c) // PlanarConfiguration
return new ExifEnumProperty<PlanarConfiguration>(ExifTag.PlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0));
else if (tag == 0x213) // YCbCrPositioning
return new ExifEnumProperty<YCbCrPositioning>(ExifTag.YCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0));
else if (tag == 0x128) // ResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.ResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0));
else if (tag == 0x132) // DateTime
return new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value));
else if (tag == 0x9c9b || tag == 0x9c9c || // Windows tags
tag == 0x9c9d || tag == 0x9c9e || tag == 0x9c9f)
return new WindowsByteString(etag, Encoding.Unicode.GetString(value).TrimEnd('\0'));
}
else if (ifd == IFD.EXIF)
{
if (tag == 0x9000) // ExifVersion
return new ExifVersion(ExifTag.ExifVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
else if (tag == 0xa000) // FlashpixVersion
return new ExifVersion(ExifTag.FlashpixVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
else if (tag == 0xa001) // ColorSpace
return new ExifEnumProperty<ColorSpace>(ExifTag.ColorSpace, (ColorSpace)conv.ToUInt16(value, 0));
else if (tag == 0x9286) // UserComment
{
// Default to ASCII
Encoding enc = Encoding.ASCII;
bool hasenc;
if (value.Length < 8)
hasenc = false;
else
{
hasenc = true;
string encstr = enc.GetString(value, 0, 8);
if (string.Compare(encstr, "ASCII\0\0\0", StringComparison.OrdinalIgnoreCase) == 0)
enc = Encoding.ASCII;
else if (string.Compare(encstr, "JIS\0\0\0\0\0", StringComparison.OrdinalIgnoreCase) == 0)
enc = Encoding.GetEncoding("Japanese (JIS 0208-1990 and 0212-1990)");
else if (string.Compare(encstr, "Unicode\0", StringComparison.OrdinalIgnoreCase) == 0)
enc = Encoding.Unicode;
else
hasenc = false;
}
string val = (hasenc ? enc.GetString(value, 8, value.Length - 8) : enc.GetString(value)).Trim('\0');
return new ExifEncodedString(ExifTag.UserComment, val, enc);
}
else if (tag == 0x9003) // DateTimeOriginal
return new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value));
else if (tag == 0x9004) // DateTimeDigitized
return new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value));
else if (tag == 0x8822) // ExposureProgram
return new ExifEnumProperty<ExposureProgram>(ExifTag.ExposureProgram, (ExposureProgram)conv.ToUInt16(value, 0));
else if (tag == 0x9207) // MeteringMode
return new ExifEnumProperty<MeteringMode>(ExifTag.MeteringMode, (MeteringMode)conv.ToUInt16(value, 0));
else if (tag == 0x9208) // LightSource
return new ExifEnumProperty<LightSource>(ExifTag.LightSource, (LightSource)conv.ToUInt16(value, 0));
else if (tag == 0x9209) // Flash
return new ExifEnumProperty<Flash>(ExifTag.Flash, (Flash)conv.ToUInt16(value, 0), true);
else if (tag == 0x9214) // SubjectArea
{
if (count == 3)
return new ExifCircularSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
else if (count == 4)
return new ExifRectangularSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
else // count == 2
return new ExifPointSubjectArea(ExifTag.SubjectArea, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
else if (tag == 0xa210) // FocalPlaneResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.FocalPlaneResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0), true);
else if (tag == 0xa214) // SubjectLocation
return new ExifPointSubjectArea(ExifTag.SubjectLocation, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
else if (tag == 0xa217) // SensingMethod
return new ExifEnumProperty<SensingMethod>(ExifTag.SensingMethod, (SensingMethod)conv.ToUInt16(value, 0), true);
else if (tag == 0xa300) // FileSource
return new ExifEnumProperty<FileSource>(ExifTag.FileSource, (FileSource)conv.ToUInt16(value, 0), true);
else if (tag == 0xa301) // SceneType
return new ExifEnumProperty<SceneType>(ExifTag.SceneType, (SceneType)conv.ToUInt16(value, 0), true);
else if (tag == 0xa401) // CustomRendered
return new ExifEnumProperty<CustomRendered>(ExifTag.CustomRendered, (CustomRendered)conv.ToUInt16(value, 0), true);
else if (tag == 0xa402) // ExposureMode
return new ExifEnumProperty<ExposureMode>(ExifTag.ExposureMode, (ExposureMode)conv.ToUInt16(value, 0), true);
else if (tag == 0xa403) // WhiteBalance
return new ExifEnumProperty<WhiteBalance>(ExifTag.WhiteBalance, (WhiteBalance)conv.ToUInt16(value, 0), true);
else if (tag == 0xa406) // SceneCaptureType
return new ExifEnumProperty<SceneCaptureType>(ExifTag.SceneCaptureType, (SceneCaptureType)conv.ToUInt16(value, 0), true);
else if (tag == 0xa407) // GainControl
return new ExifEnumProperty<GainControl>(ExifTag.GainControl, (GainControl)conv.ToUInt16(value, 0), true);
else if (tag == 0xa408) // Contrast
return new ExifEnumProperty<Contrast>(ExifTag.Contrast, (Contrast)conv.ToUInt16(value, 0), true);
else if (tag == 0xa409) // Saturation
return new ExifEnumProperty<Saturation>(ExifTag.Saturation, (Saturation)conv.ToUInt16(value, 0), true);
else if (tag == 0xa40a) // Sharpness
return new ExifEnumProperty<Sharpness>(ExifTag.Sharpness, (Sharpness)conv.ToUInt16(value, 0), true);
else if (tag == 0xa40c) // SubjectDistanceRange
return new ExifEnumProperty<SubjectDistanceRange>(ExifTag.SubjectDistanceRange, (SubjectDistanceRange)conv.ToUInt16(value, 0), true);
}
else if (ifd == IFD.GPS)
{
if (tag == 0) // GPSVersionID
return new ExifVersion(ExifTag.GPSVersionID, ExifBitConverter.ToString(value));
else if (tag == 1) // GPSLatitudeRef
return new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSLatitudeRef, (GPSLatitudeRef)value[0]);
else if (tag == 2) // GPSLatitude
return new GPSLatitudeLongitude(ExifTag.GPSLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 3) // GPSLongitudeRef
return new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSLongitudeRef, (GPSLongitudeRef)value[0]);
else if (tag == 4) // GPSLongitude
return new GPSLatitudeLongitude(ExifTag.GPSLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 5) // GPSAltitudeRef
return new ExifEnumProperty<GPSAltitudeRef>(ExifTag.GPSAltitudeRef, (GPSAltitudeRef)value[0]);
else if (tag == 7) // GPSTimeStamp
return new GPSTimeStamp(ExifTag.GPSTimeStamp, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 9) // GPSStatus
return new ExifEnumProperty<GPSStatus>(ExifTag.GPSStatus, (GPSStatus)value[0]);
else if (tag == 10) // GPSMeasureMode
return new ExifEnumProperty<GPSMeasureMode>(ExifTag.GPSMeasureMode, (GPSMeasureMode)value[0]);
else if (tag == 12) // GPSSpeedRef
return new ExifEnumProperty<GPSSpeedRef>(ExifTag.GPSSpeedRef, (GPSSpeedRef)value[0]);
else if (tag == 14) // GPSTrackRef
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSTrackRef, (GPSDirectionRef)value[0]);
else if (tag == 16) // GPSImgDirectionRef
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSImgDirectionRef, (GPSDirectionRef)value[0]);
else if (tag == 19) // GPSDestLatitudeRef
return new ExifEnumProperty<GPSLatitudeRef>(ExifTag.GPSDestLatitudeRef, (GPSLatitudeRef)value[0]);
else if (tag == 20) // GPSDestLatitude
return new GPSLatitudeLongitude(ExifTag.GPSDestLatitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 21) // GPSDestLongitudeRef
return new ExifEnumProperty<GPSLongitudeRef>(ExifTag.GPSDestLongitudeRef, (GPSLongitudeRef)value[0]);
else if (tag == 22) // GPSDestLongitude
return new GPSLatitudeLongitude(ExifTag.GPSDestLongitude, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
else if (tag == 23) // GPSDestBearingRef
return new ExifEnumProperty<GPSDirectionRef>(ExifTag.GPSDestBearingRef, (GPSDirectionRef)value[0]);
else if (tag == 25) // GPSDestDistanceRef
return new ExifEnumProperty<GPSDistanceRef>(ExifTag.GPSDestDistanceRef, (GPSDistanceRef)value[0]);
else if (tag == 29) // GPSDate
return new ExifDateTime(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false));
else if (tag == 30) // GPSDifferential
return new ExifEnumProperty<GPSDifferential>(ExifTag.GPSDifferential, (GPSDifferential)conv.ToUInt16(value, 0));
}
else if (ifd == IFD.Interop)
{
if (tag == 1) // InteroperabilityIndex
return new ExifAscii(ExifTag.InteroperabilityIndex, ExifBitConverter.ToAscii(value, Encoding.ASCII), Encoding.ASCII);
else if (tag == 2) // InteroperabilityVersion
return new ExifVersion(ExifTag.InteroperabilityVersion, ExifBitConverter.ToAscii(value, Encoding.ASCII));
}
else if (ifd == IFD.First)
{
if (tag == 0x103) // Compression
return new ExifEnumProperty<Compression>(ExifTag.ThumbnailCompression, (Compression)conv.ToUInt16(value, 0));
else if (tag == 0x106) // PhotometricInterpretation
return new ExifEnumProperty<PhotometricInterpretation>(ExifTag.ThumbnailPhotometricInterpretation, (PhotometricInterpretation)conv.ToUInt16(value, 0));
else if (tag == 0x112) // Orientation
return new ExifEnumProperty<Orientation>(ExifTag.ThumbnailOrientation, (Orientation)conv.ToUInt16(value, 0));
else if (tag == 0x11c) // PlanarConfiguration
return new ExifEnumProperty<PlanarConfiguration>(ExifTag.ThumbnailPlanarConfiguration, (PlanarConfiguration)conv.ToUInt16(value, 0));
else if (tag == 0x213) // YCbCrPositioning
return new ExifEnumProperty<YCbCrPositioning>(ExifTag.ThumbnailYCbCrPositioning, (YCbCrPositioning)conv.ToUInt16(value, 0));
else if (tag == 0x128) // ResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.ThumbnailResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0));
else if (tag == 0x132) // DateTime
return new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value));
}
if (type == 1) // 1 = BYTE An 8-bit unsigned integer.
{
if (count == 1)
return new ExifByte(etag, value[0]);
else
return new ExifByteArray(etag, value);
}
else if (type == 2) // 2 = ASCII An 8-bit byte containing one 7-bit ASCII code.
{
return new ExifAscii(etag, ExifBitConverter.ToAscii(value, encoding), encoding);
}
else if (type == 3) // 3 = SHORT A 16-bit (2-byte) unsigned integer.
{
if (count == 1)
return new ExifUShort(etag, conv.ToUInt16(value, 0));
else
return new ExifUShortArray(etag, ExifBitConverter.ToUShortArray(value, (int)count, byteOrder));
}
else if (type == 4) // 4 = LONG A 32-bit (4-byte) unsigned integer.
{
if (count == 1)
return new ExifUInt(etag, conv.ToUInt32(value, 0));
else
return new ExifUIntArray(etag, ExifBitConverter.ToUIntArray(value, (int)count, byteOrder));
}
else if (type == 5) // 5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator.
{
if (count == 1)
return new ExifURational(etag, ExifBitConverter.ToURational(value, byteOrder));
else
return new ExifURationalArray(etag, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder));
}
else if (type == 7) // 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition.
return new ExifUndefined(etag, value);
else if (type == 9) // 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation).
{
if (count == 1)
return new ExifSInt(etag, conv.ToInt32(value, 0));
else
return new ExifSIntArray(etag, ExifBitConverter.ToSIntArray(value, (int)count, byteOrder));
}
else if (type == 10) // 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator.
{
if (count == 1)
return new ExifSRational(etag, ExifBitConverter.ToSRational(value, byteOrder));
else
return new ExifSRationalArray(etag, ExifBitConverter.ToSRationalArray(value, (int)count, byteOrder));
}
else
throw new ArgumentException("Unknown property type.");
}
#endregion
}
}
+290
View File
@@ -0,0 +1,290 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the tags associated with exif fields.
/// </summary>
internal enum ExifTag : int
{
// ****************************
// Zeroth IFD
// ****************************
NewSubfileType = IFD.Zeroth + 254,
SubfileType = IFD.Zeroth + 255,
ImageWidth = IFD.Zeroth + 256,
ImageLength = IFD.Zeroth + 257,
BitsPerSample = IFD.Zeroth + 258,
Compression = IFD.Zeroth + 259,
PhotometricInterpretation = IFD.Zeroth + 262,
Threshholding = IFD.Zeroth + 263,
CellWidth = IFD.Zeroth + 264,
CellLength = IFD.Zeroth + 265,
FillOrder = IFD.Zeroth + 266,
DocumentName = IFD.Zeroth + 269,
ImageDescription = IFD.Zeroth + 270,
Make = IFD.Zeroth + 271,
Model = IFD.Zeroth + 272,
StripOffsets = IFD.Zeroth + 273,
Orientation = IFD.Zeroth + 274,
SamplesPerPixel = IFD.Zeroth + 277,
RowsPerStrip = IFD.Zeroth + 278,
StripByteCounts = IFD.Zeroth + 279,
MinSampleValue = IFD.Zeroth + 280,
MaxSampleValue = IFD.Zeroth + 281,
XResolution = IFD.Zeroth + 282,
YResolution = IFD.Zeroth + 283,
PlanarConfiguration = IFD.Zeroth + 284,
PageName = IFD.Zeroth + 285,
XPosition = IFD.Zeroth + 286,
YPosition = IFD.Zeroth + 287,
FreeOffsets = IFD.Zeroth + 288,
FreeByteCounts = IFD.Zeroth + 289,
GrayResponseUnit = IFD.Zeroth + 290,
GrayResponseCurve = IFD.Zeroth + 291,
T4Options = IFD.Zeroth + 292,
T6Options = IFD.Zeroth + 293,
ResolutionUnit = IFD.Zeroth + 296,
PageNumber = IFD.Zeroth + 297,
TransferFunction = IFD.Zeroth + 301,
Software = IFD.Zeroth + 305,
DateTime = IFD.Zeroth + 306,
Artist = IFD.Zeroth + 315,
HostComputer = IFD.Zeroth + 316,
Predictor = IFD.Zeroth + 317,
WhitePoint = IFD.Zeroth + 318,
PrimaryChromaticities = IFD.Zeroth + 319,
ColorMap = IFD.Zeroth + 320,
HalftoneHints = IFD.Zeroth + 321,
TileWidth = IFD.Zeroth + 322,
TileLength = IFD.Zeroth + 323,
TileOffsets = IFD.Zeroth + 324,
TileByteCounts = IFD.Zeroth + 325,
InkSet = IFD.Zeroth + 332,
InkNames = IFD.Zeroth + 333,
NumberOfInks = IFD.Zeroth + 334,
DotRange = IFD.Zeroth + 336,
TargetPrinter = IFD.Zeroth + 337,
ExtraSamples = IFD.Zeroth + 338,
SampleFormat = IFD.Zeroth + 339,
SMinSampleValue = IFD.Zeroth + 340,
SMaxSampleValue = IFD.Zeroth + 341,
TransferRange = IFD.Zeroth + 342,
JPEGProc = IFD.Zeroth + 512,
JPEGInterchangeFormat = IFD.Zeroth + 513,
JPEGInterchangeFormatLength = IFD.Zeroth + 514,
JPEGRestartInterval = IFD.Zeroth + 515,
JPEGLosslessPredictors = IFD.Zeroth + 517,
JPEGPointTransforms = IFD.Zeroth + 518,
JPEGQTables = IFD.Zeroth + 519,
JPEGDCTables = IFD.Zeroth + 520,
JPEGACTables = IFD.Zeroth + 521,
YCbCrCoefficients = IFD.Zeroth + 529,
YCbCrSubSampling = IFD.Zeroth + 530,
YCbCrPositioning = IFD.Zeroth + 531,
ReferenceBlackWhite = IFD.Zeroth + 532,
Copyright = IFD.Zeroth + 33432,
// Pointers to other IFDs
EXIFIFDPointer = IFD.Zeroth + 34665,
GPSIFDPointer = IFD.Zeroth + 34853,
// Windows Tags
WindowsTitle = IFD.Zeroth + 0x9c9b,
WindowsComment = IFD.Zeroth + 0x9c9c,
WindowsAuthor = IFD.Zeroth + 0x9c9d,
WindowsKeywords = IFD.Zeroth + 0x9c9e,
WindowsSubject = IFD.Zeroth + 0x9c9f,
// Rating
Rating = IFD.Zeroth + 0x4746,
RatingPercent = IFD.Zeroth + 0x4749,
// Microsoft specifing padding and offset tags
ZerothIFDPadding = IFD.Zeroth + 0xea1c,
// ****************************
// EXIF Tags
// ****************************
ExifVersion = IFD.EXIF + 36864,
FlashpixVersion = IFD.EXIF + 40960,
ColorSpace = IFD.EXIF + 40961,
ComponentsConfiguration = IFD.EXIF + 37121,
CompressedBitsPerPixel = IFD.EXIF + 37122,
PixelXDimension = IFD.EXIF + 40962,
PixelYDimension = IFD.EXIF + 40963,
MakerNote = IFD.EXIF + 37500,
UserComment = IFD.EXIF + 37510,
RelatedSoundFile = IFD.EXIF + 40964,
DateTimeOriginal = IFD.EXIF + 36867,
DateTimeDigitized = IFD.EXIF + 36868,
SubSecTime = IFD.EXIF + 37520,
SubSecTimeOriginal = IFD.EXIF + 37521,
SubSecTimeDigitized = IFD.EXIF + 37522,
ExposureTime = IFD.EXIF + 33434,
FNumber = IFD.EXIF + 33437,
ExposureProgram = IFD.EXIF + 34850,
SpectralSensitivity = IFD.EXIF + 34852,
ISOSpeedRatings = IFD.EXIF + 34855,
OECF = IFD.EXIF + 34856,
ShutterSpeedValue = IFD.EXIF + 37377,
ApertureValue = IFD.EXIF + 37378,
BrightnessValue = IFD.EXIF + 37379,
ExposureBiasValue = IFD.EXIF + 37380,
MaxApertureValue = IFD.EXIF + 37381,
SubjectDistance = IFD.EXIF + 37382,
MeteringMode = IFD.EXIF + 37383,
LightSource = IFD.EXIF + 37384,
Flash = IFD.EXIF + 37385,
FocalLength = IFD.EXIF + 37386,
SubjectArea = IFD.EXIF + 37396,
FlashEnergy = IFD.EXIF + 41483,
SpatialFrequencyResponse = IFD.EXIF + 41484,
FocalPlaneXResolution = IFD.EXIF + 41486,
FocalPlaneYResolution = IFD.EXIF + 41487,
FocalPlaneResolutionUnit = IFD.EXIF + 41488,
SubjectLocation = IFD.EXIF + 41492,
ExposureIndex = IFD.EXIF + 41493,
SensingMethod = IFD.EXIF + 41495,
FileSource = IFD.EXIF + 41728,
SceneType = IFD.EXIF + 41729,
CFAPattern = IFD.EXIF + 41730,
CustomRendered = IFD.EXIF + 41985,
ExposureMode = IFD.EXIF + 41986,
WhiteBalance = IFD.EXIF + 41987,
DigitalZoomRatio = IFD.EXIF + 41988,
FocalLengthIn35mmFilm = IFD.EXIF + 41989,
SceneCaptureType = IFD.EXIF + 41990,
GainControl = IFD.EXIF + 41991,
Contrast = IFD.EXIF + 41992,
Saturation = IFD.EXIF + 41993,
Sharpness = IFD.EXIF + 41994,
DeviceSettingDescription = IFD.EXIF + 41995,
SubjectDistanceRange = IFD.EXIF + 41996,
ImageUniqueID = IFD.EXIF + 42016,
InteroperabilityIFDPointer = IFD.EXIF + 40965,
// Microsoft specifing padding and offset tags
ExifIFDPadding = IFD.EXIF + 0xea1c,
OffsetSchema = IFD.EXIF + 0xea1d,
// ****************************
// GPS Tags
// ****************************
GPSVersionID = IFD.GPS + 0,
GPSLatitudeRef = IFD.GPS + 1,
GPSLatitude = IFD.GPS + 2,
GPSLongitudeRef = IFD.GPS + 3,
GPSLongitude = IFD.GPS + 4,
GPSAltitudeRef = IFD.GPS + 5,
GPSAltitude = IFD.GPS + 6,
GPSTimeStamp = IFD.GPS + 7,
GPSSatellites = IFD.GPS + 8,
GPSStatus = IFD.GPS + 9,
GPSMeasureMode = IFD.GPS + 10,
GPSDOP = IFD.GPS + 11,
GPSSpeedRef = IFD.GPS + 12,
GPSSpeed = IFD.GPS + 13,
GPSTrackRef = IFD.GPS + 14,
GPSTrack = IFD.GPS + 15,
GPSImgDirectionRef = IFD.GPS + 16,
GPSImgDirection = IFD.GPS + 17,
GPSMapDatum = IFD.GPS + 18,
GPSDestLatitudeRef = IFD.GPS + 19,
GPSDestLatitude = IFD.GPS + 20,
GPSDestLongitudeRef = IFD.GPS + 21,
GPSDestLongitude = IFD.GPS + 22,
GPSDestBearingRef = IFD.GPS + 23,
GPSDestBearing = IFD.GPS + 24,
GPSDestDistanceRef = IFD.GPS + 25,
GPSDestDistance = IFD.GPS + 26,
GPSProcessingMethod = IFD.GPS + 27,
GPSAreaInformation = IFD.GPS + 28,
GPSDateStamp = IFD.GPS + 29,
GPSDifferential = IFD.GPS + 30,
// ****************************
// InterOp Tags
// ****************************
InteroperabilityIndex = IFD.Interop + 1,
InteroperabilityVersion = IFD.Interop + 2,
RelatedImageWidth = IFD.Interop + 0x1001,
RelatedImageHeight = IFD.Interop + 0x1002,
// ****************************
// First IFD TIFF Tags
// ****************************
ThumbnailImageWidth = IFD.First + 256,
ThumbnailImageLength = IFD.First + 257,
ThumbnailBitsPerSample = IFD.First + 258,
ThumbnailCompression = IFD.First + 259,
ThumbnailPhotometricInterpretation = IFD.First + 262,
ThumbnailOrientation = IFD.First + 274,
ThumbnailSamplesPerPixel = IFD.First + 277,
ThumbnailPlanarConfiguration = IFD.First + 284,
ThumbnailYCbCrSubSampling = IFD.First + 530,
ThumbnailYCbCrPositioning = IFD.First + 531,
ThumbnailXResolution = IFD.First + 282,
ThumbnailYResolution = IFD.First + 283,
ThumbnailResolutionUnit = IFD.First + 296,
ThumbnailStripOffsets = IFD.First + 273,
ThumbnailRowsPerStrip = IFD.First + 278,
ThumbnailStripByteCounts = IFD.First + 279,
ThumbnailJPEGInterchangeFormat = IFD.First + 513,
ThumbnailJPEGInterchangeFormatLength = IFD.First + 514,
ThumbnailTransferFunction = IFD.First + 301,
ThumbnailWhitePoint = IFD.First + 318,
ThumbnailPrimaryChromaticities = IFD.First + 319,
ThumbnailYCbCrCoefficients = IFD.First + 529,
ThumbnailReferenceBlackWhite = IFD.First + 532,
ThumbnailDateTime = IFD.First + 306,
ThumbnailImageDescription = IFD.First + 270,
ThumbnailMake = IFD.First + 271,
ThumbnailModel = IFD.First + 272,
ThumbnailSoftware = IFD.First + 305,
ThumbnailArtist = IFD.First + 315,
ThumbnailCopyright = IFD.First + 33432,
// ****************************
// JFIF Tags
// ****************************
/// <summary>
/// Represents the JFIF version.
/// </summary>
JFIFVersion = IFD.JFIF + 1,
/// <summary>
/// Represents units for X and Y densities.
/// </summary>
JFIFUnits = IFD.JFIF + 101,
/// <summary>
/// Horizontal pixel density.
/// </summary>
XDensity = IFD.JFIF + 102,
/// <summary>
/// Vertical pixel density
/// </summary>
YDensity = IFD.JFIF + 103,
/// <summary>
/// Thumbnail horizontal pixel count.
/// </summary>
JFIFXThumbnail = IFD.JFIF + 201,
/// <summary>
/// Thumbnail vertical pixel count.
/// </summary>
JFIFYThumbnail = IFD.JFIF + 202,
/// <summary>
/// JFIF JPEG thumbnail.
/// </summary>
JFIFThumbnail = IFD.JFIF + 203,
/// <summary>
/// Code which identifies the JFIF extension.
/// </summary>
JFXXExtensionCode = IFD.JFXX + 1,
/// <summary>
/// Thumbnail horizontal pixel count.
/// </summary>
JFXXXThumbnail = IFD.JFXX + 101,
/// <summary>
/// Thumbnail vertical pixel count.
/// </summary>
JFXXYThumbnail = IFD.JFXX + 102,
/// <summary>
/// The 256-Color RGB palette.
/// </summary>
JFXXPalette = IFD.JFXX + 201,
/// <summary>
/// JFIF thumbnail. The thumbnail will be either a JPEG,
/// a 256 color palette bitmap, or a 24-bit RGB bitmap.
/// </summary>
JFXXThumbnail = IFD.JFXX + 202,
}
}
@@ -0,0 +1,68 @@
using System;
namespace Umbraco.Core.Media.Exif
{
internal static class ExifTagFactory
{
#region Static Methods
/// <summary>
/// Returns the ExifTag corresponding to the given tag id.
/// </summary>
public static ExifTag GetExifTag(IFD ifd, ushort tagid)
{
return (ExifTag)(ifd + tagid);
}
/// <summary>
/// Returns the tag id corresponding to the given ExifTag.
/// </summary>
public static ushort GetTagID(ExifTag exiftag)
{
IFD ifd = GetTagIFD(exiftag);
return (ushort)((int)exiftag - (int)ifd);
}
/// <summary>
/// Returns the IFD section containing the given tag.
/// </summary>
public static IFD GetTagIFD(ExifTag tag)
{
return (IFD)(((int)tag / 100000) * 100000);
}
/// <summary>
/// Returns the string representation for the given exif tag.
/// </summary>
public static string GetTagName(ExifTag tag)
{
string name = Enum.GetName(typeof(ExifTag), tag);
if (name == null)
return "Unknown";
else
return name;
}
/// <summary>
/// Returns the string representation for the given tag id.
/// </summary>
public static string GetTagName(IFD ifd, ushort tagid)
{
return GetTagName(GetExifTag(ifd, tagid));
}
/// <summary>
/// Returns the string representation for the given exif tag including
/// IFD section and tag id.
/// </summary>
public static string GetTagLongName(ExifTag tag)
{
string ifdname = Enum.GetName(typeof(IFD), GetTagIFD(tag));
string name = Enum.GetName(typeof(ExifTag), tag);
if (name == null)
name = "Unknown";
string tagidname = GetTagID(tag).ToString();
return ifdname + ": " + name + " (" + tagidname + ")";
}
#endregion
}
}
+18
View File
@@ -0,0 +1,18 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the IFD section containing tags.
/// </summary>
internal enum IFD : int
{
Unknown = 0,
Zeroth = 100000,
EXIF = 200000,
GPS = 300000,
Interop = 400000,
First = 500000,
MakerNote = 600000,
JFIF = 700000,
JFXX = 800000,
}
}
+140
View File
@@ -0,0 +1,140 @@
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the base class for image files.
/// </summary>
[TypeDescriptionProvider(typeof(ExifFileTypeDescriptionProvider))]
internal abstract class ImageFile
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="ImageFile"/> class.
/// </summary>
protected ImageFile ()
{
Format = ImageFileFormat.Unknown;
Properties = new ExifPropertyCollection (this);
Encoding = Encoding.Default;
}
#endregion
#region Properties
/// <summary>
/// Returns the format of the <see cref="ImageFile"/>.
/// </summary>
public ImageFileFormat Format { get; protected set; }
/// <summary>
/// Gets the collection of Exif properties contained in the <see cref="ImageFile"/>.
/// </summary>
public ExifPropertyCollection Properties { get; private set; }
/// <summary>
/// Gets or sets the embedded thumbnail image.
/// </summary>
public ImageFile Thumbnail { get; set; }
/// <summary>
/// Gets or sets the Exif property with the given key.
/// </summary>
/// <param name="key">The Exif tag associated with the Exif property.</param>
public ExifProperty this[ExifTag key] {
get { return Properties[key]; }
set { Properties[key] = value; }
}
/// <summary>
/// Gets the encoding used for text metadata when the source encoding is unknown.
/// </summary>
public Encoding Encoding { get; protected set; }
#endregion
#region Instance Methods
/// <summary>
/// Converts the <see cref="ImageFile"/> to a <see cref="System.Drawing.Image"/>.
/// </summary>
/// <returns>Returns a <see cref="System.Drawing.Image"/> containing image data.</returns>
public abstract Image ToImage ();
/// <summary>
/// Saves the <see cref="ImageFile"/> to the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
public virtual void Save (string filename)
{
using (FileStream stream = new FileStream (filename, FileMode.Create, FileAccess.Write, FileShare.None)) {
Save (stream);
}
}
/// <summary>
/// Saves the <see cref="ImageFile"/> to the specified stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> to save image data to.</param>
public abstract void Save (Stream stream);
#endregion
#region Static Methods
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromFile (string filename)
{
return FromFile(filename, Encoding.Default);
}
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified file.
/// </summary>
/// <param name="filename">A string that contains the name of the file.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromFile(string filename, Encoding encoding)
{
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return FromStream(stream, encoding);
}
}
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromStream(Stream stream)
{
return FromStream(stream, Encoding.Default);
}
/// <summary>
/// Creates an <see cref="ImageFile"/> from the specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
public static ImageFile FromStream(Stream stream, Encoding encoding)
{
stream.Seek (0, SeekOrigin.Begin);
byte[] header = new byte[8];
stream.Seek (0, SeekOrigin.Begin);
if (stream.Read (header, 0, header.Length) != header.Length)
throw new NotValidImageFileException ();
// JPEG
if (header[0] == 0xFF && header[1] == 0xD8)
return new JPEGFile (stream, encoding);
// TIFF
string tiffHeader = Encoding.ASCII.GetString (header, 0, 4);
if (tiffHeader == "MM\x00\x2a" || tiffHeader == "II\x2a\x00")
return new TIFFFile (stream, encoding);
throw new NotValidImageFileException ();
}
#endregion
}
}
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents an image file directory.
/// </summary>
internal class ImageFileDirectory
{
/// <summary>
/// The fields contained in this IFD.
/// </summary>
public List<ImageFileDirectoryEntry> Fields { get; private set; }
/// <summary>
/// Offset to the next IFD.
/// </summary>
public uint NextIFDOffset { get; private set; }
/// <summary>
/// Compressed image data.
/// </summary>
public List<TIFFStrip> Strips { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ImageFileDirectory"/> class.
/// </summary>
public ImageFileDirectory()
{
Fields = new List<ImageFileDirectoryEntry>();
Strips = new List<TIFFStrip>();
}
/// <summary>
/// Returns a <see cref="ImageFileDirectory"/> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data"/>.</param>
/// <param name="byteOrder">The byte order of <paramref name="data"/>.</param>
/// <returns>A <see cref="ImageFileDirectory"/> initialized from the given byte data.</returns>
public static ImageFileDirectory FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder)
{
ImageFileDirectory ifd = new ImageFileDirectory();
BitConverterEx conv = new BitConverterEx(byteOrder, BitConverterEx.SystemByteOrder);
List<uint> stripOffsets = new List<uint>();
List<uint> stripLengths = new List<uint>();
// Count
ushort fieldcount = conv.ToUInt16(data, offset);
// Read fields
for (uint i = 0; i < fieldcount; i++)
{
uint fieldoffset = offset + 2 + 12 * i;
ImageFileDirectoryEntry field = ImageFileDirectoryEntry.FromBytes(data, fieldoffset, byteOrder);
ifd.Fields.Add(field);
// Read strip offsets
if (field.Tag == 273)
{
int baselen = field.Data.Length / (int)field.Count;
for (uint j = 0; j < field.Count; j++)
{
byte[] val = new byte[baselen];
Array.Copy(field.Data, j * baselen, val, 0, baselen);
uint stripOffset = (field.Type == 3 ? (uint)BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0));
stripOffsets.Add(stripOffset);
}
}
// Read strip lengths
if (field.Tag == 279)
{
int baselen = field.Data.Length / (int)field.Count;
for (uint j = 0; j < field.Count; j++)
{
byte[] val = new byte[baselen];
Array.Copy(field.Data, j * baselen, val, 0, baselen);
uint stripLength = (field.Type == 3 ? (uint)BitConverter.ToUInt16(val, 0) : BitConverter.ToUInt32(val, 0));
stripLengths.Add(stripLength);
}
}
}
// Save strips
if (stripOffsets.Count != stripLengths.Count)
throw new NotValidTIFFileException();
for (int i = 0; i < stripOffsets.Count; i++)
ifd.Strips.Add(new TIFFStrip(data, stripOffsets[i], stripLengths[i]));
// Offset to next ifd
ifd.NextIFDOffset = conv.ToUInt32(data, offset + 2 + 12 * fieldcount);
return ifd;
}
}
}
@@ -0,0 +1,117 @@
using System;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents an entry in the image file directory.
/// </summary>
internal struct ImageFileDirectoryEntry
{
/// <summary>
/// The tag that identifies the field.
/// </summary>
public ushort Tag;
/// <summary>
/// Field type identifier.
/// </summary>
public ushort Type;
/// <summary>
/// Count of Type.
/// </summary>
public uint Count;
/// <summary>
/// Field data.
/// </summary>
public byte[] Data;
/// <summary>
/// Initializes a new instance of the <see cref="ImageFileDirectoryEntry"/> struct.
/// </summary>
/// <param name="tag">The tag that identifies the field.</param>
/// <param name="type">Field type identifier.</param>
/// <param name="count">Count of Type.</param>
/// <param name="data">Field data.</param>
public ImageFileDirectoryEntry(ushort tag, ushort type, uint count, byte[] data)
{
Tag = tag;
Type = type;
Count = count;
Data = data;
}
/// <summary>
/// Returns a <see cref="ImageFileDirectoryEntry"/> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data"/>.</param>
/// <param name="byteOrder">The byte order of <paramref name="data"/>.</param>
/// <returns>A <see cref="ImageFileDirectoryEntry"/> initialized from the given byte data.</returns>
public static ImageFileDirectoryEntry FromBytes(byte[] data, uint offset, BitConverterEx.ByteOrder byteOrder)
{
// Tag ID
ushort tag = BitConverterEx.ToUInt16(data, offset, byteOrder, BitConverterEx.SystemByteOrder);
// Tag Type
ushort type = BitConverterEx.ToUInt16(data, offset + 2, byteOrder, BitConverterEx.SystemByteOrder);
// Count of Type
uint count = BitConverterEx.ToUInt32(data, offset + 4, byteOrder, BitConverterEx.SystemByteOrder);
// Field value or offset to field data
byte[] value = new byte[4];
Array.Copy(data, offset + 8, value, 0, 4);
// Calculate the bytes we need to read
uint baselength = GetBaseLength(type);
uint totallength = count * baselength;
// If field value does not fit in 4 bytes
// the value field is an offset to the actual
// field value
if (totallength > 4)
{
uint dataoffset = BitConverterEx.ToUInt32(value, 0, byteOrder, BitConverterEx.SystemByteOrder);
value = new byte[totallength];
Array.Copy(data, dataoffset, value, 0, totallength);
}
// Reverse array order if byte orders are different
if (byteOrder != BitConverterEx.SystemByteOrder)
{
for (uint i = 0; i < count; i++)
{
byte[] val = new byte[baselength];
Array.Copy(value, i * baselength, val, 0, baselength);
Array.Reverse(val);
Array.Copy(val, 0, value, i * baselength, baselength);
}
}
return new ImageFileDirectoryEntry(tag, type, count, value);
}
/// <summary>
/// Gets the base byte length for the given type.
/// </summary>
/// <param name="type">Type identifier.</param>
private static uint GetBaseLength(ushort type)
{
if (type == 1 || type == 6) // BYTE and SBYTE
return 1;
else if (type == 2 || type == 7) // ASCII and UNDEFINED
return 1;
else if (type == 3 || type == 8) // SHORT and SSHORT
return 2;
else if (type == 4 || type == 9) // LONG and SLONG
return 4;
else if (type == 5 || type == 10) // RATIONAL (2xLONG) and SRATIONAL (2xSLONG)
return 8;
else if (type == 11) // FLOAT
return 4;
else if (type == 12) // DOUBLE
return 8;
throw new ArgumentException("Unknown type identifier.", "type");
}
}
}
@@ -0,0 +1,21 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the format of the <see cref="ImageFile"/>.
/// </summary>
internal enum ImageFileFormat
{
/// <summary>
/// The file is not recognized.
/// </summary>
Unknown,
/// <summary>
/// The file is a JPEG/Exif or JPEG/JFIF file.
/// </summary>
JPEG,
/// <summary>
/// The file is a TIFF File.
/// </summary>
TIFF,
}
}
+40
View File
@@ -0,0 +1,40 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the units for the X and Y densities
/// for a JFIF file.
/// </summary>
internal enum JFIFDensityUnit : byte
{
/// <summary>
/// No units, XDensity and YDensity specify the pixel aspect ratio.
/// </summary>
None = 0,
/// <summary>
/// XDensity and YDensity are dots per inch.
/// </summary>
DotsPerInch = 1,
/// <summary>
/// XDensity and YDensity are dots per cm.
/// </summary>
DotsPerCm = 2,
}
/// <summary>
/// Represents the JFIF extension.
/// </summary>
internal enum JFIFExtension : byte
{
/// <summary>
/// Thumbnail coded using JPEG.
/// </summary>
ThumbnailJPEG = 0x10,
/// <summary>
/// Thumbnail stored using a 256-Color RGB palette.
/// </summary>
ThumbnailPaletteRGB = 0x11,
/// <summary>
/// Thumbnail stored using 3 bytes/pixel (24-bit) RGB values.
/// </summary>
Thumbnail24BitRGB = 0x13,
}
}
@@ -0,0 +1,67 @@
using System;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the JFIF version as a 16 bit unsigned integer. (EXIF Specification: SHORT)
/// </summary>
internal class JFIFVersion : ExifUShort
{
/// <summary>
/// Gets the major version.
/// </summary>
public byte Major { get { return (byte)(mValue >> 8); } }
/// <summary>
/// Gets the minor version.
/// </summary>
public byte Minor { get { return (byte)(mValue - (mValue >> 8) * 256); } }
public JFIFVersion(ExifTag tag, ushort value)
: base(tag, value)
{
;
}
public override string ToString()
{
return string.Format("{0}.{1:00}", Major, Minor);
}
}
/// <summary>
/// Represents a JFIF thumbnail. (EXIF Specification: BYTE)
/// </summary>
internal class JFIFThumbnailProperty : ExifProperty
{
protected JFIFThumbnail mValue;
protected override object _Value { get { return Value; } set { Value = (JFIFThumbnail)value; } }
public new JFIFThumbnail Value { get { return mValue; } set { mValue = value; } }
public override string ToString() { return mValue.Format.ToString(); }
public JFIFThumbnailProperty(ExifTag tag, JFIFThumbnail value)
: base(tag)
{
mValue = value;
}
public override ExifInterOperability Interoperability
{
get
{
if (mValue.Format == JFIFThumbnail.ImageFormat.BMP24Bit)
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.PixelData.Length, mValue.PixelData);
else if (mValue.Format == JFIFThumbnail.ImageFormat.BMPPalette)
{
byte[] data = new byte[mValue.Palette.Length + mValue.PixelData.Length];
Array.Copy(mValue.Palette, data, mValue.Palette.Length);
Array.Copy(mValue.PixelData, 0, data, mValue.Palette.Length, mValue.PixelData.Length);
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)data.Length, data);
}
else if (mValue.Format == JFIFThumbnail.ImageFormat.JPEG)
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), 1, (uint)mValue.PixelData.Length, mValue.PixelData);
else
throw new InvalidOperationException("Unknown thumbnail type.");
}
}
}
}
@@ -0,0 +1,55 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents a JFIF thumbnail.
/// </summary>
internal class JFIFThumbnail
{
#region Properties
/// <summary>
/// Gets the 256 color RGB palette.
/// </summary>
public byte[] Palette { get; private set; }
/// <summary>
/// Gets raw image data.
/// </summary>
public byte[] PixelData { get; private set; }
/// <summary>
/// Gets the image format.
/// </summary>
public ImageFormat Format { get; private set; }
#endregion
#region Public Enums
public enum ImageFormat
{
JPEG,
BMPPalette,
BMP24Bit,
}
#endregion
#region Constructors
protected JFIFThumbnail()
{
Palette = new byte[0];
PixelData = new byte[0];
}
public JFIFThumbnail(ImageFormat format, byte[] data)
: this()
{
Format = format;
PixelData = data;
}
public JFIFThumbnail(byte[] palette, byte[] data)
: this()
{
Format = ImageFormat.BMPPalette;
Palette = palette;
PixelData = data;
}
#endregion
}
}
@@ -0,0 +1,117 @@
using System;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// The exception that is thrown when the format of the image file
/// could not be understood.
/// </summary>
internal class UnknownImageFormatException : Exception
{
public UnknownImageFormatException()
: base("Unkown image format.")
{
;
}
public UnknownImageFormatException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the image file
/// could not be understood.
/// </summary>
internal class NotValidImageFileException : Exception
{
public NotValidImageFileException()
: base("Not a valid image file.")
{
;
}
public NotValidImageFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the JPEG file
/// could not be understood.
/// </summary>
internal class NotValidJPEGFileException : Exception
{
public NotValidJPEGFileException()
: base("Not a valid JPEG file.")
{
;
}
public NotValidJPEGFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the TIFF file
/// could not be understood.
/// </summary>
internal class NotValidTIFFileException : Exception
{
public NotValidTIFFileException()
: base("Not a valid TIFF file.")
{
;
}
public NotValidTIFFileException(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the format of the TIFF header
/// could not be understood.
/// </summary>
internal class NotValidTIFFHeader : Exception
{
public NotValidTIFFHeader()
: base("Not a valid TIFF header.")
{
;
}
public NotValidTIFFHeader(string message)
: base(message)
{
;
}
}
/// <summary>
/// The exception that is thrown when the length of a section exceeds 64 kB.
/// </summary>
internal class SectionExceeds64KBException : Exception
{
public SectionExceeds64KBException()
: base("Section length exceeds 64 kB.")
{
;
}
public SectionExceeds64KBException(string message)
: base(message)
{
;
}
}
}
+918
View File
@@ -0,0 +1,918 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the binary view of a JPEG compressed file.
/// </summary>
internal class JPEGFile : ImageFile
{
#region Member Variables
private JPEGSection jfifApp0;
private JPEGSection jfxxApp0;
private JPEGSection exifApp1;
private uint makerNoteOffset;
private long exifIFDFieldOffset, gpsIFDFieldOffset, interopIFDFieldOffset, firstIFDFieldOffset;
private long thumbOffsetLocation, thumbSizeLocation;
private uint thumbOffsetValue, thumbSizeValue;
private bool makerNoteProcessed;
#endregion
#region Properties
/// <summary>
/// Gets or sets the byte-order of the Exif properties.
/// </summary>
public BitConverterEx.ByteOrder ByteOrder { get; set; }
/// <summary>
/// Gets or sets the sections contained in the <see cref="ImageFile"/>.
/// </summary>
public List<JPEGSection> Sections { get; private set; }
/// <summary>
/// Gets or sets non-standard trailing data following the End of Image (EOI) marker.
/// </summary>
public byte[] TrailingData { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="ExifFile"/> class.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
protected internal JPEGFile(Stream stream, Encoding encoding)
{
Format = ImageFileFormat.JPEG;
Sections = new List<JPEGSection>();
TrailingData = new byte[0];
Encoding = encoding;
stream.Seek(0, SeekOrigin.Begin);
// Read the Start of Image (SOI) marker. SOI marker is represented
// with two bytes: 0xFF, 0xD8.
byte[] markerbytes = new byte[2];
if (stream.Read(markerbytes, 0, 2) != 2 || markerbytes[0] != 0xFF || markerbytes[1] != 0xD8)
throw new NotValidJPEGFileException();
stream.Seek(0, SeekOrigin.Begin);
// Search and read sections until we reach the end of file.
while (stream.Position != stream.Length)
{
// Read the next section marker. Section markers are two bytes
// with values 0xFF, 0x?? where ?? must not be 0x00 or 0xFF.
if (stream.Read(markerbytes, 0, 2) != 2 || markerbytes[0] != 0xFF || markerbytes[1] == 0x00 || markerbytes[1] == 0xFF)
throw new NotValidJPEGFileException();
JPEGMarker marker = (JPEGMarker)markerbytes[1];
byte[] header = new byte[0];
// SOI, EOI and RST markers do not contain any header
if (marker != JPEGMarker.SOI && marker != JPEGMarker.EOI && !(marker >= JPEGMarker.RST0 && marker <= JPEGMarker.RST7))
{
// Length of the header including the length bytes.
// This value is a 16-bit unsigned integer
// in big endian byte-order.
byte[] lengthbytes = new byte[2];
if (stream.Read(lengthbytes, 0, 2) != 2)
throw new NotValidJPEGFileException();
long length = (long)BitConverterEx.BigEndian.ToUInt16(lengthbytes, 0);
// Read section header.
header = new byte[length - 2];
int bytestoread = header.Length;
while (bytestoread > 0)
{
int count = Math.Min(bytestoread, 4 * 1024);
int bytesread = stream.Read(header, header.Length - bytestoread, count);
if (bytesread == 0)
throw new NotValidJPEGFileException();
bytestoread -= bytesread;
}
}
// Start of Scan (SOS) sections and RST sections are immediately
// followed by entropy coded data. For that, we need to read until
// the next section marker once we reach a SOS or RST.
byte[] entropydata = new byte[0];
if (marker == JPEGMarker.SOS || (marker >= JPEGMarker.RST0 && marker <= JPEGMarker.RST7))
{
long position = stream.Position;
// Search for the next section marker
while (true)
{
// Search for an 0xFF indicating start of a marker
int nextbyte = 0;
do
{
nextbyte = stream.ReadByte();
if (nextbyte == -1)
throw new NotValidJPEGFileException();
} while ((byte)nextbyte != 0xFF);
// Skip filler bytes (0xFF)
do
{
nextbyte = stream.ReadByte();
if (nextbyte == -1)
throw new NotValidJPEGFileException();
} while ((byte)nextbyte == 0xFF);
// Looks like a section marker. The next byte must not be 0x00.
if ((byte)nextbyte != 0x00)
{
// We reached a section marker. Calculate the
// length of the entropy coded data.
stream.Seek(-2, SeekOrigin.Current);
long edlength = stream.Position - position;
stream.Seek(-edlength, SeekOrigin.Current);
// Read entropy coded data
entropydata = new byte[edlength];
int bytestoread = entropydata.Length;
while (bytestoread > 0)
{
int count = Math.Min(bytestoread, 4 * 1024);
int bytesread = stream.Read(entropydata, entropydata.Length - bytestoread, count);
if (bytesread == 0)
throw new NotValidJPEGFileException();
bytestoread -= bytesread;
}
break;
}
}
}
// Store section.
JPEGSection section = new JPEGSection(marker, header, entropydata);
Sections.Add(section);
// Some propriety formats store data past the EOI marker
if (marker == JPEGMarker.EOI)
{
int bytestoread = (int)(stream.Length - stream.Position);
TrailingData = new byte[bytestoread];
while (bytestoread > 0)
{
int count = (int)Math.Min(bytestoread, 4 * 1024);
int bytesread = stream.Read(TrailingData, TrailingData.Length - bytestoread, count);
if (bytesread == 0)
throw new NotValidJPEGFileException();
bytestoread -= bytesread;
}
}
}
// Read metadata sections
ReadJFIFAPP0();
ReadJFXXAPP0();
ReadExifAPP1();
// Process the maker note
makerNoteProcessed = false;
}
#endregion
#region Instance Methods
/// <summary>
/// Saves the JPEG/Exif image to the given stream.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
/// <param name="preserveMakerNote">Determines whether the maker note offset of
/// the original file will be preserved.</param>
public void Save(Stream stream, bool preserveMakerNote)
{
WriteJFIFApp0();
WriteJFXXApp0();
WriteExifApp1(preserveMakerNote);
// Write sections
foreach (JPEGSection section in Sections)
{
// Section header (including length bytes and section marker)
// must not exceed 64 kB.
if (section.Header.Length + 2 + 2 > 64 * 1024)
throw new SectionExceeds64KBException();
// APP sections must have a header.
// Otherwise skip the entire section.
if (section.Marker >= JPEGMarker.APP0 && section.Marker <= JPEGMarker.APP15 && section.Header.Length == 0)
continue;
// Write section marker
stream.Write(new byte[] { 0xFF, (byte)section.Marker }, 0, 2);
// SOI, EOI and RST markers do not contain any header
if (section.Marker != JPEGMarker.SOI && section.Marker != JPEGMarker.EOI && !(section.Marker >= JPEGMarker.RST0 && section.Marker <= JPEGMarker.RST7))
{
// Header length including the length field itself
stream.Write(BitConverterEx.BigEndian.GetBytes((ushort)(section.Header.Length + 2)), 0, 2);
// Write section header
if (section.Header.Length != 0)
stream.Write(section.Header, 0, section.Header.Length);
}
// Write entropy coded data
if (section.EntropyData.Length != 0)
stream.Write(section.EntropyData, 0, section.EntropyData.Length);
}
// Write trailing data, if any
if (TrailingData.Length != 0)
stream.Write(TrailingData, 0, TrailingData.Length);
}
/// <summary>
/// Saves the JPEG/Exif image with the given filename.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
/// <param name="preserveMakerNote">Determines whether the maker note offset of
/// the original file will be preserved.</param>
public void Save(string filename, bool preserveMakerNote)
{
using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream, preserveMakerNote);
}
}
/// <summary>
/// Saves the JPEG/Exif image with the given filename.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
public override void Save(string filename)
{
Save(filename, true);
}
/// <summary>
/// Saves the JPEG/Exif image to the given stream.
/// </summary>
/// <param name="filename">The path to the JPEG/Exif file.</param>
public override void Save(Stream stream)
{
Save(stream, true);
}
/// <summary>
/// Returns a System.Drawing.Image created with image data.
/// </summary>
public override Image ToImage()
{
MemoryStream stream = new MemoryStream();
Save(stream);
return Image.FromStream(stream);
}
#endregion
#region Private Helper Methods
/// <summary>
/// Reads the APP0 section containing JFIF metadata.
/// </summary>
private void ReadJFIFAPP0()
{
// Find the APP0 section containing JFIF metadata
jfifApp0 = Sections.Find(a => (a.Marker == JPEGMarker.APP0) &&
a.Header.Length >= 5 &&
(Encoding.ASCII.GetString(a.Header, 0, 5) == "JFIF\0"));
// If there is no APP0 section, return.
if (jfifApp0 == null)
return;
byte[] header = jfifApp0.Header;
BitConverterEx jfifConv = BitConverterEx.BigEndian;
// Version
ushort version = jfifConv.ToUInt16(header, 5);
Properties.Add(new JFIFVersion(ExifTag.JFIFVersion, version));
// Units
byte unit = header[7];
Properties.Add(new ExifEnumProperty<JFIFDensityUnit>(ExifTag.JFIFUnits, (JFIFDensityUnit)unit));
// X and Y densities
ushort xdensity = jfifConv.ToUInt16(header, 8);
Properties.Add(new ExifUShort(ExifTag.XDensity, xdensity));
ushort ydensity = jfifConv.ToUInt16(header, 10);
Properties.Add(new ExifUShort(ExifTag.YDensity, ydensity));
// Thumbnails pixel count
byte xthumbnail = header[12];
Properties.Add(new ExifByte(ExifTag.JFIFXThumbnail, xthumbnail));
byte ythumbnail = header[13];
Properties.Add(new ExifByte(ExifTag.JFIFYThumbnail, ythumbnail));
// Read JFIF thumbnail
int n = xthumbnail * ythumbnail;
byte[] jfifThumbnail = new byte[n];
Array.Copy(header, 14, jfifThumbnail, 0, n);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFIFThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.JPEG, jfifThumbnail)));
}
/// <summary>
/// Replaces the contents of the APP0 section with the JFIF properties.
/// </summary>
private bool WriteJFIFApp0()
{
// Which IFD sections do we have?
List<ExifProperty> ifdjfef = new List<ExifProperty>();
foreach (ExifProperty prop in Properties)
{
if (prop.IFD == IFD.JFIF)
ifdjfef.Add(prop);
}
if (ifdjfef.Count == 0)
{
// Nothing to write
return false;
}
// Create a memory stream to write the APP0 section to
MemoryStream ms = new MemoryStream();
// JFIF identifer
ms.Write(Encoding.ASCII.GetBytes("JFIF\0"), 0, 5);
// Write tags
foreach (ExifProperty prop in ifdjfef)
{
ExifInterOperability interop = prop.Interoperability;
byte[] data = interop.Data;
if (BitConverterEx.SystemByteOrder != BitConverterEx.ByteOrder.BigEndian && interop.TypeID == 3)
Array.Reverse(data);
ms.Write(data, 0, data.Length);
}
ms.Close();
// Return APP0 header
jfifApp0.Header = ms.ToArray();
return true;
}
/// <summary>
/// Reads the APP0 section containing JFIF extension metadata.
/// </summary>
private void ReadJFXXAPP0()
{
// Find the APP0 section containing JFIF metadata
jfxxApp0 = Sections.Find(a => (a.Marker == JPEGMarker.APP0) &&
a.Header.Length >= 5 &&
(Encoding.ASCII.GetString(a.Header, 0, 5) == "JFXX\0"));
// If there is no APP0 section, return.
if (jfxxApp0 == null)
return;
byte[] header = jfxxApp0.Header;
// Version
JFIFExtension version = (JFIFExtension)header[5];
Properties.Add(new ExifEnumProperty<JFIFExtension>(ExifTag.JFXXExtensionCode, version));
// Read thumbnail
if (version == JFIFExtension.ThumbnailJPEG)
{
byte[] data = new byte[header.Length - 6];
Array.Copy(header, 6, data, 0, data.Length);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFXXThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.JPEG, data)));
}
else if (version == JFIFExtension.Thumbnail24BitRGB)
{
// Thumbnails pixel count
byte xthumbnail = header[6];
Properties.Add(new ExifByte(ExifTag.JFXXXThumbnail, xthumbnail));
byte ythumbnail = header[7];
Properties.Add(new ExifByte(ExifTag.JFXXYThumbnail, ythumbnail));
byte[] data = new byte[3 * xthumbnail * ythumbnail];
Array.Copy(header, 8, data, 0, data.Length);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFXXThumbnail, new JFIFThumbnail(JFIFThumbnail.ImageFormat.BMP24Bit, data)));
}
else if (version == JFIFExtension.ThumbnailPaletteRGB)
{
// Thumbnails pixel count
byte xthumbnail = header[6];
Properties.Add(new ExifByte(ExifTag.JFXXXThumbnail, xthumbnail));
byte ythumbnail = header[7];
Properties.Add(new ExifByte(ExifTag.JFXXYThumbnail, ythumbnail));
byte[] palette = new byte[768];
Array.Copy(header, 8, palette, 0, palette.Length);
byte[] data = new byte[xthumbnail * ythumbnail];
Array.Copy(header, 8 + 768, data, 0, data.Length);
Properties.Add(new JFIFThumbnailProperty(ExifTag.JFXXThumbnail, new JFIFThumbnail(palette, data)));
}
}
/// <summary>
/// Replaces the contents of the APP0 section with the JFIF extension properties.
/// </summary>
private bool WriteJFXXApp0()
{
// Which IFD sections do we have?
List<ExifProperty> ifdjfef = new List<ExifProperty>();
foreach (ExifProperty prop in Properties)
{
if (prop.IFD == IFD.JFXX)
ifdjfef.Add(prop);
}
if (ifdjfef.Count == 0)
{
// Nothing to write
return false;
}
// Create a memory stream to write the APP0 section to
MemoryStream ms = new MemoryStream();
// JFIF identifer
ms.Write(Encoding.ASCII.GetBytes("JFXX\0"), 0, 5);
// Write tags
foreach (ExifProperty prop in ifdjfef)
{
ExifInterOperability interop = prop.Interoperability;
byte[] data = interop.Data;
if (BitConverterEx.SystemByteOrder != BitConverterEx.ByteOrder.BigEndian && interop.TypeID == 3)
Array.Reverse(data);
ms.Write(data, 0, data.Length);
}
ms.Close();
// Return APP0 header
jfxxApp0.Header = ms.ToArray();
return true;
}
/// <summary>
/// Reads the APP1 section containing Exif metadata.
/// </summary>
private void ReadExifAPP1()
{
// Find the APP1 section containing Exif metadata
exifApp1 = Sections.Find(a => (a.Marker == JPEGMarker.APP1) &&
a.Header.Length >= 6 &&
(Encoding.ASCII.GetString(a.Header, 0, 6) == "Exif\0\0"));
// If there is no APP1 section, add a new one after the last APP0 section (if any).
if (exifApp1 == null)
{
int insertionIndex = Sections.FindLastIndex(a => a.Marker == JPEGMarker.APP0);
if (insertionIndex == -1) insertionIndex = 0;
insertionIndex++;
exifApp1 = new JPEGSection(JPEGMarker.APP1);
Sections.Insert(insertionIndex, exifApp1);
if (BitConverterEx.SystemByteOrder == BitConverterEx.ByteOrder.LittleEndian)
ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else
ByteOrder = BitConverterEx.ByteOrder.BigEndian;
return;
}
byte[] header = exifApp1.Header;
SortedList<int, IFD> ifdqueue = new SortedList<int, IFD>();
makerNoteOffset = 0;
// TIFF header
int tiffoffset = 6;
if (header[tiffoffset] == 0x49 && header[tiffoffset + 1] == 0x49)
ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (header[tiffoffset] == 0x4D && header[tiffoffset + 1] == 0x4D)
ByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidExifFileException();
// TIFF header may have a different byte order
BitConverterEx.ByteOrder tiffByteOrder = ByteOrder;
if (BitConverterEx.LittleEndian.ToUInt16(header, tiffoffset + 2) == 42)
tiffByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (BitConverterEx.BigEndian.ToUInt16(header, tiffoffset + 2) == 42)
tiffByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidExifFileException();
// Offset to 0th IFD
int ifd0offset = (int)BitConverterEx.ToUInt32(header, tiffoffset + 4, tiffByteOrder, BitConverterEx.SystemByteOrder);
ifdqueue.Add(ifd0offset, IFD.Zeroth);
BitConverterEx conv = new BitConverterEx(ByteOrder, BitConverterEx.SystemByteOrder);
int thumboffset = -1;
int thumblength = 0;
int thumbtype = -1;
// Read IFDs
while (ifdqueue.Count != 0)
{
int ifdoffset = tiffoffset + ifdqueue.Keys[0];
IFD currentifd = ifdqueue.Values[0];
ifdqueue.RemoveAt(0);
// Field count
ushort fieldcount = conv.ToUInt16(header, ifdoffset);
for (short i = 0; i < fieldcount; i++)
{
// Read field info
int fieldoffset = ifdoffset + 2 + 12 * i;
ushort tag = conv.ToUInt16(header, fieldoffset);
ushort type = conv.ToUInt16(header, fieldoffset + 2);
uint count = conv.ToUInt32(header, fieldoffset + 4);
byte[] value = new byte[4];
Array.Copy(header, fieldoffset + 8, value, 0, 4);
// Fields containing offsets to other IFDs
if (currentifd == IFD.Zeroth && tag == 0x8769)
{
int exififdpointer = (int)conv.ToUInt32(value, 0);
ifdqueue.Add(exififdpointer, IFD.EXIF);
}
else if (currentifd == IFD.Zeroth && tag == 0x8825)
{
int gpsifdpointer = (int)conv.ToUInt32(value, 0);
ifdqueue.Add(gpsifdpointer, IFD.GPS);
}
else if (currentifd == IFD.EXIF && tag == 0xa005)
{
int interopifdpointer = (int)conv.ToUInt32(value, 0);
ifdqueue.Add(interopifdpointer, IFD.Interop);
}
// Save the offset to maker note data
if (currentifd == IFD.EXIF && tag == 37500)
makerNoteOffset = conv.ToUInt32(value, 0);
// Calculate the bytes we need to read
uint baselength = 0;
if (type == 1 || type == 2 || type == 7)
baselength = 1;
else if (type == 3)
baselength = 2;
else if (type == 4 || type == 9)
baselength = 4;
else if (type == 5 || type == 10)
baselength = 8;
uint totallength = count * baselength;
// If field value does not fit in 4 bytes
// the value field is an offset to the actual
// field value
int fieldposition = 0;
if (totallength > 4)
{
fieldposition = tiffoffset + (int)conv.ToUInt32(value, 0);
value = new byte[totallength];
Array.Copy(header, fieldposition, value, 0, totallength);
}
// Compressed thumbnail data
if (currentifd == IFD.First && tag == 0x201)
{
thumbtype = 0;
thumboffset = (int)conv.ToUInt32(value, 0);
}
else if (currentifd == IFD.First && tag == 0x202)
thumblength = (int)conv.ToUInt32(value, 0);
// Uncompressed thumbnail data
if (currentifd == IFD.First && tag == 0x111)
{
thumbtype = 1;
// Offset to first strip
if (type == 3)
thumboffset = (int)conv.ToUInt16(value, 0);
else
thumboffset = (int)conv.ToUInt32(value, 0);
}
else if (currentifd == IFD.First && tag == 0x117)
{
thumblength = 0;
for (int j = 0; j < count; j++)
{
if (type == 3)
thumblength += (int)conv.ToUInt16(value, 0);
else
thumblength += (int)conv.ToUInt32(value, 0);
}
}
// Create the exif property from the interop data
ExifProperty prop = ExifPropertyFactory.Get(tag, type, count, value, ByteOrder, currentifd, Encoding);
Properties.Add(prop);
}
// 1st IFD pointer
int firstifdpointer = (int)conv.ToUInt32(header, ifdoffset + 2 + 12 * fieldcount);
if (firstifdpointer != 0)
ifdqueue.Add(firstifdpointer, IFD.First);
// Read thumbnail
if (thumboffset != -1 && thumblength != 0 && Thumbnail == null)
{
if (thumbtype == 0)
{
using (MemoryStream ts = new MemoryStream(header, tiffoffset + thumboffset, thumblength))
{
Thumbnail = ImageFile.FromStream(ts);
}
}
}
}
}
/// <summary>
/// Replaces the contents of the APP1 section with the Exif properties.
/// </summary>
private bool WriteExifApp1(bool preserveMakerNote)
{
// Zero out IFD field offsets. We will fill those as we write the IFD sections
exifIFDFieldOffset = 0;
gpsIFDFieldOffset = 0;
interopIFDFieldOffset = 0;
firstIFDFieldOffset = 0;
// We also do not know the location of the embedded thumbnail yet
thumbOffsetLocation = 0;
thumbOffsetValue = 0;
thumbSizeLocation = 0;
thumbSizeValue = 0;
// Write thumbnail tags if they are missing, remove otherwise
if (Thumbnail == null)
{
Properties.Remove(ExifTag.ThumbnailJPEGInterchangeFormat);
Properties.Remove(ExifTag.ThumbnailJPEGInterchangeFormatLength);
}
else
{
if (!Properties.ContainsKey(ExifTag.ThumbnailJPEGInterchangeFormat))
Properties.Add(new ExifUInt(ExifTag.ThumbnailJPEGInterchangeFormat, 0));
if (!Properties.ContainsKey(ExifTag.ThumbnailJPEGInterchangeFormatLength))
Properties.Add(new ExifUInt(ExifTag.ThumbnailJPEGInterchangeFormatLength, 0));
}
// Which IFD sections do we have?
Dictionary<ExifTag, ExifProperty> ifdzeroth = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdexif = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdgps = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdinterop = new Dictionary<ExifTag, ExifProperty>();
Dictionary<ExifTag, ExifProperty> ifdfirst = new Dictionary<ExifTag, ExifProperty>();
foreach (ExifProperty prop in Properties)
{
switch (prop.IFD)
{
case IFD.Zeroth:
ifdzeroth.Add(prop.Tag, prop);
break;
case IFD.EXIF:
ifdexif.Add(prop.Tag, prop);
break;
case IFD.GPS:
ifdgps.Add(prop.Tag, prop);
break;
case IFD.Interop:
ifdinterop.Add(prop.Tag, prop);
break;
case IFD.First:
ifdfirst.Add(prop.Tag, prop);
break;
}
}
// Add IFD pointers if they are missing
// We will write the pointer values later on
if (ifdexif.Count != 0 && !ifdzeroth.ContainsKey(ExifTag.EXIFIFDPointer))
ifdzeroth.Add(ExifTag.EXIFIFDPointer, new ExifUInt(ExifTag.EXIFIFDPointer, 0));
if (ifdgps.Count != 0 && !ifdzeroth.ContainsKey(ExifTag.GPSIFDPointer))
ifdzeroth.Add(ExifTag.GPSIFDPointer, new ExifUInt(ExifTag.GPSIFDPointer, 0));
if (ifdinterop.Count != 0 && !ifdexif.ContainsKey(ExifTag.InteroperabilityIFDPointer))
ifdexif.Add(ExifTag.InteroperabilityIFDPointer, new ExifUInt(ExifTag.InteroperabilityIFDPointer, 0));
// Remove IFD pointers if IFD sections are missing
if (ifdexif.Count == 0 && ifdzeroth.ContainsKey(ExifTag.EXIFIFDPointer))
ifdzeroth.Remove(ExifTag.EXIFIFDPointer);
if (ifdgps.Count == 0 && ifdzeroth.ContainsKey(ExifTag.GPSIFDPointer))
ifdzeroth.Remove(ExifTag.GPSIFDPointer);
if (ifdinterop.Count == 0 && ifdexif.ContainsKey(ExifTag.InteroperabilityIFDPointer))
ifdexif.Remove(ExifTag.InteroperabilityIFDPointer);
if (ifdzeroth.Count == 0 && ifdgps.Count == 0 && ifdinterop.Count == 0 && ifdfirst.Count == 0 && Thumbnail == null)
{
// Nothing to write
return false;
}
// We will need these bitconverter to write byte-ordered data
BitConverterEx bceExif = new BitConverterEx(BitConverterEx.SystemByteOrder, ByteOrder);
// Create a memory stream to write the APP1 section to
MemoryStream ms = new MemoryStream();
// Exif identifer
ms.Write(Encoding.ASCII.GetBytes("Exif\0\0"), 0, 6);
// TIFF header
// Byte order
long tiffoffset = ms.Position;
ms.Write((ByteOrder == BitConverterEx.ByteOrder.LittleEndian ? new byte[] { 0x49, 0x49 } : new byte[] { 0x4D, 0x4D }), 0, 2);
// TIFF ID
ms.Write(bceExif.GetBytes((ushort)42), 0, 2);
// Offset to 0th IFD
ms.Write(bceExif.GetBytes((uint)8), 0, 4);
// Write IFDs
WriteIFD(ms, ifdzeroth, IFD.Zeroth, tiffoffset, preserveMakerNote);
uint exififdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdexif, IFD.EXIF, tiffoffset, preserveMakerNote);
uint gpsifdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdgps, IFD.GPS, tiffoffset, preserveMakerNote);
uint interopifdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdinterop, IFD.Interop, tiffoffset, preserveMakerNote);
uint firstifdrelativeoffset = (uint)(ms.Position - tiffoffset);
WriteIFD(ms, ifdfirst, IFD.First, tiffoffset, preserveMakerNote);
// Now that we now the location of IFDs we can go back and write IFD offsets
if (exifIFDFieldOffset != 0)
{
ms.Seek(exifIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(exififdrelativeoffset), 0, 4);
}
if (gpsIFDFieldOffset != 0)
{
ms.Seek(gpsIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(gpsifdrelativeoffset), 0, 4);
}
if (interopIFDFieldOffset != 0)
{
ms.Seek(interopIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(interopifdrelativeoffset), 0, 4);
}
if (firstIFDFieldOffset != 0)
{
ms.Seek(firstIFDFieldOffset, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(firstifdrelativeoffset), 0, 4);
}
// We can write thumbnail location now
if (thumbOffsetLocation != 0)
{
ms.Seek(thumbOffsetLocation, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(thumbOffsetValue), 0, 4);
}
if (thumbSizeLocation != 0)
{
ms.Seek(thumbSizeLocation, SeekOrigin.Begin);
ms.Write(bceExif.GetBytes(thumbSizeValue), 0, 4);
}
ms.Close();
// Return APP1 header
exifApp1.Header = ms.ToArray();
return true;
}
private void WriteIFD(MemoryStream stream, Dictionary<ExifTag, ExifProperty> ifd, IFD ifdtype, long tiffoffset, bool preserveMakerNote)
{
BitConverterEx conv = new BitConverterEx(BitConverterEx.SystemByteOrder, ByteOrder);
// Create a queue of fields to write
Queue<ExifProperty> fieldqueue = new Queue<ExifProperty>();
foreach (ExifProperty prop in ifd.Values)
if (prop.Tag != ExifTag.MakerNote)
fieldqueue.Enqueue(prop);
// Push the maker note data to the end
if (ifd.ContainsKey(ExifTag.MakerNote))
fieldqueue.Enqueue(ifd[ExifTag.MakerNote]);
// Offset to start of field data from start of TIFF header
uint dataoffset = (uint)(2 + ifd.Count * 12 + 4 + stream.Position - tiffoffset);
uint currentdataoffset = dataoffset;
long absolutedataoffset = stream.Position + (2 + ifd.Count * 12 + 4);
bool makernotewritten = false;
// Field count
stream.Write(conv.GetBytes((ushort)ifd.Count), 0, 2);
// Fields
while (fieldqueue.Count != 0)
{
ExifProperty field = fieldqueue.Dequeue();
ExifInterOperability interop = field.Interoperability;
uint fillerbytecount = 0;
// Try to preserve the makernote data offset
if (!makernotewritten &&
!makerNoteProcessed &&
makerNoteOffset != 0 &&
ifdtype == IFD.EXIF &&
field.Tag != ExifTag.MakerNote &&
interop.Data.Length > 4 &&
currentdataoffset + interop.Data.Length > makerNoteOffset &&
ifd.ContainsKey(ExifTag.MakerNote))
{
// Delay writing this field until we write makernote data
fieldqueue.Enqueue(field);
continue;
}
else if (field.Tag == ExifTag.MakerNote)
{
makernotewritten = true;
// We may need to write filler bytes to preserve maker note offset
if (preserveMakerNote && !makerNoteProcessed && (makerNoteOffset > currentdataoffset))
fillerbytecount = makerNoteOffset - currentdataoffset;
else
fillerbytecount = 0;
}
// Tag
stream.Write(conv.GetBytes(interop.TagID), 0, 2);
// Type
stream.Write(conv.GetBytes(interop.TypeID), 0, 2);
// Count
stream.Write(conv.GetBytes(interop.Count), 0, 4);
// Field data
byte[] data = interop.Data;
if (ByteOrder != BitConverterEx.SystemByteOrder &&
(interop.TypeID == 3 || interop.TypeID == 4 || interop.TypeID == 9 ||
interop.TypeID == 5 || interop.TypeID == 10))
{
int vlen = 4;
if (interop.TypeID == 3) vlen = 2;
int n = data.Length / vlen;
for (int i = 0; i < n; i++)
Array.Reverse(data, i * vlen, vlen);
}
// Fields containing offsets to other IFDs
// Just store their offets, we will write the values later on when we know the lengths of IFDs
if (ifdtype == IFD.Zeroth && interop.TagID == 0x8769)
exifIFDFieldOffset = stream.Position;
else if (ifdtype == IFD.Zeroth && interop.TagID == 0x8825)
gpsIFDFieldOffset = stream.Position;
else if (ifdtype == IFD.EXIF && interop.TagID == 0xa005)
interopIFDFieldOffset = stream.Position;
else if (ifdtype == IFD.First && interop.TagID == 0x201)
thumbOffsetLocation = stream.Position;
else if (ifdtype == IFD.First && interop.TagID == 0x202)
thumbSizeLocation = stream.Position;
// Write 4 byte field value or field data
if (data.Length <= 4)
{
stream.Write(data, 0, data.Length);
for (int i = data.Length; i < 4; i++)
stream.WriteByte(0);
}
else
{
// Pointer to data area relative to TIFF header
stream.Write(conv.GetBytes(currentdataoffset + fillerbytecount), 0, 4);
// Actual data
long currentoffset = stream.Position;
stream.Seek(absolutedataoffset, SeekOrigin.Begin);
// Write filler bytes
for (int i = 0; i < fillerbytecount; i++)
stream.WriteByte(0xFF);
stream.Write(data, 0, data.Length);
stream.Seek(currentoffset, SeekOrigin.Begin);
// Increment pointers
currentdataoffset += fillerbytecount + (uint)data.Length;
absolutedataoffset += fillerbytecount + data.Length;
}
}
// Offset to 1st IFD
// We will write zeros for now. This will be filled after we write all IFDs
if (ifdtype == IFD.Zeroth)
firstIFDFieldOffset = stream.Position;
stream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4);
// Seek to end of IFD
stream.Seek(absolutedataoffset, SeekOrigin.Begin);
// Write thumbnail data
if (ifdtype == IFD.First)
{
if (Thumbnail != null)
{
MemoryStream ts = new MemoryStream();
Thumbnail.Save(ts);
ts.Close();
byte[] thumb = ts.ToArray();
thumbOffsetValue = (uint)(stream.Position - tiffoffset);
thumbSizeValue = (uint)thumb.Length;
stream.Write(thumb, 0, thumb.Length);
ts.Dispose();
}
else
{
thumbOffsetValue = 0;
thumbSizeValue = 0;
}
}
}
#endregion
}
}
+85
View File
@@ -0,0 +1,85 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents a JPEG marker byte.
/// </summary>
internal enum JPEGMarker : byte
{
// Start Of Frame markers, non-differential, Huffman coding
SOF0 = 0xc0,
SOF1 = 0xc1,
SOF2 = 0xc2,
SOF3 = 0xc3,
// Start Of Frame markers, differential, Huffman coding
SOF5 = 0xc5,
SOF6 = 0xc6,
SOF7 = 0xc7,
// Start Of Frame markers, non-differential, arithmetic coding
JPG = 0xc8,
SOF9 = 0xc9,
SOF10 = 0xca,
SOF11 = 0xcb,
// Start Of Frame markers, differential, arithmetic coding
SOF13 = 0xcd,
SOF14 = 0xce,
SOF15 = 0xcf,
// Huffman table specification
DHT = 0xc4,
// Arithmetic coding conditioning specification
DAC = 0xcc,
// Restart interval termination
RST0 = 0xd0,
RST1 = 0xd1,
RST2 = 0xd2,
RST3 = 0xd3,
RST4 = 0xd4,
RST5 = 0xd5,
RST6 = 0xd6,
RST7 = 0xd7,
// Other markers
SOI = 0xd8,
EOI = 0xd9,
SOS = 0xda,
DQT = 0xdb,
DNL = 0xdc,
DRI = 0xdd,
DHP = 0xde,
EXP = 0xdf,
// application segments
APP0 = 0xe0,
APP1 = 0xe1,
APP2 = 0xe2,
APP3 = 0xe3,
APP4 = 0xe4,
APP5 = 0xe5,
APP6 = 0xe6,
APP7 = 0xe7,
APP8 = 0xe8,
APP9 = 0xe9,
APP10 = 0xea,
APP11 = 0xeb,
APP12 = 0xec,
APP13 = 0xed,
APP14 = 0xee,
APP15 = 0xef,
// JPEG extensions
JPG0 = 0xf0,
JPG1 = 0xf1,
JPG2 = 0xf2,
JPG3 = 0xf3,
JPG4 = 0xf4,
JPG5 = 0xf5,
JPG6 = 0xf6,
JPG7 = 0xf7,
JPG8 = 0xf8,
JPG9 = 0xf9,
JPG10 = 0xfa,
JPG11 = 0xfb,
JP1G2 = 0xfc,
JPG13 = 0xfd,
// Comment
COM = 0xfe,
// Temporary
TEM = 0x01,
}
}
@@ -0,0 +1,63 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the memory view of a JPEG section.
/// A JPEG section is the data between markers of the JPEG file.
/// </summary>
internal class JPEGSection
{
#region Properties
/// <summary>
/// The marker byte representing the section.
/// </summary>
public JPEGMarker Marker { get; private set; }
/// <summary>
/// Section header as a byte array. This is different from the header
/// definition in JPEG specification in that it does not include the
/// two byte section length.
/// </summary>
public byte[] Header { get; set; }
/// <summary>
/// For the SOS and RST markers, this contains the entropy coded data.
/// </summary>
public byte[] EntropyData { get; set; }
#endregion
#region Constructors
/// <summary>
/// Constructs a JPEGSection represented by the marker byte and containing
/// the given data.
/// </summary>
/// <param name="marker">The marker byte representing the section.</param>
/// <param name="data">Section data.</param>
/// <param name="entropydata">Entropy coded data.</param>
public JPEGSection(JPEGMarker marker, byte[] data, byte[] entropydata)
{
Marker = marker;
Header = data;
EntropyData = entropydata;
}
/// <summary>
/// Constructs a JPEGSection represented by the marker byte.
/// </summary>
/// <param name="marker">The marker byte representing the section.</param>
public JPEGSection(JPEGMarker marker)
: this(marker, new byte[0], new byte[0])
{
;
}
#endregion
#region Instance Methods
/// <summary>
/// Returns a string representation of the current section.
/// </summary>
/// <returns>A System.String that represents the current section.</returns>
public override string ToString()
{
return string.Format("{0} => Header: {1} bytes, Entropy Data: {2} bytes", Marker, Header.Length, EntropyData.Length);
}
#endregion
}
}
File diff suppressed because it is too large Load Diff
+177
View File
@@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents the binary view of a TIFF file.
/// </summary>
internal class TIFFFile : ImageFile
{
#region Properties
/// <summary>
/// Gets the TIFF header.
/// </summary>
public TIFFHeader TIFFHeader { get; private set; }
/// <summary>
/// Gets the image file directories.
/// </summary>
public List<ImageFileDirectory> IFDs { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="JPEGFile"/> class from the
/// specified data stream.
/// </summary>
/// <param name="stream">A <see cref="Sytem.IO.Stream"/> that contains image data.</param>
/// <param name="encoding">The encoding to be used for text metadata when the source encoding is unknown.</param>
protected internal TIFFFile(Stream stream, System.Text.Encoding encoding)
{
Format = ImageFileFormat.TIFF;
IFDs = new List<ImageFileDirectory>();
Encoding = encoding;
// Read the entire stream
byte[] data = Utility.GetStreamBytes(stream);
// Read the TIFF header
TIFFHeader = TIFFHeader.FromBytes(data, 0);
uint nextIFDOffset = TIFFHeader.IFDOffset;
if (nextIFDOffset == 0)
throw new NotValidTIFFileException("The first IFD offset is zero.");
// Read IFDs in order
while (nextIFDOffset != 0)
{
ImageFileDirectory ifd = ImageFileDirectory.FromBytes(data, nextIFDOffset, TIFFHeader.ByteOrder);
nextIFDOffset = ifd.NextIFDOffset;
IFDs.Add(ifd);
}
// Process IFDs
// TODO: Add support for multiple frames
foreach (ImageFileDirectoryEntry field in IFDs[0].Fields)
{
Properties.Add(ExifPropertyFactory.Get(field.Tag, field.Type, field.Count, field.Data, BitConverterEx.SystemByteOrder, IFD.Zeroth, Encoding));
}
}
#endregion
#region Instance Methods
/// <summary>
/// Saves the <see cref="ImageFile"/> to the given stream.
/// </summary>
/// <param name="stream">The data stream used to save the image.</param>
public override void Save(Stream stream)
{
BitConverterEx conv = BitConverterEx.SystemEndian;
// Write TIFF header
uint ifdoffset = 8;
// Byte order
stream.Write((BitConverterEx.SystemByteOrder == BitConverterEx.ByteOrder.LittleEndian ? new byte[] { 0x49, 0x49 } : new byte[] { 0x4D, 0x4D }), 0, 2);
// TIFF ID
stream.Write(conv.GetBytes((ushort)42), 0, 2);
// Offset to 0th IFD, will be corrected below
stream.Write(conv.GetBytes(ifdoffset), 0, 4);
// Write IFD sections
for (int i = 0; i < IFDs.Count; i++)
{
ImageFileDirectory ifd = IFDs[i];
// Save the location of IFD offset
long ifdLocation = stream.Position - 4;
// Write strips first
byte[] stripOffsets = new byte[4 * ifd.Strips.Count];
byte[] stripLengths = new byte[4 * ifd.Strips.Count];
uint stripOffset = ifdoffset;
for (int j = 0; j < ifd.Strips.Count; j++)
{
byte[] stripData = ifd.Strips[j].Data;
byte[] oBytes = BitConverter.GetBytes(stripOffset);
byte[] lBytes = BitConverter.GetBytes((uint)stripData.Length);
Array.Copy(oBytes, 0, stripOffsets, 4 * j, 4);
Array.Copy(lBytes, 0, stripLengths, 4 * j, 4);
stream.Write(stripData, 0, stripData.Length);
stripOffset += (uint)stripData.Length;
}
// Remove old strip tags
for (int j = ifd.Fields.Count - 1; j > 0; j--)
{
ushort tag = ifd.Fields[j].Tag;
if (tag == 273 || tag == 279)
ifd.Fields.RemoveAt(j);
}
// Write new strip tags
ifd.Fields.Add(new ImageFileDirectoryEntry(273, 4, (uint)ifd.Strips.Count, stripOffsets));
ifd.Fields.Add(new ImageFileDirectoryEntry(279, 4, (uint)ifd.Strips.Count, stripLengths));
// Write fields after strips
ifdoffset = stripOffset;
// Correct IFD offset
long currentLocation = stream.Position;
stream.Seek(ifdLocation, SeekOrigin.Begin);
stream.Write(conv.GetBytes(ifdoffset), 0, 4);
stream.Seek(currentLocation, SeekOrigin.Begin);
// Offset to field data
uint dataOffset = ifdoffset + 2 + (uint)ifd.Fields.Count * 12 + 4;
// Field count
stream.Write(conv.GetBytes((ushort)ifd.Fields.Count), 0, 2);
// Fields
foreach (ImageFileDirectoryEntry field in ifd.Fields)
{
// Tag
stream.Write(conv.GetBytes(field.Tag), 0, 2);
// Type
stream.Write(conv.GetBytes(field.Type), 0, 2);
// Count
stream.Write(conv.GetBytes(field.Count), 0, 4);
// Field data
byte[] data = field.Data;
if (data.Length <= 4)
{
stream.Write(data, 0, data.Length);
for (int j = data.Length; j < 4; j++)
stream.WriteByte(0);
}
else
{
stream.Write(conv.GetBytes(dataOffset), 0, 4);
long currentOffset = stream.Position;
stream.Seek(dataOffset, SeekOrigin.Begin);
stream.Write(data, 0, data.Length);
dataOffset += (uint)data.Length;
stream.Seek(currentOffset, SeekOrigin.Begin);
}
}
// Offset to next IFD
ifdoffset = dataOffset;
stream.Write(conv.GetBytes(i == IFDs.Count - 1 ? 0 : ifdoffset), 0, 4);
}
}
/// <summary>
/// Converts the <see cref="ImageFile"/> to a <see cref="System.Drawing.Image"/>.
/// </summary>
/// <returns>Returns a <see cref="System.Drawing.Image"/> containing image data.</returns>
public override Image ToImage()
{
MemoryStream stream = new MemoryStream();
Save(stream);
return Image.FromStream(stream);
}
#endregion
}
}
+78
View File
@@ -0,0 +1,78 @@
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents a TIFF Header.
/// </summary>
internal struct TIFFHeader
{
/// <summary>
/// The byte order of the image file.
/// </summary>
public BitConverterEx.ByteOrder ByteOrder;
/// <summary>
/// TIFF ID. This value should always be 42.
/// </summary>
public byte ID;
/// <summary>
/// The offset to the first IFD section from the
/// start of the TIFF header.
/// </summary>
public uint IFDOffset;
/// <summary>
/// The byte order of the TIFF header itself.
/// </summary>
public BitConverterEx.ByteOrder TIFFHeaderByteOrder;
/// <summary>
/// Initializes a new instance of the <see cref="TIFFHeader"/> struct.
/// </summary>
/// <param name="byteOrder">The byte order.</param>
/// <param name="id">The TIFF ID. This value should always be 42.</param>
/// <param name="ifdOffset">The offset to the first IFD section from the
/// start of the TIFF header.</param>
/// <param name="headerByteOrder">The byte order of the TIFF header itself.</param>
public TIFFHeader(BitConverterEx.ByteOrder byteOrder, byte id, uint ifdOffset, BitConverterEx.ByteOrder headerByteOrder)
{
if (id != 42)
throw new NotValidTIFFHeader();
ByteOrder = byteOrder;
ID = id;
IFDOffset = ifdOffset;
TIFFHeaderByteOrder = headerByteOrder;
}
/// <summary>
/// Returns a <see cref="TIFFHeader"/> initialized from the given byte data.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="offset">The offset into <paramref name="data"/>.</param>
/// <returns>A <see cref="TIFFHeader"/> initialized from the given byte data.</returns>
public static TIFFHeader FromBytes(byte[] data, int offset)
{
TIFFHeader header = new TIFFHeader();
// TIFF header
if (data[offset] == 0x49 && data[offset + 1] == 0x49)
header.ByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (data[offset] == 0x4D && data[offset + 1] == 0x4D)
header.ByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidTIFFHeader();
// TIFF header may have a different byte order
if (BitConverterEx.LittleEndian.ToUInt16(data, offset + 2) == 42)
header.TIFFHeaderByteOrder = BitConverterEx.ByteOrder.LittleEndian;
else if (BitConverterEx.BigEndian.ToUInt16(data, offset + 2) == 42)
header.TIFFHeaderByteOrder = BitConverterEx.ByteOrder.BigEndian;
else
throw new NotValidTIFFHeader();
header.ID = 42;
// IFD offset
header.IFDOffset = BitConverterEx.ToUInt32(data, offset + 4, header.TIFFHeaderByteOrder, BitConverterEx.SystemByteOrder);
return header;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
using System;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Represents a strip of compressed image data in a TIFF file.
/// </summary>
internal class TIFFStrip
{
/// <summary>
/// Compressed image data contained in this strip.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="TIFFStrip"/> class.
/// </summary>
/// <param name="data">The byte array to copy strip from.</param>
/// <param name="offset">The offset to the beginning of strip.</param>
/// <param name="length">The length of strip.</param>
public TIFFStrip(byte[] data, uint offset, uint length)
{
Data = new byte[length];
Array.Copy(data, offset, Data, 0, length);
}
}
}
+30
View File
@@ -0,0 +1,30 @@
using System.IO;
namespace Umbraco.Core.Media.Exif
{
/// <summary>
/// Contains utility functions.
/// </summary>
internal class Utility
{
/// <summary>
/// Reads the entire stream and returns its contents as a byte array.
/// </summary>
/// <param name="stream">The <see cref="System.IO.Stream"/> to read.</param>
/// <returns>Contents of the <paramref name="stream"/> as a byte array.</returns>
public static byte[] GetStreamBytes(Stream stream)
{
using (MemoryStream mem = new MemoryStream())
{
stream.Seek(0, SeekOrigin.Begin);
byte[] b = new byte[32768];
int r;
while ((r = stream.Read(b, 0, b.Length)) > 0)
mem.Write(b, 0, r);
return mem.ToArray();
}
}
}
}
+47 -3
View File
@@ -6,10 +6,8 @@ using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Media.Exif;
namespace Umbraco.Core.Media
{
@@ -18,6 +16,52 @@ namespace Umbraco.Core.Media
/// </summary>
internal static class ImageHelper
{
/// <summary>
/// Gets the dimensions of an image based on a stream
/// </summary>
/// <param name="imageStream"></param>
/// <returns></returns>
/// <remarks>
/// First try with EXIF, this is because it is insanely faster and doesn't use any memory to read exif data than to load in the entire
/// image via GDI. Otherwise loading an image into GDI consumes a crazy amount of memory on large images.
///
/// Of course EXIF data might not exist in every file and can only exist in JPGs
/// </remarks>
public static Size GetDimensions(Stream imageStream)
{
//Try to load with exif
try
{
var jpgInfo = ImageFile.FromStream(imageStream);
if (jpgInfo.Format != ImageFileFormat.Unknown
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension)
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension))
{
var height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value);
var width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value);
if (height > 0 && width > 0)
{
return new Size(width, height);
}
}
}
catch (Exception)
{
//We will just swallow, just means we can't read exif data, we don't want to log an error either
}
//we have no choice but to try to read in via GDI
using (var image = Image.FromStream(imageStream))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
return new Size(fileWidth, fileHeight);
}
}
public static string GetMimeType(this Image image)
{
var format = image.RawFormat;
+5 -1
View File
@@ -460,10 +460,14 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (Content)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually clone this since it's not settable
clone._contentType = (IContentType)ContentType.DeepClone();
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
+1 -1
View File
@@ -436,7 +436,7 @@ namespace Umbraco.Core.Models
return;
}
var propertyType = PropertyTypes.FirstOrDefault(x => x.Alias == propertyTypeAlias);
var propertyType = PropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (propertyType == null)
{
throw new Exception(String.Format("No PropertyType exists with the supplied alias: {0}", propertyTypeAlias));
@@ -10,12 +10,14 @@ namespace Umbraco.Core.Models
internal class ContentPreviewEntity<TContent> : ContentXmlEntity<TContent>
where TContent : IContentBase
{
public ContentPreviewEntity(bool previewExists, TContent content, Func<TContent, XElement> xml)
: base(previewExists, content, xml)
public ContentPreviewEntity(TContent content, Func<TContent, XElement> xml)
: base(content, xml)
{
Version = content.Version;
}
public Guid Version { get; private set; }
public Guid Version
{
get { return Content.Version; }
}
}
}
+14 -9
View File
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
{
private int _defaultTemplate;
private IEnumerable<ITemplate> _allowedTemplates;
/// <summary>
/// Constuctor for creating a ContentType with the parent's id.
/// </summary>
@@ -31,9 +31,10 @@ namespace Umbraco.Core.Models
/// </summary>
/// <remarks>Use this to ensure inheritance from parent.</remarks>
/// <param name="parent"></param>
public ContentType(IContentType parent) : this(parent, null)
{
}
[Obsolete("This method is obsolete, use ContentType(IContentType parent, string alias) instead.", false)]
public ContentType(IContentType parent) : this(parent, null)
{
}
/// <summary>
/// Constuctor for creating a ContentType with the parent as an inherited type.
@@ -49,7 +50,7 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.DefaultTemplateId);
private static readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<ITemplate>>(x => x.AllowedTemplates);
/// <summary>
/// Gets or sets the alias of the default Template.
/// </summary>
@@ -89,7 +90,11 @@ namespace Umbraco.Core.Models
{
_allowedTemplates = value;
return _allowedTemplates;
}, _allowedTemplates, AllowedTemplatesSelector);
}, _allowedTemplates, AllowedTemplatesSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<ITemplate>>(
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
templates => templates.GetHashCode()));
}
}
@@ -106,7 +111,7 @@ namespace Umbraco.Core.Models
}
DefaultTemplateId = template.Id;
if(_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
if (_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
{
var templates = AllowedTemplates.ToList();
templates.Add(template);
@@ -140,7 +145,7 @@ namespace Umbraco.Core.Models
{
base.AddingEntity();
if(Key == Guid.Empty)
if (Key == Guid.Empty)
Key = Guid.NewGuid();
}
@@ -151,7 +156,7 @@ namespace Umbraco.Core.Models
/// <returns></returns>
[Obsolete("Use DeepCloneWithResetIdentities instead")]
public IContentType Clone(string alias)
{
{
return DeepCloneWithResetIdentities(alias);
}
+14 -3
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -15,6 +16,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public abstract class ContentTypeBase : Entity, IContentTypeBase
{
private Lazy<int> _parentId;
@@ -349,7 +351,11 @@ namespace Umbraco.Core.Models
{
_allowedContentTypes = value;
return _allowedContentTypes;
}, _allowedContentTypes, AllowedContentTypesSelector);
}, _allowedContentTypes, AllowedContentTypesSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<ContentTypeSort>>(
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
sorts => sorts.GetHashCode()));
}
}
@@ -497,7 +503,6 @@ namespace Umbraco.Core.Models
/// <param name="propertyTypeAlias">Alias of the <see cref="PropertyType"/> to remove</param>
public void RemovePropertyType(string propertyTypeAlias)
{
//check if the property exist in one of our collections
if (PropertyGroups.Any(group => group.PropertyTypes.Any(pt => pt.Alias == propertyTypeAlias))
|| _propertyTypes.Any(x => x.Alias == propertyTypeAlias))
@@ -524,6 +529,7 @@ namespace Umbraco.Core.Models
public void RemovePropertyGroup(string propertyGroupName)
{
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(PropertyGroupCollectionSelector);
}
/// <summary>
@@ -607,13 +613,18 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (ContentTypeBase)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually wire up the event handlers for the property type collections - we've ensured
// its ignored from the auto-clone process because its return values are unions, not raw and
// we end up with duplicates, see: http://issues.umbraco.org/issue/U4-4842
clone._propertyTypes = (PropertyTypeCollection)_propertyTypes.DeepClone();
clone._propertyTypes.CollectionChanged += clone.PropertyTypesChanged;
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
@@ -255,11 +255,15 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (ContentTypeCompositionBase)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually assign since this is an internal field and will not be automatically mapped
clone.RemovedContentTypeKeyTracker = new List<int>();
clone._contentTypeComposition = ContentTypeComposition.Select(x => (IContentTypeComposition)x.DeepClone()).ToList();
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
+14 -2
View File
@@ -8,10 +8,20 @@ namespace Umbraco.Core.Models
/// </summary>
public class ContentTypeSort : IValueObject, IDeepCloneable
{
[Obsolete("This parameterless constructor should never be used")]
public ContentTypeSort()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
/// </summary>
public ContentTypeSort(int id, int sortOrder)
{
Id = new Lazy<int>(() => id);
SortOrder = sortOrder;
}
public ContentTypeSort(Lazy<int> id, int sortOrder, string @alias)
{
Id = id;
@@ -45,7 +55,7 @@ namespace Umbraco.Core.Models
protected bool Equals(ContentTypeSort other)
{
return Id.Value.Equals(other.Id.Value) && string.Equals(Alias, other.Alias);
return Id.Value.Equals(other.Id.Value) && string.Equals(Alias, other.Alias);
}
public override bool Equals(object obj)
@@ -60,7 +70,9 @@ namespace Umbraco.Core.Models
{
unchecked
{
return (Id.GetHashCode()*397) ^ Alias.GetHashCode();
//The hash code will just be the alias if one is assigned, otherwise it will be the hash code of the Id.
//In some cases the alias can be null of the non lazy ctor is used, in that case, the lazy Id will already have a value created.
return Alias != null ? Alias.GetHashCode() : (Id.Value.GetHashCode() * 397);
}
}
+9 -5
View File
@@ -11,13 +11,11 @@ namespace Umbraco.Core.Models
internal class ContentXmlEntity<TContent> : IAggregateRoot
where TContent : IContentBase
{
private readonly bool _entityExists;
private readonly Func<TContent, XElement> _xml;
public ContentXmlEntity(bool entityExists, TContent content, Func<TContent, XElement> xml)
{
public ContentXmlEntity(TContent content, Func<TContent, XElement> xml)
{
if (content == null) throw new ArgumentNullException("content");
_entityExists = entityExists;
_xml = xml;
Content = content;
}
@@ -32,6 +30,7 @@ namespace Umbraco.Core.Models
{
get { return _xml(Content); }
}
public TContent Content { get; private set; }
public int Id
@@ -44,9 +43,14 @@ namespace Umbraco.Core.Models
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
/// <summary>
/// Special case, always return false, this will cause the repositories managing
/// this object to always do an 'insert' but these are special repositories that
/// do an InsertOrUpdate on insert since the data for this needs to be managed this way
/// </summary>
public bool HasIdentity
{
get { return _entityExists; }
get { return false; }
}
public object DeepClone()
+5 -1
View File
@@ -80,7 +80,11 @@ namespace Umbraco.Core.Models
{
_translations = value;
return _translations;
}, _translations, TranslationsSelector);
}, _translations, TranslationsSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>>(
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
enumerable => enumerable.GetHashCode()));
}
}
+18 -4
View File
@@ -17,7 +17,6 @@ namespace Umbraco.Core.Models.EntityBase
public abstract class Entity : TracksChangesEntityBase, IEntity, IRememberBeingDirty, ICanBeDirty
{
private bool _hasIdentity;
private int? _hash;
private int _id;
private Guid _key;
private DateTime _createDate;
@@ -175,6 +174,7 @@ namespace Umbraco.Core.Models.EntityBase
}
}
//TODO: Make this NOT virtual or even exist really!
public virtual bool SameIdentityAs(IEntity other)
{
if (ReferenceEquals(null, other))
@@ -195,11 +195,13 @@ namespace Umbraco.Core.Models.EntityBase
return SameIdentityAs(other);
}
//TODO: Make this NOT virtual or even exist really!
public virtual Type GetRealType()
{
return GetType();
}
//TODO: Make this NOT virtual or even exist really!
public virtual bool SameIdentityAs(Entity other)
{
if (ReferenceEquals(null, other))
@@ -226,9 +228,13 @@ namespace Umbraco.Core.Models.EntityBase
public override int GetHashCode()
{
if (!_hash.HasValue)
_hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode());
return _hash.Value;
unchecked
{
var hashCode = HasIdentity.GetHashCode();
hashCode = (hashCode * 397) ^ Id;
hashCode = (hashCode * 397) ^ GetType().GetHashCode();
return hashCode;
}
}
public virtual object DeepClone()
@@ -236,9 +242,17 @@ namespace Umbraco.Core.Models.EntityBase
//Memberwise clone on Entity will work since it doesn't have any deep elements
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
var clone = (Entity)MemberwiseClone();
//ensure the clone has it's own dictionaries
clone.ResetChangeTrackingCollections();
//turn off change tracking
clone.DisableChangeTracking();
//Automatically deep clone ref properties that are IDeepCloneable
DeepCloneHelper.DeepCloneRefProperties(this, clone);
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
@@ -18,7 +19,9 @@ namespace Umbraco.Core.Models.EntityBase
public virtual IEnumerable<string> GetDirtyProperties()
{
return _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
}
}
private bool _changeTrackingEnabled = true;
/// <summary>
/// Tracks the properties that have changed
@@ -41,6 +44,9 @@ namespace Umbraco.Core.Models.EntityBase
/// <param name="propertyInfo">The property info.</param>
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
{
//return if we're not tracking changes
if (_changeTrackingEnabled == false) return;
_propertyChangedInfo[propertyInfo.Name] = true;
if (PropertyChanged != null)
@@ -132,6 +138,22 @@ namespace Umbraco.Core.Models.EntityBase
_propertyChangedInfo = new Dictionary<string, bool>();
}
protected void ResetChangeTrackingCollections()
{
_propertyChangedInfo = new Dictionary<string, bool>();
_lastPropertyChangedInfo = new Dictionary<string, bool>();
}
protected void DisableChangeTracking()
{
_changeTrackingEnabled = false;
}
protected void EnableChangeTracking()
{
_changeTrackingEnabled = true;
}
/// <summary>
/// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did
/// it will ensure that the property has a dirty flag set.
@@ -145,17 +167,51 @@ namespace Umbraco.Core.Models.EntityBase
/// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set
/// to the same value, so it's really not dirty.
/// </remarks>
internal virtual bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector)
internal bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector)
{
if ((typeof(T) == typeof(string) == false) && TypeHelper.IsTypeAssignableFrom<IEnumerable>(typeof(T)))
{
throw new InvalidOperationException("This method does not support IEnumerable instances. For IEnumerable instances a manual custom equality check will be required");
}
return SetPropertyValueAndDetectChanges(setValue, value, propertySelector,
new DelegateEqualityComparer<T>(
//Standard Equals comparison
(arg1, arg2) => Equals(arg1, arg2),
arg => arg.GetHashCode()));
}
/// <summary>
/// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did
/// it will ensure that the property has a dirty flag set.
/// </summary>
/// <param name="setValue"></param>
/// <param name="value"></param>
/// <param name="propertySelector"></param>
/// <param name="comparer">The equality comparer to use</param>
/// <returns>returns true if the value changed</returns>
/// <remarks>
/// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we
/// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set
/// to the same value, so it's really not dirty.
/// </remarks>
internal bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector, IEqualityComparer<T> comparer)
{
var initVal = value;
var newVal = setValue(value);
if (Equals(initVal, newVal) == false)
//don't track changes, just set the value (above)
if (_changeTrackingEnabled == false) return false;
if (comparer.Equals(initVal, newVal) == false)
{
OnPropertyChanged(propertySelector);
return true;
}
return false;
}
}
}
+11 -3
View File
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Models
}
/// <summary>
/// Gets or sets the Path to the File from the root of the site
/// Gets or sets the Path to the File from the root of the file's associated IFileSystem
/// </summary>
[DataMember]
public virtual string Path
@@ -99,6 +99,11 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or sets the file's virtual path (i.e. the file path relative to the root of the website)
/// </summary>
public string VirtualPath { get; set; }
/// <summary>
/// Boolean indicating whether the file could be validated
/// </summary>
@@ -108,12 +113,15 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (File)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually assign since they are readonly properties
clone._alias = Alias;
clone._name = Name;
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
+6 -1
View File
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models
string Alias { get; }
/// <summary>
/// Gets or sets the Path to the File from the root of the site
/// Gets or sets the Path to the File from the root of the file's associated IFileSystem
/// </summary>
string Path { get; set; }
@@ -28,6 +28,11 @@ namespace Umbraco.Core.Models
/// </summary>
string Content { get; set; }
/// <summary>
/// Gets or sets the file's virtual path (i.e. the file path relative to the root of the website)
/// </summary>
string VirtualPath { get; set; }
/// <summary>
/// Boolean indicating whether the file could be validated
/// </summary>
+7
View File
@@ -0,0 +1,7 @@
namespace Umbraco.Core.Models
{
public interface IPartialView : IFile
{
}
}
+9 -5
View File
@@ -9,6 +9,7 @@ using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.IO;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models
{
@@ -48,7 +49,7 @@ namespace Umbraco.Core.Models
Id = id;
UseInEditor = useInEditor;
CacheDuration = cacheDuration;
Alias = alias;
Alias = alias.ToCleanString(CleanStringType.Alias);
Name = name;
ControlType = controlType;
ControlAssembly = controlAssembly;
@@ -87,7 +88,7 @@ namespace Umbraco.Core.Models
{
UseInEditor = useInEditor;
CacheDuration = cacheDuration;
Alias = alias;
Alias = alias.ToCleanString(CleanStringType.Alias);
Name = name;
ControlType = controlType;
ControlAssembly = controlAssembly;
@@ -207,7 +208,7 @@ namespace Umbraco.Core.Models
{
SetPropertyValueAndDetectChanges(o =>
{
_alias = value;
_alias = value.ToCleanString(CleanStringType.Alias);
return _alias;
}, _alias, AliasSelector);
}
@@ -398,14 +399,17 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (Macro)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
clone._addedProperties = new List<string>();
clone._removedProperties = new List<string>();
clone._properties = (MacroPropertyCollection)Properties.DeepClone();
//re-assign the event handler
clone._properties.CollectionChanged += clone.PropertiesChanged;
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
+6 -35
View File
@@ -20,7 +20,6 @@ namespace Umbraco.Core.Models
private string _email;
private string _rawPasswordValue;
private object _providerUserKey;
private Type _userTypeKey;
/// <summary>
/// Constructor for creating an empty Member object
@@ -114,7 +113,6 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Email);
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.RawPasswordValue);
private static readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo<Member, object>(x => x.ProviderUserKey);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<Member, Type>(x => x.ProviderUserKeyType);
/// <summary>
/// Gets or sets the Username
@@ -502,38 +500,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType(Type type)
{
ProviderUserKeyType = type;
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
@@ -650,10 +617,14 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (Member)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually clone this since it's not settable
clone._contentType = (IMemberType)ContentType.DeepClone();
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
+2 -1
View File
@@ -20,7 +20,8 @@ namespace Umbraco.Core.Models.Membership
/// Gets/sets the user type for the user
/// </summary>
IUserType UserType { get; set; }
//TODO: This should be a private set
/// <summary>
/// The default permission set for the user
/// </summary>
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Models.Membership
{
internal static class MembershipUserExtensions
{
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName)
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
{
var membershipMember = new UmbracoMembershipMember(member, providerName);
var membershipMember = new UmbracoMembershipMember(member, providerName, providerKeyAsGuid);
return membershipMember;
}
@@ -1,5 +1,6 @@
using System;
using System.Web.Security;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Models.Membership
{
@@ -25,7 +26,7 @@ namespace Umbraco.Core.Models.Membership
//NOTE: We are not calling the base constructor which will validate that a provider with the specified name exists which causes issues with unit tests. The ctor
// validation for that doesn't need to be there anyways (have checked the source).
public UmbracoMembershipMember(IMembershipUser member, string providerName)
public UmbracoMembershipMember(IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
{
_member = member;
//NOTE: We are copying the values here so that everything is consistent with how the underlying built-in ASP.Net membership user
@@ -37,7 +38,7 @@ namespace Umbraco.Core.Models.Membership
if (member.PasswordQuestion != null)
_passwordQuestion = member.PasswordQuestion.Trim();
_providerName = providerName;
_providerUserKey = member.ProviderUserKey;
_providerUserKey = providerKeyAsGuid ? member.ProviderUserKey : member.Id;
_comment = member.Comments;
_isApproved = member.IsApproved;
_isLockedOut = member.IsLockedOut;
+15 -48
View File
@@ -27,7 +27,7 @@ namespace Umbraco.Core.Models.Membership
if (userType == null) throw new ArgumentNullException("userType");
_userType = userType;
_defaultPermissions = _userType.Permissions;
_defaultPermissions = _userType.Permissions == null ? Enumerable.Empty<string>() : new List<string>(_userType.Permissions);
//Groups = new List<object> { userType };
SessionTimeout = 60;
_sectionCollection = new ObservableCollection<string>();
@@ -58,7 +58,6 @@ namespace Umbraco.Core.Models.Membership
private IUserType _userType;
private string _name;
private Type _userTypeKey;
private List<string> _addedSections;
private List<string> _removedSections;
private ObservableCollection<string> _sectionCollection;
@@ -72,7 +71,9 @@ namespace Umbraco.Core.Models.Membership
private bool _isApproved;
private bool _isLockedOut;
private string _language;
private IEnumerable<string> _defaultPermissions;
private IEnumerable<string> _defaultPermissions;
private bool _defaultToLiveEditing;
private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
@@ -80,7 +81,6 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<User, Type>(x => x.ProviderUserKeyType);
private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Username);
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Email);
@@ -88,7 +88,7 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsLockedOut);
private static readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsApproved);
private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.DefaultPermissions);
private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
private static readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
@@ -101,37 +101,6 @@ namespace Umbraco.Core.Models.Membership
set { throw new NotSupportedException("Cannot set the provider user key for a user"); }
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType(Type type)
{
ProviderUserKeyType = type;
}
[DataMember]
public string Username
@@ -352,19 +321,13 @@ namespace Umbraco.Core.Models.Membership
}, _language, LanguageSelector);
}
}
//TODO: This should be a private set
[DataMember]
public IEnumerable<string> DefaultPermissions
{
get { return _defaultPermissions; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_defaultPermissions = value;
return _defaultPermissions;
}, _defaultPermissions, DefaultPermissionsSelector);
}
get { return _defaultPermissions;}
set { _defaultPermissions = value; }
}
[IgnoreDataMember]
@@ -448,15 +411,19 @@ namespace Umbraco.Core.Models.Membership
public override object DeepClone()
{
var clone = (User)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to create new collections otherwise they'll get copied by ref
clone._addedSections = new List<string>();
clone._removedSections = new List<string>();
clone._sectionCollection = new ObservableCollection<string>(_sectionCollection.ToList());
clone._defaultPermissions = new List<string>(_defaultPermissions.ToList());
//re-create the event handler
clone._sectionCollection.CollectionChanged += clone.SectionCollectionChanged;
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
@@ -67,7 +68,11 @@ namespace Umbraco.Core.Models.Membership
{
_permissions = value;
return _permissions;
}, _permissions, PermissionsSelector);
}, _permissions, PermissionsSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<string>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode()));
}
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class PartialView : File
public class PartialView : File, IPartialView
{
//public PartialView(): base(string.Empty)
//{
+24 -3
View File
@@ -1,4 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
@@ -120,7 +123,7 @@ namespace Umbraco.Core.Models
{
bool typeValidation = _propertyType.IsPropertyTypeValid(value);
if (!typeValidation)
if (typeValidation == false)
throw new Exception(
string.Format(
"Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'",
@@ -130,7 +133,21 @@ namespace Umbraco.Core.Models
{
_value = value;
return _value;
}, _value, ValueSelector);
}, _value, ValueSelector,
new DelegateEqualityComparer<object>(
(o, o1) =>
{
//Custom comparer for enumerable if it is enumerable
if (o == null && o1 == null) return true;
if (o == null || o1 == null) return false;
var enum1 = o as IEnumerable;
var enum2 = o1 as IEnumerable;
if (enum1 != null && enum2 != null)
{
return enum1.Cast<object>().UnsortedSequenceEqual(enum2.Cast<object>());
}
return o.Equals(o1);
}, o => o.GetHashCode()));
}
}
@@ -160,10 +177,14 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (Property)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually assign since this is a readonly property
clone._propertyType = (PropertyType)PropertyType.DeepClone();
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
+12 -8
View File
@@ -16,12 +16,14 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
{
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
private readonly object _addLocker = new object();
internal Action OnAdd;
internal Func<Property, bool> ValidateAdd { get; set; }
internal PropertyCollection()
{}
: base(StringComparer.InvariantCultureIgnoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PropertyCollection"/> class with a delegate responsible for validating the addition of <see cref="Property"/> instances.
@@ -29,11 +31,13 @@ namespace Umbraco.Core.Models
/// <param name="validationCallback">The validation callback.</param>
/// <remarks></remarks>
internal PropertyCollection(Func<Property, bool> validationCallback)
: this()
{
ValidateAdd = validationCallback;
}
public PropertyCollection(IEnumerable<Property> properties)
: this()
{
Reset(properties);
}
@@ -78,7 +82,7 @@ namespace Umbraco.Core.Models
internal new void Add(Property item)
{
using (new WriteLock(_addLocker))
lock (_addLocker)
{
var key = GetKeyForItem(item);
if (key != null)
@@ -113,14 +117,14 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
public new bool Contains(string propertyTypeAlias)
{
return this.Any(x => x.Alias == propertyTypeAlias);
return base.Contains(propertyTypeAlias);
}
public int IndexOfKey(string key)
{
for (var i = 0; i < this.Count; i++)
{
if (this[i].Alias == key)
if (this[i].Alias.InvariantEquals(key))
{
return i;
}
@@ -145,7 +149,7 @@ namespace Umbraco.Core.Models
{
get
{
return this.FirstOrDefault(x => x.Alias == propertyType.Alias);
return this.FirstOrDefault(x => x.Alias.InvariantEquals(propertyType.Alias));
}
}
@@ -165,7 +169,7 @@ namespace Umbraco.Core.Models
/// <param name="propertyTypes">List of PropertyType</param>
protected internal void EnsurePropertyTypes(IEnumerable<PropertyType> propertyTypes)
{
if(/*!this.Any() &&*/ propertyTypes != null)
if (/*!this.Any() &&*/ propertyTypes != null)
{
foreach (var propertyType in propertyTypes)
{
@@ -180,7 +184,7 @@ namespace Umbraco.Core.Models
/// <param name="propertyTypes">List of PropertyType</param>
protected internal void EnsureCleanPropertyTypes(IEnumerable<PropertyType> propertyTypes)
{
if(propertyTypes != null)
if (propertyTypes != null)
{
//Remove PropertyTypes that doesn't exist in the list of new PropertyTypes
var aliases = this.Select(p => p.Alias).Except(propertyTypes.Select(x => x.Alias)).ToList();
+6 -11
View File
@@ -120,27 +120,22 @@ namespace Umbraco.Core.Models
public bool Equals(PropertyGroup other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
if (base.Equals(other)) return true;
//Check whether the PropertyGroup's properties are equal.
return Id.Equals(other.Id) && Name.Equals(other.Name);
return Name.InvariantEquals(other.Name);
}
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
int hashName = Name == null ? 0 : Name.GetHashCode();
int baseHash = base.GetHashCode();
//Get hash code for the Id field.
int hashId = Id.GetHashCode();
//Get hash code for the Alias field.
int nameHash = Name.ToLowerInvariant().GetHashCode();
//Calculate the hash code for the product.
return hashName ^ hashId;
return baseHash ^ nameHash;
}
}
@@ -71,16 +71,34 @@ namespace Umbraco.Core.Models
{
using (new WriteLock(_addLocker))
{
var key = GetKeyForItem(item);
if (key != null)
//Note this is done to ensure existig groups can be renamed
if (item.HasIdentity && item.Id > 0)
{
var exists = this.Contains(key);
var exists = this.Contains(item.Id);
if (exists)
{
SetItem(IndexOfKey(key), item);
var keyExists = this.Contains(item.Name);
if(keyExists)
throw new Exception(string.Format("Naming conflict: Changing the name of PropertyGroup '{0}' would result in duplicates", item.Name));
SetItem(IndexOfKey(item.Id), item);
return;
}
}
else
{
var key = GetKeyForItem(item);
if (key != null)
{
var exists = this.Contains(key);
if (exists)
{
SetItem(IndexOfKey(key), item);
return;
}
}
}
base.Add(item);
OnAdd.IfNotNull(x => x.Invoke());//Could this not be replaced by a Mandate/Contract for ensuring item is not null
@@ -99,6 +117,11 @@ namespace Umbraco.Core.Models
return this.Any(x => x.Name == groupName);
}
public bool Contains(int id)
{
return this.Any(x => x.Id == id);
}
public void RemoveItem(string propertyGroupName)
{
var key = IndexOfKey(propertyGroupName);
@@ -119,6 +142,18 @@ namespace Umbraco.Core.Models
return -1;
}
public int IndexOfKey(int id)
{
for (var i = 0; i < this.Count; i++)
{
if (this[i].Id == id)
{
return i;
}
}
return -1;
}
protected override string GetKeyForItem(PropertyGroup item)
{
return item.Name;
+51 -21
View File
@@ -1,9 +1,9 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public class PropertyType : Entity, IEquatable<PropertyType>
{
private readonly bool _isExplicitDbType;
@@ -37,11 +38,21 @@ namespace Umbraco.Core.Models
_propertyEditorAlias = dataTypeDefinition.PropertyEditorAlias;
_dataTypeDatabaseType = dataTypeDefinition.DatabaseType;
}
public PropertyType(IDataTypeDefinition dataTypeDefinition, string propertyTypeAlias)
: this(dataTypeDefinition)
{
SetAlias(propertyTypeAlias);
}
internal PropertyType(string propertyEditorAlias, DataTypeDatabaseType dataTypeDatabaseType)
public PropertyType(string propertyEditorAlias, DataTypeDatabaseType dataTypeDatabaseType)
: this(propertyEditorAlias, dataTypeDatabaseType, false)
{
PropertyEditorAlias = propertyEditorAlias;
}
public PropertyType(string propertyEditorAlias, DataTypeDatabaseType dataTypeDatabaseType, string propertyTypeAlias)
: this(propertyEditorAlias, dataTypeDatabaseType, false, propertyTypeAlias)
{
}
/// <summary>
@@ -57,6 +68,21 @@ namespace Umbraco.Core.Models
_dataTypeDatabaseType = dataTypeDatabaseType;
}
/// <summary>
/// Used internally to assign an explicity database type for this property type regardless of what the underlying data type/property editor is.
/// </summary>
/// <param name="propertyEditorAlias"></param>
/// <param name="dataTypeDatabaseType"></param>
/// <param name="isExplicitDbType"></param>
/// <param name="propertyTypeAlias"></param>
internal PropertyType(string propertyEditorAlias, DataTypeDatabaseType dataTypeDatabaseType, bool isExplicitDbType, string propertyTypeAlias)
{
_isExplicitDbType = isExplicitDbType;
_propertyEditorAlias = propertyEditorAlias;
_dataTypeDatabaseType = dataTypeDatabaseType;
SetAlias(propertyTypeAlias);
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Name);
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Alias);
private static readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Description);
@@ -95,15 +121,9 @@ namespace Umbraco.Core.Models
get { return _alias; }
set
{
//NOTE: WE are doing this because we don't want to do a ToSafeAlias when the alias is the special case of
// being prefixed with Constants.PropertyEditors.InternalGenericPropertiesPrefix
// which is used internally
SetPropertyValueAndDetectChanges(o =>
{
_alias = value.StartsWith(Constants.PropertyEditors.InternalGenericPropertiesPrefix)
? value
: value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
SetAlias(value);
return _alias;
}, _alias, AliasSelector);
}
@@ -283,6 +303,17 @@ namespace Umbraco.Core.Models
}
}
private void SetAlias(string value)
{
//NOTE: WE are doing this because we don't want to do a ToSafeAlias when the alias is the special case of
// being prefixed with Constants.PropertyEditors.InternalGenericPropertiesPrefix
// which is used internally
_alias = value.StartsWith(Constants.PropertyEditors.InternalGenericPropertiesPrefix)
? value
: value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
}
/// <summary>
/// Create a new Property object from a "raw" database value.
/// </summary>
@@ -430,39 +461,38 @@ namespace Umbraco.Core.Models
public bool Equals(PropertyType other)
{
//Check whether the compared object is null.
if (ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (ReferenceEquals(this, other)) return true;
if (base.Equals(other)) return true;
//Check whether the PropertyType's properties are equal.
return Alias.Equals(other.Alias) && Name.Equals(other.Name);
return Alias.InvariantEquals(other.Alias);
}
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
int hashName = Name == null ? 0 : Name.GetHashCode();
int baseHash = base.GetHashCode();
//Get hash code for the Alias field.
int hashAlias = Alias.GetHashCode();
int hashAlias = Alias.ToLowerInvariant().GetHashCode();
//Calculate the hash code for the product.
return hashName ^ hashAlias;
return baseHash ^ hashAlias;
}
public override object DeepClone()
{
var clone = (PropertyType)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually assign the Lazy value as it will not be automatically mapped
if (PropertyGroupId != null)
{
clone._propertyGroupId = new Lazy<int>(() => PropertyGroupId.Value);
}
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
@@ -5,6 +5,7 @@
/// </summary>
public enum TaggableObjectTypes
{
All,
Content,
Media,
Member
+5 -2
View File
@@ -193,12 +193,15 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (Template)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//need to manually assign since they are readonly properties
clone._alias = Alias;
clone._name = Name;
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
+6 -2
View File
@@ -288,7 +288,8 @@ namespace Umbraco.Core.Models
public override object DeepClone()
{
var clone = (UmbracoEntity) base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//This ensures that any value in the dictionary that is deep cloneable is cloned too
foreach (var key in clone.AdditionalData.Keys.ToArray())
{
@@ -298,7 +299,10 @@ namespace Umbraco.Core.Models
clone.AdditionalData[key] = deepCloneable.DeepClone();
}
}
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
clone.EnableChangeTracking();
return clone;
}
+35 -1
View File
@@ -1,11 +1,45 @@
using System;
using System.Globalization;
using System.Linq;
using System.Threading;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
internal static class UserExtensions
public static class UserExtensions
{
/// <summary>
/// Returns the culture info associated with this user, based on the language they're assigned to in the back office
/// </summary>
/// <param name="user"></param>
/// <param name="textService"></param>
/// <returns></returns>
public static CultureInfo GetUserCulture(this IUser user, ILocalizedTextService textService)
{
if (user == null) throw new ArgumentNullException("user");
if (textService == null) throw new ArgumentNullException("textService");
return GetUserCulture(user.Language, textService);
}
internal static CultureInfo GetUserCulture(string userLanguage, ILocalizedTextService textService)
{
try
{
var culture = CultureInfo.GetCultureInfo(userLanguage.Replace("_", "-"));
//TODO: This is a hack because we store the user language as 2 chars instead of the full culture
// which is actually stored in the language files (which are also named with 2 chars!) so we need to attempt
// to convert to a supported full culture
var result = textService.ConvertToSupportedCultureWithRegionCode(culture);
return result;
}
catch (CultureNotFoundException)
{
//return the default one
return CultureInfo.GetCultureInfo("en");
}
}
/// <summary>
/// Checks if the user has access to the content item based on their start noe
/// </summary>
@@ -23,7 +23,7 @@ namespace Umbraco.Core.ObjectResolution
where TResolver : ResolverBase
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
/// with creation of objects based on an HttpRequest lifetime scope.
@@ -31,9 +31,11 @@ namespace Umbraco.Core.ObjectResolution
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: base(scope)
{ }
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: base(scope)
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
@@ -41,9 +43,11 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
: base(httpContext)
{ }
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
: base(httpContext)
{
Initialize();
}
/// <summary>
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list
@@ -101,23 +105,37 @@ namespace Umbraco.Core.ObjectResolution
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
private readonly List<Func<IEnumerable<Type>>> _typeListProducerList = new List<Func<IEnumerable<Type>>>();
private readonly List<Type> _excludedTypesList = new List<Type>();
private Lazy<List<Type>> _resolvedTypes = null;
private void Initialize()
{
_resolvedTypes = new Lazy<List<Type>>(() =>
{
var resolvedTypes = new List<Type>();
// get the types by evaluating the lazy & producers
var types = new List<Type>();
types.AddRange(_lazyTypeList.Select(x => x.Value));
types.AddRange(_typeListProducerList.SelectMany(x => x()));
// we need to validate each resolved type now since we could
// not do it before evaluating the lazy & producers
foreach (var type in types.Where(x => _excludedTypesList.Contains(x) == false))
{
AddValidAndNoDuplicate(resolvedTypes, type);
}
return resolvedTypes;
});
}
private List<Type> _resolvedTypes = null;
private readonly ReaderWriterLockSlim _resolvedTypesLock = new ReaderWriterLockSlim();
/// <summary>
/// Gets a value indicating whether the resolver has resolved types to create instances from.
/// </summary>
/// <remarks>To be used in unit tests.</remarks>
public bool HasResolvedTypes
{
get
{
using (new ReadLock(_resolvedTypesLock))
{
return _resolvedTypes != null;
}
}
get { return _resolvedTypes.IsValueCreated; }
}
/// <summary>
@@ -126,32 +144,7 @@ namespace Umbraco.Core.ObjectResolution
/// <remarks>When called, will get the types from the lazy list.</remarks>
protected override IEnumerable<Type> InstanceTypes
{
get
{
using (var lck = new UpgradeableReadLock(_resolvedTypesLock))
{
if (_resolvedTypes == null)
{
lck.UpgradeToWriteLock();
_resolvedTypes = new List<Type>();
// get the types by evaluating the lazy & producers
var types = new List<Type>();
types.AddRange(_lazyTypeList.Select(x => x.Value));
types.AddRange(_typeListProducerList.SelectMany(x => x()));
// we need to validate each resolved type now since we could
// not do it before evaluating the lazy & producers
foreach (var type in types.Where(x => !_excludedTypesList.Contains(x)))
{
AddValidAndNoDuplicate(_resolvedTypes, type);
}
}
return _resolvedTypes;
}
}
get { return _resolvedTypes.Value; }
}
/// <summary>
@@ -15,7 +15,7 @@ namespace Umbraco.Core.ObjectResolution
where TResolved : class
where TResolver : ResolverBase
{
private IEnumerable<TResolved> _applicationInstances = null;
private Lazy<IEnumerable<TResolved>> _applicationInstances = null;
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private readonly string _httpContextKey;
private readonly List<Type> _instanceTypes = new List<Type>();
@@ -47,6 +47,8 @@ namespace Umbraco.Core.ObjectResolution
if (scope == ObjectLifetimeScope.HttpRequest)
_httpContextKey = this.GetType().FullName;
_instanceTypes = new List<Type>();
InitializeAppInstances();
}
/// <summary>
@@ -64,6 +66,8 @@ namespace Umbraco.Core.ObjectResolution
_httpContextKey = this.GetType().FullName;
CurrentHttpContext = httpContext;
_instanceTypes = new List<Type>();
InitializeAppInstances();
}
/// <summary>
@@ -94,6 +98,11 @@ namespace Umbraco.Core.ObjectResolution
}
#endregion
private void InitializeAppInstances()
{
_applicationInstances = new Lazy<IEnumerable<TResolved>>(() => CreateInstances().ToArray());
}
/// <summary>
/// Gets or sets a value indicating whether the resolver can resolve objects before resolution is frozen.
/// </summary>
@@ -178,30 +187,17 @@ namespace Umbraco.Core.ObjectResolution
switch (LifetimeScope)
{
case ObjectLifetimeScope.HttpRequest:
// create new instances per HttpContext
using (var l = new UpgradeableReadLock(_lock))
{
// create if not already there
if (CurrentHttpContext.Items[_httpContextKey] == null)
{
l.UpgradeToWriteLock();
CurrentHttpContext.Items[_httpContextKey] = CreateInstances().ToArray();
}
return (TResolved[])CurrentHttpContext.Items[_httpContextKey];
}
case ObjectLifetimeScope.Application:
// create new instances per application
using (var l = new UpgradeableReadLock(_lock))
// create new instances per HttpContext
if (CurrentHttpContext.Items[_httpContextKey] == null)
{
// create if not already there
if (_applicationInstances == null)
{
l.UpgradeToWriteLock();
_applicationInstances = CreateInstances().ToArray();
}
return _applicationInstances;
CurrentHttpContext.Items[_httpContextKey] = CreateInstances().ToArray();
}
return (TResolved[])CurrentHttpContext.Items[_httpContextKey];
case ObjectLifetimeScope.Application:
return _applicationInstances.Value;
case ObjectLifetimeScope.Transient:
default:
@@ -105,9 +105,9 @@ namespace Umbraco.Core.Persistence.Factories
propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success)
propDbType.Success,
typeDto.Alias)
{
Alias = typeDto.Alias,
DataTypeDefinitionId = typeDto.DataTypeId,
Description = typeDto.Description,
Id = typeDto.Id.Value,
@@ -158,9 +158,9 @@ namespace Umbraco.Core.Persistence.Factories
propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success)
propDbType.Success,
typeDto.Alias)
{
Alias = typeDto.Alias,
DataTypeDefinitionId = typeDto.DataTypeId,
Description = typeDto.Description,
HelpText = typeDto.HelpText,
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Factories
{
internal void AddAdditionalData(UmbracoEntity entity, IDictionary<string, object> originalEntityProperties)
{
var entityProps = TypeHelper.GetPublicProperties(typeof(IUmbracoEntity)).Select(x => x.Name).ToArray();
var entityProps = typeof(IUmbracoEntity).GetPublicProperties().Select(x => x.Name).ToArray();
//figure out what extra properties we have that are not on the IUmbracoEntity and add them to additional data
foreach (var k in originalEntityProperties.Keys
@@ -32,9 +32,7 @@ namespace Umbraco.Core.Persistence.Factories
IsLockedOut = dto.NoConsole,
IsApproved = dto.Disabled == false,
Email = dto.Email,
Language = dto.UserLanguage,
//NOTE: The default permission come from the user type's default permissions
DefaultPermissions = _userType.Permissions
Language = dto.UserLanguage
};
foreach (var app in dto.User2AppDtos)

Some files were not shown because too many files have changed in this diff Show More