1 /*******************************************************************************
2  * processrenderoptions.cpp
3  *
4  * ---------------------------------------------------------------------------
5  * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
6  * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
7  *
8  * POV-Ray is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Affero General Public License as
10  * published by the Free Software Foundation, either version 3 of the
11  * License, or (at your option) any later version.
12  *
13  * POV-Ray is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Affero General Public License for more details.
17  *
18  * You should have received a copy of the GNU Affero General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  * ---------------------------------------------------------------------------
21  * POV-Ray is based on the popular DKB raytracer version 2.12.
22  * DKBTrace was originally written by David K. Buck.
23  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24  * ---------------------------------------------------------------------------
25  * $File: //depot/public/povray/3.x/source/frontend/processrenderoptions.cpp $
26  * $Revision: #1 $
27  * $Change: 6069 $
28  * $DateTime: 2013/11/06 11:59:40 $
29  * $Author: chrisc $
30  *******************************************************************************/
31 
32 #include <cctype>
33 #include <cstdlib>
34 
35 // configbase.h must always be the first POV file included within base *.cpp files
36 #include "base/configbase.h"
37 #include "base/types.h"
38 #include "base/povmscpp.h"
39 #include "base/fileinputoutput.h"
40 #include "base/stringutilities.h"
41 #include "base/textstream.h"
42 #include "base/povms.h"
43 #include "base/povmsgid.h"
44 #include "base/pov_err.h"
45 
46 #include "frontend/configfrontend.h"
47 #include "frontend/processrenderoptions.h"
48 
49 // this must be the last file included
50 #include "base/povdebug.h"
51 
52 namespace pov_frontend
53 {
54 
55 using namespace pov_base;
56 
57 /*****************************************************************************
58 * Local preprocessor defines
59 ******************************************************************************/
60 
61 #define kUseSpecialHandler   kPOVMSType_WildCard
62 #define kNoParameter         kPOVMSType_Null
63 
64 /*****************************************************************************
65 * Local variables
66 ******************************************************************************/
67 
68 #ifdef SYS_HAS_GRAYSCALE
69 #define SYS_GRAYSCALE_FLAG true
70 #else // SYS_HAS_GRAYSCALE
71 #define SYS_GRAYSCALE_FLAG false
72 #endif // SYS_HAS_GRAYSCALE
73 
74 #ifdef SYS_HAS_ALPHA
75 #define SYS_ALPHA_FLAG true
76 #else // SYS_HAS_ALPHA
77 #define SYS_ALPHA_FLAG false
78 #endif // SYS_HAS_ALPHA
79 
80 /*
81    Keyword table for the INI-file parser.
82    The parser converts the INI-file options into a POVMS object using
83    the specifications provided in this table. The first element is the
84    INI-file keyword, the second element is the POVMS object attribute
85    key, the third is the attribute type. Entries with a POVMS attribute
86    key of 0 are superceded options that will generate a warning that the
87    option no longer is supported and will generate an error in a later
88    (unspecified) version of POV.
89 */
90 struct ProcessOptions::INI_Parser_Table RenderOptions_INI_Table[] =
91 {
92 	{ "All_Console",         kPOVAttrib_AllConsole,         kPOVMSType_Bool },
93 	{ "All_File",            kPOVAttrib_AllFile,            kPOVMSType_UCS2String },
94 	{ "Antialias_Depth",     kPOVAttrib_AntialiasDepth,     kPOVMSType_Int },
95 	{ "Antialias",           kPOVAttrib_Antialias,          kPOVMSType_Bool },
96 	{ "Antialias_Threshold", kPOVAttrib_AntialiasThreshold, kPOVMSType_Float },
97 	{ "Antialias_Gamma",     kPOVAttrib_AntialiasGamma,     kPOVMSType_Float },
98 	{ "Append_File",         kPOVAttrib_AppendConsoleFiles, kPOVMSType_Bool },
99 
100 	{ "Bits_Per_Color",      kPOVAttrib_BitsPerColor,       kPOVMSType_Int },
101 	{ "Bits_Per_Colour",     kPOVAttrib_BitsPerColor,       kPOVMSType_Int },
102 	{ "Bounding",            kPOVAttrib_Bounding,           kPOVMSType_Bool },
103 	{ "Bounding_Method",     kPOVAttrib_BoundingMethod,     kPOVMSType_Int },
104 	{ "Bounding_Threshold",  kPOVAttrib_BoundingThreshold,  kPOVMSType_Int },
105 	{ "BSP_BaseAccessCost",  kPOVAttrib_BSP_BaseAccessCost, kPOVMSType_Float },
106 	{ "BSP_ChildAccessCost", kPOVAttrib_BSP_ChildAccessCost,kPOVMSType_Float },
107 	{ "BSP_ISectCost",       kPOVAttrib_BSP_ISectCost,      kPOVMSType_Float },
108 	{ "BSP_MaxDepth",        kPOVAttrib_BSP_MaxDepth,       kPOVMSType_Int },
109 	{ "BSP_MissChance",      kPOVAttrib_BSP_MissChance,     kPOVMSType_Float },
110 	{ "Buffer_Output",       0,                             0 },
111 	{ "Buffer_Size",         0,                             0 },
112 
113 	{ "Clock",               kPOVAttrib_Clock,              kPOVMSType_Float },
114 	{ "Clockless_Animation", kPOVAttrib_ClocklessAnimation, kPOVMSType_Bool },
115 	{ "Compression",         kPOVAttrib_Compression,        kPOVMSType_Int },
116 	{ "Continue_Trace",      kPOVAttrib_ContinueTrace,      kPOVMSType_Bool },
117 	{ "Create_Histogram",    0,                             0 },
118 	{ "Create_Ini",          kPOVAttrib_CreateIni,          kPOVMSType_UCS2String },
119 	{ "Cyclic_Animation",    kPOVAttrib_CyclicAnimation,    kPOVMSType_Bool },
120 
121 	{ "Debug_Console",       kPOVAttrib_DebugConsole,       kPOVMSType_Bool },
122 	{ "Debug_File",          kPOVAttrib_DebugFile,          kPOVMSType_UCS2String },
123 	{ "Declare",             kPOVAttrib_Declare,            kUseSpecialHandler },
124 	{ "Display",             kPOVAttrib_Display,            kPOVMSType_Bool },
125 	{ "Display_Gamma",       kPOVAttrib_DisplayGamma,       kUseSpecialHandler },
126 	{ "Dither",              kPOVAttrib_Dither,             kPOVMSType_Bool },
127 	{ "Dither_Method",       kPOVAttrib_DitherMethod,       kUseSpecialHandler },
128 	{ "Draw_Vistas",         kPOVAttrib_DrawVistas,         kPOVMSType_Bool },
129 
130 	{ "End_Column",          kPOVAttrib_Right,              kPOVMSType_Float },
131 	{ "End_Row",             kPOVAttrib_Bottom,             kPOVMSType_Float },
132 
133 	{ "Fatal_Console",       kPOVAttrib_FatalConsole,       kPOVMSType_Bool },
134 	{ "Fatal_Error_Command", kPOVAttrib_FatalErrorCommand,  kUseSpecialHandler },
135 	{ "Fatal_Error_Return",  kPOVAttrib_FatalErrorCommand,  kUseSpecialHandler },
136 	{ "Fatal_File",          kPOVAttrib_FatalFile,          kPOVMSType_UCS2String },
137 	{ "Field_Render",        kPOVAttrib_FieldRender,        kPOVMSType_Bool },
138 	{ "File_Gamma",          kPOVAttrib_FileGamma,          kUseSpecialHandler },
139 	{ "Final_Clock",         kPOVAttrib_FinalClock,         kPOVMSType_Float },
140 	{ "Final_Frame",         kPOVAttrib_FinalFrame,         kPOVMSType_Int },
141 	{ "Frame_Step",          kPOVAttrib_FrameStep,          kPOVMSType_Int },
142 
143 	{ "Grayscale_Output",    kPOVAttrib_GrayscaleOutput,    kPOVMSType_Bool },
144 
145 	{ "Height",              kPOVAttrib_Height,             kPOVMSType_Int },
146 	{ "High_Reproducibility",kPOVAttrib_HighReproducibility,kPOVMSType_Bool },
147 	{ "Histogram_Name",      0,                             0 },
148 	{ "Histogram_Grid_Size", 0,                             0 },
149 	{ "Histogram_Type",      0,                             0 },
150 
151 	{ "Initial_Clock",       kPOVAttrib_InitialClock,       kPOVMSType_Float },
152 	{ "Initial_Frame",       kPOVAttrib_InitialFrame,       kPOVMSType_Int },
153 	{ "Input_File_Name",     kPOVAttrib_InputFile,          kPOVMSType_UCS2String },
154 	{ "Include_Header",      kPOVAttrib_IncludeHeader,      kPOVMSType_UCS2String },
155 	{ "Include_Ini",         kPOVAttrib_IncludeIni,         kUseSpecialHandler },
156 
157 	{ "Jitter_Amount",       kPOVAttrib_JitterAmount,       kPOVMSType_Float },
158 	{ "Jitter",              kPOVAttrib_Jitter,             kPOVMSType_Bool },
159 
160 	{ "Library_Path",        kPOVAttrib_LibraryPath,        kUseSpecialHandler },
161 	{ "Light_Buffer",        kPOVAttrib_LightBuffer,        kPOVMSType_Bool },
162 
163 	{ "Max_Image_Buffer_Memory", kPOVAttrib_MaxImageBufferMem, kPOVMSType_Int },
164 
165 	{ "Odd_Field",           kPOVAttrib_OddField,           kPOVMSType_Bool },
166 	{ "Output_Alpha",        kPOVAttrib_OutputAlpha,        kPOVMSType_Bool },
167 	{ "Output_File_Name",    kPOVAttrib_OutputFile,         kPOVMSType_UCS2String },
168 	{ "Output_File_Type",    kPOVAttrib_OutputFileType,     kUseSpecialHandler },
169 	{ "Output_To_File",      kPOVAttrib_OutputToFile,       kPOVMSType_Bool },
170 
171 	{ "Palette",             kPOVAttrib_Palette,            kUseSpecialHandler },
172 	{ "Pause_When_Done",     kPOVAttrib_PauseWhenDone,      kPOVMSType_Bool },
173 	{ "Post_Frame_Command",  kPOVAttrib_PostFrameCommand,   kUseSpecialHandler },
174 	{ "Post_Frame_Return",   kPOVAttrib_PostFrameCommand,   kUseSpecialHandler },
175 	{ "Post_Scene_Command",  kPOVAttrib_PostSceneCommand,   kUseSpecialHandler },
176 	{ "Post_Scene_Return",   kPOVAttrib_PostSceneCommand,   kUseSpecialHandler },
177 	{ "Preview_End_Size",    kPOVAttrib_PreviewEndSize,     kPOVMSType_Int },
178 	{ "Preview_Start_Size",  kPOVAttrib_PreviewStartSize,   kPOVMSType_Int },
179 	{ "Pre_Frame_Command",   kPOVAttrib_PreFrameCommand,    kUseSpecialHandler },
180 	{ "Pre_Frame_Return",    kPOVAttrib_PreFrameCommand,    kUseSpecialHandler },
181 	{ "Pre_Scene_Command",   kPOVAttrib_PreSceneCommand,    kUseSpecialHandler },
182 	{ "Pre_Scene_Return",    kPOVAttrib_PreSceneCommand,    kUseSpecialHandler },
183 
184 	{ "Quality",             kPOVAttrib_Quality,            kPOVMSType_Int },
185 
186 	{ "Radiosity_File_Name", kPOVAttrib_RadiosityFileName,  kPOVMSType_UCS2String },
187 	{ "Radiosity_From_File", kPOVAttrib_RadiosityFromFile,  kPOVMSType_Bool },
188 	{ "Radiosity_To_File",   kPOVAttrib_RadiosityToFile,    kPOVMSType_Bool },
189 	{ "Radiosity_Vain_Pretrace", kPOVAttrib_RadiosityVainPretrace, kPOVMSType_Bool },
190 	{ "Real_Time_Raytracing",kPOVAttrib_RealTimeRaytracing, kPOVMSType_Bool },
191 	{ "Remove_Bounds",       kPOVAttrib_RemoveBounds,       kPOVMSType_Bool },
192 	{ "Render_Block_Size",   kPOVAttrib_RenderBlockSize,    kPOVMSType_Int },
193 	{ "Render_Block_Step",   kPOVAttrib_RenderBlockStep,    kPOVMSType_Int },
194 	{ "Render_Console",      kPOVAttrib_RenderConsole,      kPOVMSType_Bool },
195 	{ "Render_File",         kPOVAttrib_RenderFile,         kPOVMSType_UCS2String },
196 	{ "Render_Pattern",      kPOVAttrib_RenderPattern,      kPOVMSType_Int },
197 
198 	{ "Sampling_Method",     kPOVAttrib_SamplingMethod,     kPOVMSType_Int },
199 	{ "Split_Unions",        kPOVAttrib_SplitUnions,        kPOVMSType_Bool },
200 	{ "Start_Column",        kPOVAttrib_Left,               kPOVMSType_Float },
201 	{ "Start_Row",           kPOVAttrib_Top,                kPOVMSType_Float },
202 	{ "Statistic_Console",   kPOVAttrib_StatisticsConsole,  kPOVMSType_Bool },
203 	{ "Statistic_File",      kPOVAttrib_StatisticsFile,     kPOVMSType_UCS2String },
204 	{ "Subset_End_Frame",    kPOVAttrib_SubsetEndFrame,     kPOVMSType_Float },
205 	{ "Subset_Start_Frame",  kPOVAttrib_SubsetStartFrame,   kPOVMSType_Float },
206 
207 	{ "Test_Abort_Count",    kPOVAttrib_TestAbortCount,     kPOVMSType_Int },
208 	{ "Test_Abort",          kPOVAttrib_TestAbort,          kPOVMSType_Bool },
209 
210 	{ "User_Abort_Command",  kPOVAttrib_UserAbortCommand,   kUseSpecialHandler },
211 	{ "User_Abort_Return",   kPOVAttrib_UserAbortCommand,   kUseSpecialHandler },
212 
213 	{ "Verbose",             kPOVAttrib_Verbose,            kPOVMSType_Bool },
214 	{ "Version",             kPOVAttrib_Version,            kPOVMSType_Float },
215 	{ "Video_Mode",          kPOVAttrib_VideoMode,          kUseSpecialHandler },
216 	{ "Vista_Buffer",        kPOVAttrib_VistaBuffer,        kPOVMSType_Bool },
217 
218 	{ "Warning_Console",     kPOVAttrib_WarningConsole,     kPOVMSType_Bool },
219 	{ "Warning_File",        kPOVAttrib_WarningFile,        kPOVMSType_UCS2String },
220 	{ "Warning_Level",       kPOVAttrib_WarningLevel,       kPOVMSType_Int },
221 	{ "Width",               kPOVAttrib_Width,              kPOVMSType_Int },
222 	{ "Work_Threads",        kPOVAttrib_MaxRenderThreads,   kPOVMSType_Int },
223 
224 	{ NULL, 0, 0 }
225 };
226 
227 /*
228    Keyword table for the command line parser.
229    The parser converts the command line options into a POVMS object using
230    the specifications provided in this table. The first element is the
231    command keyword, the second element is the POVMS object attribute key
232    of the parameter, the third is the attribute type and the last specifies
233    if the +/- switch is used as boolean parameter if an attribute key is
234    provided.
235 */
236 struct ProcessOptions::Cmd_Parser_Table RenderOptions_Cmd_Table[] =
237 {
238 	{ "AG",  kPOVAttrib_AntialiasGamma,     kPOVMSType_Float,       kNoParameter },
239 	{ "AM",  kPOVAttrib_SamplingMethod,     kPOVMSType_Int,         kNoParameter },
240 	{ "A0",  kPOVAttrib_AntialiasThreshold, kPOVMSType_Float,       kPOVAttrib_Antialias },
241 	{ "A",   kNoParameter,                  kNoParameter,           kPOVAttrib_Antialias },
242 
243 	{ "BM",  kPOVAttrib_BoundingMethod,     kPOVMSType_Int,         kNoParameter },
244 	{ "BS",  kPOVAttrib_RenderBlockSize,    kPOVMSType_Int,         kNoParameter },
245 	{ "B",   kNoParameter,                  kNoParameter,           kPOVAttrib_Bounding },
246 
247 	{ "C",   kNoParameter,                  kNoParameter,           kPOVAttrib_ContinueTrace },
248 
249 	{ "D",   kPOVAttrib_Display,            kUseSpecialHandler,     kPOVAttrib_Display },
250 	{ "D",   kNoParameter,                  kNoParameter,           kPOVAttrib_Display },
251 
252 	{ "EC",  kPOVAttrib_Right,              kPOVMSType_Float,       kNoParameter },
253 	{ "EF0", kPOVAttrib_SubsetEndFrame,     kPOVMSType_Float,       kNoParameter },
254 	{ "EF",  kPOVAttrib_SubsetEndFrame,     kPOVMSType_Int,         kNoParameter },
255 	{ "EP",  kPOVAttrib_PreviewEndSize,     kPOVMSType_Int,         kNoParameter },
256 	{ "ER",  kPOVAttrib_Bottom,             kPOVMSType_Float,       kNoParameter },
257 
258 	{ "F",   kPOVAttrib_OutputFileType,     kUseSpecialHandler,     kPOVAttrib_OutputToFile },
259 	{ "F",   kNoParameter,                  kNoParameter,           kPOVAttrib_OutputToFile },
260 
261 	{ "GA",  kPOVAttrib_AllFile,            kPOVMSType_UCS2String,  kPOVAttrib_AllConsole },
262 	{ "GA",  kNoParameter,                  kNoParameter,           kPOVAttrib_AllConsole },
263 	{ "GD",  kPOVAttrib_DebugFile,          kPOVMSType_UCS2String,  kPOVAttrib_DebugConsole },
264 	{ "GD",  kNoParameter,                  kNoParameter,           kPOVAttrib_DebugConsole },
265 	{ "GF",  kPOVAttrib_FatalFile,          kPOVMSType_UCS2String,  kPOVAttrib_FatalConsole },
266 	{ "GF",  kNoParameter,                  kNoParameter,           kPOVAttrib_FatalConsole },
267 	{ "GI",  kPOVAttrib_CreateIni,          kPOVMSType_UCS2String,  kNoParameter },
268 	{ "GP",  kNoParameter,                  kNoParameter,           kPOVAttrib_AppendConsoleFiles },
269 	{ "GR",  kPOVAttrib_RenderFile,         kPOVMSType_UCS2String,  kPOVAttrib_RenderConsole },
270 	{ "GR",  kNoParameter,                  kNoParameter,           kPOVAttrib_RenderConsole },
271 	{ "GS",  kPOVAttrib_StatisticsFile,     kPOVMSType_UCS2String,  kPOVAttrib_StatisticsConsole },
272 	{ "GS",  kNoParameter,                  kNoParameter,           kPOVAttrib_StatisticsConsole },
273 	{ "GW",  kPOVAttrib_WarningFile,        kPOVMSType_UCS2String,  kPOVAttrib_WarningConsole },
274 	{ "GW",  kNoParameter,                  kNoParameter,           kPOVAttrib_WarningConsole },
275 
276 	{ "HI",  kPOVAttrib_IncludeHeader,      kPOVMSType_UCS2String,  kNoParameter },
277 	{ "HR",  kNoParameter,                  kNoParameter,           kPOVAttrib_HighReproducibility },
278 	{ "H",   kPOVAttrib_Height,             kPOVMSType_Int,         kNoParameter },
279 
280 	{ "I",   kPOVAttrib_InputFile,          kPOVMSType_UCS2String,  kNoParameter },
281 
282 	{ "J",   kPOVAttrib_JitterAmount,       kPOVMSType_Float,       kPOVAttrib_Jitter },
283 	{ "J",   kNoParameter,                  kNoParameter,           kPOVAttrib_Jitter },
284 
285 	{ "KC",  kNoParameter,                  kNoParameter,           kPOVAttrib_CyclicAnimation },
286 	{ "KI",  kPOVAttrib_InitialClock,       kPOVMSType_Float,       kNoParameter },
287 	{ "KFF", kPOVAttrib_FinalFrame,         kPOVMSType_Int,         kNoParameter },
288 	{ "KFI", kPOVAttrib_InitialFrame,       kPOVMSType_Int,         kNoParameter },
289 	{ "KF",  kPOVAttrib_FinalClock,         kPOVMSType_Float,       kNoParameter },
290 	{ "KLA", kNoParameter,                  kNoParameter,           kPOVAttrib_ClocklessAnimation },
291 	{ "K",   kPOVAttrib_Clock,              kPOVMSType_Float,       kNoParameter },
292 
293 	{ "L",   kPOVAttrib_LibraryPath,        kUseSpecialHandler,     kNoParameter },
294 
295 	{ "MB",  kPOVAttrib_BoundingThreshold,  kPOVMSType_Int,         kPOVAttrib_Bounding },
296 	{ "MB",  kNoParameter,                  kNoParameter,           kPOVAttrib_Bounding },
297 	{ "MI",  kPOVAttrib_MaxImageBufferMem,  kPOVMSType_Int,         kNoParameter },
298 	{ "MV",  kPOVAttrib_Version,            kPOVMSType_Float,       kNoParameter },
299 
300 	{ "O",   kPOVAttrib_OutputFile,         kPOVMSType_UCS2String,  kNoParameter },
301 
302 	{ "P",   kNoParameter,                  kNoParameter,           kPOVAttrib_PauseWhenDone },
303 
304 	{ "Q",   kPOVAttrib_Quality,            kPOVMSType_Int,         kNoParameter },
305 
306 	{ "RFI", kNoParameter,                  kNoParameter,           kPOVAttrib_RadiosityFromFile },
307 	{ "RFO", kNoParameter,                  kNoParameter,           kPOVAttrib_RadiosityToFile },
308 	{ "RF",  kPOVAttrib_RadiosityFileName,  kPOVMSType_UCS2String,  kNoParameter },
309 	{ "RS",  kPOVAttrib_RenderBlockStep,    kPOVMSType_Int,         kNoParameter },
310 	{ "RP",  kPOVAttrib_RenderPattern,      kPOVMSType_Int,         kNoParameter },
311 	{ "RTR", kNoParameter,                  kNoParameter,           kPOVAttrib_RealTimeRaytracing },
312 	{ "RVP", kNoParameter,                  kNoParameter,           kPOVAttrib_RadiosityVainPretrace },
313 	{ "R",   kPOVAttrib_AntialiasDepth,     kPOVMSType_Int,         kNoParameter },
314 
315 	{ "SC",  kPOVAttrib_Left,               kPOVMSType_Float,       kNoParameter },
316 	{ "SF0", kPOVAttrib_SubsetStartFrame,   kPOVMSType_Float,       kNoParameter },
317 	{ "SF",  kPOVAttrib_SubsetStartFrame,   kPOVMSType_Int,         kNoParameter },
318 	{ "SP",  kPOVAttrib_PreviewStartSize,   kPOVMSType_Int,         kNoParameter },
319 	{ "SR",  kPOVAttrib_Top,                kPOVMSType_Float,       kNoParameter },
320 	{ "STP", kPOVAttrib_FrameStep,          kPOVMSType_Int,         kNoParameter },
321 	{ "SU",  kNoParameter,                  kNoParameter,           kPOVAttrib_SplitUnions },
322 
323 	{ "TH",  kPOVAttrib_DitherMethod,       kUseSpecialHandler,     kPOVAttrib_Dither },
324 	{ "TH",  kNoParameter,                  kNoParameter,           kPOVAttrib_Dither },
325 
326 	{ "UA",  kNoParameter,                  kNoParameter,           kPOVAttrib_OutputAlpha },
327 	{ "UD",  kNoParameter,                  kNoParameter,           kPOVAttrib_DrawVistas },
328 	{ "UF",  kNoParameter,                  kNoParameter,           kPOVAttrib_FieldRender },
329 	{ "UL",  kNoParameter,                  kNoParameter,           kPOVAttrib_LightBuffer },
330 	{ "UO",  kNoParameter,                  kNoParameter,           kPOVAttrib_OddField },
331 	{ "UR",  kNoParameter,                  kNoParameter,           kPOVAttrib_RemoveBounds },
332 	{ "UV",  kNoParameter,                  kNoParameter,           kPOVAttrib_VistaBuffer },
333 
334 	{ "V",   kNoParameter,                  kNoParameter,           kPOVAttrib_Verbose },
335 
336 	{ "WL",  kPOVAttrib_WarningLevel,       kPOVMSType_Int,         kNoParameter },
337 	{ "WT",  kPOVAttrib_MaxRenderThreads,   kPOVMSType_Int,         kNoParameter },
338 	{ "W",   kPOVAttrib_Width,              kPOVMSType_Int,         kNoParameter },
339 
340 	{ "X",   kPOVAttrib_TestAbortCount,     kUseSpecialHandler,     kPOVAttrib_TestAbort },
341 	{ "X",   kNoParameter,                  kNoParameter,           kPOVAttrib_TestAbort },
342 
343 	{ NULL, 0, 0, 0 }
344 };
345 
346 // TODO FIXME - The following are hacks of some sort, no idea what they are good for. They certainly use wrong types and probably contain other mistakes [trf]
347 extern struct ProcessRenderOptions::Parameter_Code_Table DitherMethodTable[];
348 
ProcessRenderOptions()349 ProcessRenderOptions::ProcessRenderOptions() : ProcessOptions(RenderOptions_INI_Table, RenderOptions_Cmd_Table)
350 {
351 }
352 
~ProcessRenderOptions()353 ProcessRenderOptions::~ProcessRenderOptions()
354 {
355 }
356 
ReadSpecialOptionHandler(INI_Parser_Table * option,char * param,POVMSObjectPtr obj)357 int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, char *param, POVMSObjectPtr obj)
358 {
359 	POVMSAttributeList list;
360 	double floatval = 0.0;
361 	int intval = 0;
362 	int intval2 = 0;
363 	int err = kNoErr;
364 
365 	switch(option->key)
366 	{
367 		case kPOVAttrib_Palette:
368 		case kPOVAttrib_VideoMode:
369 			while(isspace(*param))
370 				param++;
371 			err = POVMSUtil_SetInt(obj, option->key, tolower(*param));
372 			break;
373 		case kPOVAttrib_DitherMethod:
374 			while(isspace(*param))
375 				param++;
376 			err = ParseParameterCode(DitherMethodTable, param, &intval);
377 			if (err == kNoErr)
378 				err = POVMSUtil_SetInt(obj, option->key, intval);
379 			else
380 				ParseError("Unrecognized dither method '%s'.", param);
381 			break;
382 		case kPOVAttrib_OutputFileType:
383 			while(isspace(*param))
384 				param++;
385 			err = ParseFileType(*param, option->key, &intval);
386 			if (err == kNoErr)
387 				err = POVMSUtil_SetInt(obj, option->key, intval);
388 			break;
389 		case kPOVAttrib_IncludeIni:
390 		case kPOVAttrib_LibraryPath:
391 			POVMSAttribute attr;
392 
393 			if(err == kNoErr)
394 			{
395 				// parse INI file (recursive)
396 				if(option->key == kPOVAttrib_IncludeIni)
397 					err = ParseFile(param, obj);
398 
399 				// create list if it isn't there
400 				if(err == kNoErr)
401 				{
402 					if(POVMSObject_Exist(obj, option->key) == kFalseErr)
403 						err = POVMSAttrList_New(&list);
404 					else if(POVMSObject_Exist(obj, option->key) != kNoErr)
405 						err = kObjectAccessErr;
406 					else
407 						err = POVMSObject_Get(obj, &list, option->key);
408 				}
409 			}
410 			else
411 			{
412 				ParseError("File name or path parameter expected for option '%s', found '%s'.", option->keyword, param);
413 				err = kParamErr;
414 			}
415 
416 			// add path or file to list
417 			if(err == kNoErr)
418 				err = POVMSAttr_New(&attr);
419 			if(err == kNoErr)
420 			{
421 				err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, param);
422 				if(err == kNoErr)
423 					err = POVMSAttrList_Append(&list, &attr);
424 				else
425 					err = POVMSAttr_Delete(&attr);
426 			}
427 			if(err == kNoErr)
428 				err = POVMSObject_Set(obj, &list, option->key);
429 			break;
430 		case kPOVAttrib_Declare:
431 			POVMSObject decobj;
432 
433 			// create list if it isn't there
434 			if(POVMSObject_Exist(obj, option->key) == kFalseErr)
435 				err = POVMSAttrList_New(&list);
436 			else if(POVMSObject_Exist(obj, option->key) != kNoErr)
437 				err = kObjectAccessErr;
438 			else
439 				err = POVMSObject_Get(obj, &list, option->key);
440 
441 			// add value to list
442 			if(err == kNoErr)
443 				err = POVMSObject_New(&decobj, kPOVMSType_WildCard);
444 			if(err == kNoErr)
445 			{
446 				char *ptr = NULL;
447 
448 				err = POVMSUtil_SetString(&decobj, kPOVAttrib_Identifier, strtok(param, "="));
449 				if(err == kNoErr)
450 				{
451 					ptr = strtok(NULL, "");
452 					if(ptr == NULL)
453 						err = kParseErr;
454 				}
455 				if(err == kNoErr)
456 				{
457 					if(strchr(ptr, '"') != NULL)
458 					{
459 						ptr = strchr(ptr, '"') + 1;
460 						strtok(ptr, "\"");
461 						err = POVMSUtil_SetString(&decobj, kPOVAttrib_Value, ptr);
462 					}
463 					else
464 						err = POVMSUtil_SetFloat(&decobj, kPOVAttrib_Value, std::atof(ptr));
465 				}
466 				if(err == kNoErr)
467 					err = POVMSAttrList_Append(&list, &decobj);
468 				else
469 					err = POVMSObject_Delete(&decobj);
470 			}
471 			if(err == kNoErr)
472 				err = POVMSObject_Set(obj, &list, option->key);
473 			break;
474 		case kPOVAttrib_FatalErrorCommand:
475 		case kPOVAttrib_PostFrameCommand:
476 		case kPOVAttrib_PostSceneCommand:
477 		case kPOVAttrib_PreFrameCommand:
478 		case kPOVAttrib_PreSceneCommand:
479 		case kPOVAttrib_UserAbortCommand:
480 			POVMSObject cmdobj;
481 
482 			if(POVMSObject_Exist(obj, option->key) == kNoErr)
483 				err = POVMSObject_Get(obj, &cmdobj, option->key);
484 			else
485 				err = POVMSObject_New(&cmdobj, kPOVMSType_WildCard);
486 			if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
487 			{
488 				if(err == kNoErr)
489 					err = POVMSUtil_SetString(&cmdobj, kPOVAttrib_CommandString, param);
490 			}
491 			else
492 			{
493 				if(err == kNoErr)
494 				{
495 					int i = 0;
496 
497 					if((*param == '-') || (*param == '!'))
498 						i = toupper(*(param + 1)); // use upper-case to indicate negation of process result
499 					else
500 						i = tolower(*param); // lower-case for normal interpretation of process result
501 					err = POVMSUtil_SetInt(&cmdobj, kPOVAttrib_ReturnAction, i);
502 				}
503 			}
504 			if(err == kNoErr)
505 				err = POVMSObject_Set(obj, &cmdobj, option->key);
506 			break;
507 		case kPOVAttrib_AntialiasGamma:
508 		case kPOVAttrib_DisplayGamma:
509 		case kPOVAttrib_FileGamma:
510 			POVMSType typeKey;
511 			switch (option->key)
512 			{
513 				case kPOVAttrib_AntialiasGamma:  typeKey = kPOVAttrib_AntialiasGammaType;    break;
514 				case kPOVAttrib_DisplayGamma:    typeKey = kPOVAttrib_DisplayGammaType;      break;
515 				case kPOVAttrib_FileGamma:       typeKey = kPOVAttrib_FileGammaType;         break;
516 			}
517 			floatval = std::atof(param);
518 			if (floatval == 1.0)
519 				intval = kPOVList_GammaType_Neutral;
520 			else if (floatval > 0)
521 				intval = kPOVList_GammaType_PowerLaw;
522 			else
523 				err = ParseGammaType(param, &intval);
524 
525 			if (err == kNoErr)
526 				err = POVMSUtil_SetFloat(obj, option->key, fabs(floatval));
527 			if (err == kNoErr)
528 				err = POVMSUtil_SetInt(obj, typeKey, intval);
529 			break;
530 	}
531 
532 	return err;
533 }
534 
ReadSpecialSwitchHandler(Cmd_Parser_Table * option,char * param,POVMSObjectPtr obj,bool)535 int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, char *param, POVMSObjectPtr obj, bool)
536 {
537 	int intval = 0;
538 	int intval2 = 0;
539 	int err = 0;
540 	char chr = 0;
541 	char file_type;
542 	bool has16BitGrayscale;
543 
544 	switch(option->key)
545 	{
546 		case kPOVAttrib_Display:
547 			if(param[0] != '\0')
548 			{
549 				err = POVMSUtil_SetInt(obj, kPOVAttrib_VideoMode, (int)toupper(param[0]));
550 				if((param[1] != '\0') && (err == 0))
551 					err = POVMSUtil_SetInt(obj, kPOVAttrib_Palette, (int)toupper(param[1]));
552 			}
553 			break;
554 		case kPOVAttrib_DitherMethod:
555 			err = ParseParameterCode(DitherMethodTable, param, &intval);
556 			if (err == kNoErr)
557 				err = POVMSUtil_SetInt(obj, option->key, intval);
558 			else
559 				ParseError("Unrecognized dither method '%s'.", param);
560 			break;
561 		case kPOVAttrib_OutputFileType:
562 			err = ParseFileType(*param, option->key, &intval, &has16BitGrayscale);
563 			if (err == kNoErr)
564 			{
565 				err = POVMSUtil_SetInt(obj, option->key, intval);
566 				file_type = *param++;
567 			}
568 			if ((err == kNoErr) && (*param > ' '))
569 			{
570 				if (tolower(*param) == 'g')
571 				{
572 					if(!has16BitGrayscale)
573 					{
574 						ParseError("Grayscale not currently supported with output file format '%c'.", file_type);
575 						err = kParamErr;
576 					}
577 					else
578 					{
579 						if ((err = POVMSUtil_SetBool(obj, kPOVAttrib_GrayscaleOutput, true)) == kNoErr && *++param > ' ')
580 						{
581 							ParseError("Unexpected '%s' following grayscale flag in +F%c option.", param, file_type);
582 							err = kParamErr;
583 						}
584 					}
585 				}
586 				else if (isdigit(*param) != 0)
587 				{
588 					if (sscanf(param, "%d%n", &intval, &intval2) == 1)
589 					{
590 						if ((err = POVMSUtil_SetInt(obj, kPOVAttrib_BitsPerColor, intval)) == kNoErr)
591 						{
592 							param += intval2;
593 							if (*param > ' ')
594 							{
595 								ParseError("Unexpected '%s' following bits per color in +F%c option.", param, file_type);
596 								err = kParamErr;
597 							}
598 						}
599 					}
600 					else
601 					{
602 						ParseError("Invalid bits per color '%s' found in +F%c option.", param, file_type);
603 						err = kParamErr;
604 					}
605 				}
606 				else
607 				{
608 					ParseError("Invalid modifier '%s' following +F%c option.", param, file_type);
609 					err = kParamErr;
610 				}
611 			}
612 			break;
613 		case kPOVAttrib_LibraryPath:
614 			POVMSAttributeList list;
615 			POVMSAttribute attr;
616 
617 			if(err == kNoErr)
618 			{
619 				// create list if it isn't there
620 				if(POVMSObject_Exist(obj, option->key) == kFalseErr)
621 					err = POVMSAttrList_New(&list);
622 				else if(POVMSObject_Exist(obj, option->key) != kNoErr)
623 					err = kObjectAccessErr;
624 				else
625 					err = POVMSObject_Get(obj, &list, option->key);
626 			}
627 			else
628 			{
629 				ParseError("File name or path parameter expected for switch '%s', found '%s'.", option->command, param);
630 				err = kParamErr;
631 			}
632 
633 			// add path or file to list
634 			if(err == kNoErr)
635 				err = POVMSAttr_New(&attr);
636 			if(err == kNoErr)
637 			{
638 				err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, param);
639 				if(err == kNoErr)
640 					err = POVMSAttrList_Append(&list, &attr);
641 				else
642 					err = POVMSAttr_Delete(&attr);
643 			}
644 			if(err == kNoErr)
645 				err = POVMSObject_Set(obj, &list, option->key);
646 			break;
647 		case kPOVAttrib_TestAbortCount:
648 			if((*param) == 0)
649 				break;
650 			if(sscanf(param, "%d", &intval) == 1)
651 				err = POVMSUtil_SetInt(obj, option->key, intval);
652 			else
653 			{
654 				ParseError("No or integer parameter expected for switch '%s', found '%s'.", option->command, param);
655 				err = kParamErr;
656 			}
657 			break;
658 	}
659 
660 	return err;
661 }
662 
WriteSpecialOptionHandler(INI_Parser_Table * option,POVMSObjectPtr obj,OTextStream * file)663 int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, POVMSObjectPtr obj, OTextStream *file)
664 {
665 	POVMSAttributeList list;
666 	POVMSFloat floatval;
667 	POVMSInt intval;
668 	int err = 0;
669 	int l;
670 	int i,imax;
671 	POVMSAttribute item;
672 	char *bufptr;
673 	char chr;
674 
675 	switch(option->key)
676 	{
677 		case kPOVAttrib_Palette:
678 		case kPOVAttrib_VideoMode:
679 			if(POVMSUtil_GetInt(obj, option->key, &intval) == 0)
680 			{
681 				chr = intval;
682 				if(chr > 32)
683 					file->printf("%s=%c\n", option->keyword, chr);
684 			}
685 			break;
686 		case kPOVAttrib_OutputFileType:
687 			if(POVMSUtil_GetInt(obj, option->key, &intval) == 0)
688 			{
689 				chr = UnparseFileType(intval);
690 				if(chr > 32)
691 					file->printf("%s=%c\n", option->keyword, chr);
692 			}
693 			break;
694 		case kPOVAttrib_IncludeIni:
695 			break;
696 		case kPOVAttrib_Declare:
697 			POVMSObject decobj;
698 
699 			err = POVMSObject_Get(obj, &list, option->key);
700 			if(err != 0)
701 				break;
702 
703 			l = 0;
704 			err = POVMSAttrList_Count(&list, &l);
705 			if(err != 0)
706 				break;
707 			if(l == 0)
708 				break;
709 
710 			imax = l;
711 			for(i = 1; i <= imax; i++)
712 			{
713 				err = POVMSAttrList_GetNth(&list, i, &decobj);
714 				if(err == 0)
715 					err = POVMSObject_Get(&decobj, &item, kPOVAttrib_Identifier);
716 				if(err == 0)
717 				{
718 					l = 0;
719 					err = POVMSAttr_Size(&item, &l);
720 					if(l > 0)
721 					{
722 						bufptr = new char[l];
723 						bufptr[0] = 0;
724 						if((POVMSUtil_GetFloat(&decobj, kPOVAttrib_Value, &floatval) == 0) &&
725 						   (POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0))
726 							file->printf("%s=%s=%g\n", option->keyword, bufptr, (float)floatval);
727 						delete[] bufptr;
728 					}
729 					(void)POVMSAttr_Delete(&item);
730 				}
731 			}
732 			break;
733 		case kPOVAttrib_LibraryPath:
734 			err = POVMSObject_Get(obj, &list, option->key);
735 			if(err != 0)
736 				break;
737 
738 			l = 0;
739 			err = POVMSAttrList_Count(&list, &l);
740 			if(err != 0)
741 				break;
742 			if(l == 0)
743 				break;
744 
745 			imax = l;
746 			for(i = 1; i <= imax; i++)
747 			{
748 				err = POVMSAttrList_GetNth(&list, i, &item);
749 				if(err == 0)
750 				{
751 					l = 0;
752 					err = POVMSAttr_Size(&item, &l);
753 					if(l > 0)
754 					{
755 						bufptr = new char[l * 3];
756 						bufptr[0] = 0;
757 						if(POVMSAttr_GetUTF8String(&item, kPOVMSType_UCS2String, bufptr, &l) == 0)
758 							file->printf("%s=\"%s\"\n", option->keyword, bufptr);
759 						delete[] bufptr;
760 					}
761 					(void)POVMSAttr_Delete(&item);
762 				}
763 			}
764 			break;
765 		case kPOVAttrib_FatalErrorCommand:
766 		case kPOVAttrib_PostFrameCommand:
767 		case kPOVAttrib_PostSceneCommand:
768 		case kPOVAttrib_PreFrameCommand:
769 		case kPOVAttrib_PreSceneCommand:
770 		case kPOVAttrib_UserAbortCommand:
771 			POVMSObject cmdobj;
772 
773 			err = POVMSObject_Get(obj, &cmdobj, option->key);
774 			if(err != 0)
775 				break;
776 
777 			err = POVMSObject_Get(&cmdobj, &item, kPOVAttrib_CommandString);
778 			if(err == 0)
779 			{
780 				if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
781 				{
782 					l = 0;
783 					err = POVMSAttr_Size(&item, &l);
784 					if(l > 0)
785 					{
786 						bufptr = new char[l];
787 						bufptr[0] = 0;
788 						if(POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0)
789 							file->printf("%s=%s\n", option->keyword, bufptr);
790 						delete[] bufptr;
791 					}
792 				}
793 				else
794 				{
795 					if(POVMSUtil_GetInt(&cmdobj, kPOVAttrib_ReturnAction, &intval) == 0)
796 					{
797 						if(intval < 0)
798 						{
799 							chr = -intval;
800 							file->printf("%s=!%c\n", option->keyword, chr);
801 						}
802 						else
803 						{
804 							chr = intval;
805 							file->printf("%s=%c\n", option->keyword, chr);
806 						}
807 					}
808 				}
809 			}
810 			if(err == 0)
811 				err = POVMSObject_Delete(&cmdobj);
812 			break;
813 	}
814 
815 	return err;
816 }
817 
WriteOptionFilter(INI_Parser_Table * table)818 bool ProcessRenderOptions::WriteOptionFilter(INI_Parser_Table *table)
819 {
820 	// So that we don't get both Bits_Per_Color and Bits_Per_Colour in the INI file.
821 	return (strcmp(table->keyword, "Bits_Per_Colour") != 0);
822 }
823 
ProcessUnknownString(char * str,POVMSObjectPtr obj)824 int ProcessRenderOptions::ProcessUnknownString(char *str, POVMSObjectPtr obj)
825 {
826 	POVMSAttributeList list;
827 	POVMSAttribute attr;
828 	int state = 0; // INI file
829 	int err = kNoErr;
830 
831 	if(str == NULL)
832 	{
833 		ParseError("Expected filename, nothing was found.");
834 		return kParamErr;
835 	}
836 
837 	// add filename or path
838 
839 	// see if it is a POV file
840 	if(state == 0)
841 	{
842 		char *ptr = strrchr(str, '.');
843 		if(ptr != NULL)
844 		{
845 			if(pov_stricmp(ptr, ".pov") == 0)
846 				state = 1; // POV file
847 		}
848 	}
849 
850 	// see if it is a path
851 	if(state == 0)
852 	{
853 		if(strlen(str) > 0)
854 		{
855 			if(str[strlen(str) - 1] == POV_FILE_SEPARATOR)
856 				state = 2; // library path
857 #ifdef POV_FILE_SEPARATOR_2
858 			else if(str[strlen(str) - 1] == POV_FILE_SEPARATOR_2)
859 				state = 2; // library path
860 #endif
861 		}
862 	}
863 
864 	switch(state)
865 	{
866 		// INI file
867 		case 0:
868 			// parse INI file (recursive)
869 			err = ParseFile(str, obj);
870 			if(err == kNoErr)
871 			{
872 				// create list if it isn't there
873 				if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) == kFalseErr)
874 					err = POVMSAttrList_New(&list);
875 				else if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) != kNoErr)
876 					err = kObjectAccessErr;
877 				else
878 					err = POVMSObject_Get(obj, &list, kPOVAttrib_IncludeIni);
879 			}
880 
881 			// add INI file to list
882 			if(err == kNoErr)
883 				err = POVMSAttr_New(&attr);
884 			if(err == kNoErr)
885 			{
886 				err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, str);
887 				if(err == kNoErr)
888 					err = POVMSAttrList_Append(&list, &attr);
889 				else
890 					err = POVMSAttr_Delete(&attr);
891 			}
892 			if(err == kNoErr)
893 				err = POVMSObject_Set(obj, &list, kPOVAttrib_IncludeIni);
894 			break;
895 		// POV file
896 		case 1:
897 			// set POV file
898 			err = POVMSUtil_SetUTF8String(obj, kPOVAttrib_InputFile, str);
899 			break;
900 		// library path
901 		case 2:
902 			// create list if it isn't there
903 			if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) == kFalseErr)
904 				err = POVMSAttrList_New(&list);
905 			else if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) != kNoErr)
906 				err = kObjectAccessErr;
907 			else
908 				err = POVMSObject_Get(obj, &list, kPOVAttrib_LibraryPath);
909 
910 			// add library path to list
911 			if(err == kNoErr)
912 				err = POVMSAttr_New(&attr);
913 			if(err == kNoErr)
914 			{
915 				err = POVMSAttr_SetUTF8String(&attr, kPOVMSType_UCS2String, str);
916 				if(err == kNoErr)
917 					err = POVMSAttrList_Append(&list, &attr);
918 				else
919 					err = POVMSAttr_Delete(&attr);
920 			}
921 			if(err == kNoErr)
922 				err = POVMSObject_Set(obj, &list, kPOVAttrib_LibraryPath);
923 			break;
924 	}
925 
926 	return err;
927 }
928 
OpenFileForRead(const char * filename,POVMSObjectPtr obj)929 ITextStream *ProcessRenderOptions::OpenFileForRead(const char *filename, POVMSObjectPtr obj)
930 {
931 	return OpenINIFileStream(filename, pov_base::POV_File_Text_INI, obj);
932 }
933 
OpenFileForWrite(const char * filename,POVMSObjectPtr)934 OTextStream *ProcessRenderOptions::OpenFileForWrite(const char *filename, POVMSObjectPtr)
935 {
936 	return new OTextStream(ASCIItoUCS2String(filename).c_str(), pov_base::POV_File_Text_INI);
937 }
938 
OpenINIFileStream(const char * filename,unsigned int stype,POVMSObjectPtr obj)939 ITextStream *ProcessRenderOptions::OpenINIFileStream(const char *filename, unsigned int stype, POVMSObjectPtr obj) // TODO FIXME - Use new Path class!
940 {
941 	// TODO FIXME - we should join forces with SceneData::FindFile()
942 	// TODO FIXME - use proper C++ strings instead of C character arrays
943 
944 	int i,ii,l[POV_FILE_EXTENSIONS_PER_TYPE];
945 	char pathname[1024];
946 	char file[1024];
947 	char file_x[POV_FILE_EXTENSIONS_PER_TYPE][1024];
948 	int cnt = 0;
949 	int ll;
950 	POVMSAttribute attr, item;
951 	const char *xstr = strrchr(filename, '.');
952 	bool hasextension = ((xstr != NULL) && (strlen(xstr) <= 4)); // TODO FIXME - we shouldn't rely on extensions being at most 1+3 chars long
953 
954 	if(POV_ALLOW_FILE_READ(ASCIItoUCS2String(filename).c_str(),stype) == 0) // TODO FIXME - Remove dependency on this macro!!! [trf]
955 		return NULL;
956 
957 	for(i = 0; i < POV_FILE_EXTENSIONS_PER_TYPE; i++)
958 	{
959 		if((l[i] = strlen(pov::gPOV_File_Extensions[stype].ext[i])) > 0)
960 		{
961 			strcpy(file_x[i], filename);
962 			strcat(file_x[i], pov::gPOV_File_Extensions[stype].ext[i]);
963 		}
964 	}
965 
966 	// Check the current directory first
967 
968 	if((hasextension == true) && (CheckIfFileExists(filename) == true))
969 	{
970 		return new ITextStream(ASCIItoUCS2String(filename).c_str(), stype);
971 	}
972 
973 	for(i = 0; i < POV_FILE_EXTENSIONS_PER_TYPE; i++)
974 	{
975 		if(l[i])
976 		{
977 			if(CheckIfFileExists(file_x[i]) == true)
978 			{
979 				return new ITextStream(ASCIItoUCS2String(file_x[i]).c_str(), stype);
980 			}
981 		}
982 	}
983 
984 	if(POVMSObject_Get(obj, &attr, kPOVAttrib_LibraryPath) != 0)
985 		return NULL;
986 
987 	if(POVMSAttrList_Count(&attr, &cnt) != 0)
988 	{
989 		(void)POVMSAttrList_Delete(&attr);
990 		return NULL;
991 	}
992 
993 	for (i = 1; i <= cnt; i++)
994 	{
995 		(void)POVMSAttr_New(&item);
996 		if(POVMSAttrList_GetNth(&attr, i, &item) != 0)
997 			continue;
998 		ll = 0;
999 		if(POVMSAttr_Size(&item, &ll) != 0)
1000 		{
1001 			(void)POVMSAttr_Delete(&item);
1002 			continue;
1003 		}
1004 		if(ll <= 0)
1005 		{
1006 			(void)POVMSAttr_Delete(&item);
1007 			continue;
1008 		}
1009 		if(POVMSAttr_GetUTF8String(&item, kPOVMSType_UCS2String, file, &ll) != 0) // TODO FIXME!!!
1010 		{
1011 			(void)POVMSAttr_Delete(&item);
1012 			continue;
1013 		}
1014 		(void)POVMSAttr_Delete(&item);
1015 
1016 		file[strlen(file)+1] = '\0';
1017 		file[strlen(file)] = POV_FILE_SEPARATOR;
1018 
1019 		strcpy(pathname, file);
1020 		strcat(pathname, filename);
1021 		if((hasextension == true) && (CheckIfFileExists(pathname) == true))
1022 		{
1023 			(void)POVMSAttrList_Delete(&attr);
1024 			return new ITextStream(ASCIItoUCS2String(pathname).c_str(), stype);
1025 		}
1026 
1027 		for(ii = 0; ii < POV_FILE_EXTENSIONS_PER_TYPE; ii++)
1028 		{
1029 			if(l[ii])
1030 			{
1031 				strcpy(pathname, file);
1032 				strcat(pathname, file_x[ii]);
1033 				if(CheckIfFileExists(pathname) == true)
1034 				{
1035 					(void)POVMSAttrList_Delete(&attr);
1036 					return new ITextStream(ASCIItoUCS2String(pathname).c_str(), stype);
1037 				}
1038 			}
1039 		}
1040 	}
1041 
1042 	(void)POVMSAttrList_Delete(&attr);
1043 
1044 	if(l[0])
1045 		ParseError("Could not find file '%s%s'", filename, pov::gPOV_File_Extensions[stype].ext[0]);
1046 	else
1047 		ParseError("Could not find file '%s'", filename);
1048 
1049 	return NULL;
1050 }
1051 
1052 // TODO - the following code might need reviewing, according to trf
1053 
1054 /* Supported output file types */
1055 struct ProcessRenderOptions::Output_FileType_Table FileTypeTable[] =
1056 {
1057 	// attribute-specific file types (must go first)
1058 	// code, attribute,                     internalId,                         has16BitGrayscale   hasAlpha
1059 	// { 'C',  kPOVAttrib_HistogramFileType,   kPOVList_FileType_CSV,              false,              false },
1060 
1061 	// generic file types
1062 	// code, attribute,                     internalId,                         has16BitGrayscale   hasAlpha
1063 	{ 'T',  0,                              kPOVList_FileType_Targa,            false,              true },
1064 	{ 'C',  0,                              kPOVList_FileType_CompressedTarga,  false,              true },
1065 	{ 'N',  0,                              kPOVList_FileType_PNG,              true,               true },
1066 	{ 'J',  0,                              kPOVList_FileType_JPEG,             false,              false },
1067 	{ 'P',  0,                              kPOVList_FileType_PPM,              true,               false },
1068 	{ 'B',  0,                              kPOVList_FileType_BMP,              false,              false /*[1]*/ },
1069 	{ 'E',  0,                              kPOVList_FileType_OpenEXR,          false /*[2]*/,      true },
1070 	{ 'H',  0,                              kPOVList_FileType_RadianceHDR,      false,              false },
1071 #ifdef SYS_TO_STANDARD
1072 	{ 'S',  0,                              kPOVList_FileType_System,           SYS_GRAYSCALE_FLAG, SYS_ALPHA_FLAG },
1073 #endif // SYS_TO_STANDARD
1074 
1075 	//  [1] Alpha support for BMP uses an inofficial extension to the BMP file format, which is not recognized by
1076 	//      most image pocessing software.
1077 
1078 	//  [2] While OpenEXR does support greyscale output at >8 bits, the variants currently supported by POV-Ray
1079 	//      use 16-bit floating-point values with 10 bit mantissa, which might be insufficient for various purposes
1080 	//      such as height fields.
1081 
1082 	// end-of-list marker
1083 	{ '\0', 0, 0, false }
1084 };
1085 
1086 /* Supported special gamma types */
1087 struct ProcessRenderOptions::Parameter_Code_Table GammaTypeTable[] =
1088 {
1089 
1090 	// code,    internalId,
1091 	{ "SRGB",   kPOVList_GammaType_SRGB },
1092 
1093 	// end-of-list marker
1094 	{ NULL,     0 }
1095 };
1096 
1097 /* Supported dither types */
1098 struct ProcessRenderOptions::Parameter_Code_Table DitherMethodTable[] =
1099 {
1100 
1101 	// code,    internalId,
1102 	{ "B2",     kPOVList_DitherMethod_Bayer2x2 },
1103 	{ "B3",     kPOVList_DitherMethod_Bayer3x3 },
1104 	{ "B4",     kPOVList_DitherMethod_Bayer4x4 },
1105 	{ "D1",     kPOVList_DitherMethod_Diffusion1D },
1106 	{ "D2",     kPOVList_DitherMethod_Diffusion2D },
1107 	{ "FS",     kPOVList_DitherMethod_FloydSteinberg },
1108 
1109 	// end-of-list marker
1110 	{ NULL,     0 }
1111 };
1112 
ParseFileType(char code,POVMSType attribute,int * pInternalId,bool * pHas16BitGreyscale)1113 int ProcessRenderOptions::ParseFileType(char code, POVMSType attribute, int* pInternalId, bool* pHas16BitGreyscale)
1114 {
1115 	*pInternalId = kPOVList_FileType_Unknown;
1116 	int err = kNoErr;
1117 	for (int i = 0; FileTypeTable[i].code != '\0'; i ++)
1118 	{
1119 		if ( (toupper(code) == FileTypeTable[i].code) &&
1120 		     ((FileTypeTable[i].attribute == 0) || (FileTypeTable[i].attribute == attribute )) )
1121 		{
1122 			if (pHas16BitGreyscale != NULL)
1123 				*pHas16BitGreyscale = FileTypeTable[i].has16BitGrayscale;
1124 			*pInternalId = FileTypeTable[i].internalId;
1125 			break;
1126 		}
1127 	}
1128 #ifdef OPENEXR_MISSING
1129 	if (*pInternalId == kPOVList_FileType_OpenEXR)
1130 	{
1131 		ParseError(
1132 "This unofficial POV-Ray binary was built without support for the OpenEXR \
1133 file format.  You must either use an official POV-Ray binary or recompile \
1134 the POV-Ray sources on a system providing you with the OpenEXR library \
1135 to make use of this facility.  Alternatively, you may use any of the \
1136 following built-in formats: HDR."
1137 		);
1138 		err = kParamErr;
1139 	}
1140 #endif // OPENEXR_MISSING
1141 	if (*pInternalId == kPOVList_FileType_Unknown)
1142 	{
1143 		ParseError("Unrecognized output file format %c.", code);
1144 		err = kParamErr;
1145 	}
1146 	return err;
1147 }
1148 
UnparseFileType(int fileType)1149 char ProcessRenderOptions::UnparseFileType(int fileType)
1150 {
1151 	for (int i = 0; FileTypeTable[i].code != '\0'; i ++)
1152 		if (fileType == FileTypeTable[i].internalId)
1153 			return FileTypeTable[i].code;
1154 	return '\0';
1155 }
1156 
ParseGammaType(char * code,int * pInternalId)1157 int ProcessRenderOptions::ParseGammaType(char* code, int* pInternalId)
1158 {
1159 	*pInternalId = kPOVList_GammaType_Unknown;
1160 	int err = ParseParameterCode(GammaTypeTable, code, pInternalId);
1161 	if (err == kParamErr)
1162 		ParseError("Unrecognized gamma setting '%s'.", code);
1163 	return err;
1164 }
1165 
UnparseGammaType(int gammaType)1166 const char* ProcessRenderOptions::UnparseGammaType(int gammaType)
1167 {
1168 	return UnparseParameterCode(GammaTypeTable, gammaType);
1169 }
1170 
ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table * codeTable,char * code,int * pInternalId)1171 int ProcessRenderOptions::ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, char* code, int* pInternalId)
1172 {
1173 	for (int i = 0; code[i] != '\0'; i ++)
1174 		code[i] = toupper(code[i]);
1175 	for (int i = 0; codeTable[i].code != NULL; i ++)
1176 	{
1177 		if ( strcmp(code, codeTable[i].code) == 0 )
1178 		{
1179 			*pInternalId = codeTable[i].internalId;
1180 			return kNoErr;
1181 		}
1182 	}
1183 	return kParamErr;
1184 }
1185 
UnparseParameterCode(const ProcessRenderOptions::Parameter_Code_Table * codeTable,int internalId)1186 const char* ProcessRenderOptions::UnparseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, int internalId)
1187 {
1188 	for (int i = 0; codeTable[i].code != NULL; i ++)
1189 		if (internalId == codeTable[i].internalId)
1190 			return codeTable[i].code;
1191 	return NULL;
1192 }
1193 
1194 }
1195