1 /**
2  * Classes that wrap the Imagemagick exception handling.
3  *
4  * Copyright: Mike Wey 2011
5  * License:   zlib (See accompanying LICENSE file)
6  * Authors:   Mike Wey
7  */
8 
9 module dmagick.Exception;
10 
11 import std.conv;
12 
13 import dmagick.c.client;
14 import dmagick.c.exception;
15 
16 /**
17  * A base class for all exceptions thrown bij DMagick.
18  * The following Exceptions are derived from this class:
19  *
20  * ResourceLimitException, TypeException, OptionException,
21  * DelegateException, MissingDelegateException, CorruptImageException,
22  * FileOpenException, BlobException, StreamException, CacheException,
23  * CoderException, FilterException, ModuleException, DrawException,
24  * ImageException, WandException, RandomException, XServerException,
25  * MonitorException, RegistryException, ConfigureException, PolicyException
26  */
27 class DMagickException : Exception
28 {
29 	this(string reason, string description = null, string file = __FILE__, size_t line = __LINE__)
30 	{
31 		string message = to!(string)(GetClientName());
32 
33 		if ( reason.length > 0 )
34 			message ~= ": " ~ reason;
35 		if ( description.length > 0 )
36 			message ~= " (" ~ description ~ ")";
37 
38 		super(message, file, line);
39 	}
40 
41 	private enum string[] severities = [ "Blob", "Cache", "Coder",
42 		"Configure", "CorruptImage", "Delegate", "Draw", "FileOpen",
43 		"Filter", "Image", "MissingDelegate", "Module", "Monitor",
44 		"Option", "Policy", "Random", "Registry", "ResourceLimit",
45 		"Stream", "Type", "Wand", "XServer" ];
46 
47 	/**
48 	 * Throws an Exception or error matching the ExceptionInfo.
49 	 */
50 	static void throwException(ExceptionInfo* exception, string file = __FILE__, size_t line = __LINE__)
51 	{
52 		if ( exception.severity == ExceptionType.UndefinedException )
53 			return;
54 
55 		string reason      = to!(string)(exception.reason);
56 		string description = to!(string)(exception.description);
57 
58 		scope(exit) exception = DestroyExceptionInfo(exception);
59 
60 		mixin(
61 		{
62 			string exceptions =
63 				"switch ( exception.severity )
64 			 	{";
65 
66 			foreach ( severity; severities )
67 			{
68 				//TODO: Warnings?
69 				exceptions ~=
70 					"case ExceptionType."~ severity ~"Error:
71 						throw new "~ severity ~"Exception(reason, description, file, line);
72 					 case ExceptionType."~ severity ~"FatalError:
73 						throw new "~ severity ~"Error(reason, description, file, line);";
74 			}
75 
76 			return exceptions ~= 
77 				"	default:
78 						return;
79 				}";
80 		}());
81 	}
82 }
83 
84 /**
85  * A base class for all errors thrown bij DMagick.
86  * The following Errors are derived from this class:
87  *
88  * ResourceLimitError, TypeError, OptionError,
89  * DelegateError, MissingDelegateError, CorruptImageError,
90  * FileOpenError, BlobError, StreamError, CacheError,
91  * CoderError, FilterError, ModuleError, DrawError,
92  * ImageError, WandError, RandomError, XServerError,
93  * MonitorError, RegistryError, ConfigureError, PolicyError
94  */
95 class DMagickError : Error
96 {
97 	this(string reason, string description = null, string file = __FILE__, size_t line = __LINE__)
98 	{
99 		string message = to!(string)(GetClientName());
100 
101 		if ( reason.length > 0 )
102 			message ~= ": " ~ reason;
103 		if ( description.length > 0 )
104 			message ~= " (" ~ description ~ ")";
105 
106 		super(message, file, line);
107 	}
108 }
109 
110 /**
111  * Generate the exceptions and the throwException function;
112  */
113 mixin(
114 {
115 	string exceptions;
116 
117 	foreach ( severity; DMagickException.severities )
118 	{
119 		exceptions ~= 
120 			"class " ~ severity ~ "Exception : DMagickException
121 			 {
122 				this(string reason, string description = null, string file = __FILE__, size_t line = __LINE__)
123 				{
124 					super(reason, description, file, line);
125 				}
126 			 }";
127 
128 		exceptions ~= 
129 			"class " ~ severity ~ "Error : DMagickError
130 			 {
131 				this(string reason, string description = null, string file = __FILE__, size_t line = __LINE__)
132 				{
133 					super(reason, description, file, line);
134 				}
135 			 }";
136 	}
137 
138 	return exceptions;
139 }());
140 
141 /**
142  * This struct is used to wrap the ImageMagick exception handling.
143  * Needs dmd >= 2.053
144  * Usage:
145  * --------------------
146  * CFunctionCall(param1, param2, DExceptionInfo());
147  * --------------------
148  */
149 struct DMagickExceptionInfo
150 {
151 	ExceptionInfo* exceptionInfo;
152 
153 	string file;
154 	size_t line;
155 
156 	private bool isInitialized;
157 	private size_t* refcount;
158 
159 	alias exceptionInfo this;
160 
161 	static DMagickExceptionInfo opCall(string file = __FILE__, size_t line = __LINE__)
162 	{
163 		DMagickExceptionInfo info;
164 
165 		info.exceptionInfo = AcquireExceptionInfo();
166 		info.refcount = new size_t;
167 
168 		*(info.refcount) = 1;
169 		info.isInitialized = true;
170 
171 		info.file = file;
172 		info.line = line;
173 
174 		return info;
175 	}
176 
177 	this(this)
178 	{
179 		if ( isInitialized )
180 			(*refcount)++;
181 	}
182 
183 	~this()
184 	{
185 		if ( !isInitialized )
186 			return;
187 
188 		(*refcount)--;
189 
190 		if ( *refcount == 0 )
191 		{
192 			DMagickException.throwException(exceptionInfo, file, line);
193 		}
194 	}
195 }
196 
197 unittest
198 {
199 	void testDMagickExcepionInfo(ExceptionInfo* info)
200 	{
201 		assert(info !is null);
202 	}
203 
204 	testDMagickExcepionInfo(DMagickExceptionInfo());
205 }