1 /*****************************************************************************/
2 // Copyright 2006-2008 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8 
9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_parse_utils.cpp#3 $ */
10 /* $DateTime: 2012/06/06 12:08:58 $ */
11 /* $Change: 833617 $ */
12 /* $Author: tknoll $ */
13 
14 /*****************************************************************************/
15 
16 #include "dng_parse_utils.h"
17 
18 #include "dng_date_time.h"
19 #include "dng_globals.h"
20 #include "dng_ifd.h"
21 #include "dng_tag_codes.h"
22 #include "dng_tag_types.h"
23 #include "dng_tag_values.h"
24 #include "dng_types.h"
25 #include "dng_stream.h"
26 #include "dng_exceptions.h"
27 #include "dng_utils.h"
28 
29 /*****************************************************************************/
30 
31 #if qDNGValidate
32 
33 /*****************************************************************************/
34 
35 struct dng_name_table
36 	{
37 	uint32 key;
38 	const char *name;
39 	};
40 
41 /*****************************************************************************/
42 
LookupName(uint32 key,const dng_name_table * table,uint32 table_entries)43 static const char * LookupName (uint32 key,
44 						 		const dng_name_table *table,
45 						 		uint32 table_entries)
46 	{
47 
48 	for (uint32 index = 0; index < table_entries; index++)
49 		{
50 
51 		if (key == table [index] . key)
52 			{
53 
54 			return table [index] . name;
55 
56 			}
57 
58 		}
59 
60 	return NULL;
61 
62 	}
63 
64 /*****************************************************************************/
65 
LookupParentCode(uint32 parentCode)66 const char * LookupParentCode (uint32 parentCode)
67 	{
68 
69 	const dng_name_table kParentCodeNames [] =
70 		{
71 		{	0,							"IFD 0"							},
72 		{	tcExifIFD,					"Exif IFD"						},
73 		{	tcGPSInfo,					"GPS IFD"						},
74 		{	tcInteroperabilityIFD,		"Interoperability IFD"			},
75 		{	tcKodakDCRPrivateIFD,		"Kodak DCR Private IFD"			},
76 		{	tcKodakKDCPrivateIFD,		"Kodak KDC Private IFD"			},
77 		{	tcCanonMakerNote,			"Canon MakerNote"				},
78 		{	tcEpsonMakerNote,			"Epson MakerNote"				},
79 		{	tcFujiMakerNote,			"Fuji MakerNote"				},
80 		{	tcHasselbladMakerNote,		"Hasselblad MakerNote"			},
81 		{	tcKodakMakerNote,			"Kodak MakerNote"				},
82 		{	tcKodakMakerNote65280,		"Kodak MakerNote 65280"			},
83 		{	tcLeicaMakerNote,			"Leica MakerNote"				},
84 		{	tcMamiyaMakerNote,			"Mamiya MakerNote"				},
85 		{	tcMinoltaMakerNote,			"Minolta MakerNote"				},
86 		{	tcNikonMakerNote,			"Nikon MakerNote"				},
87 		{	tcOlympusMakerNote,			"Olympus MakerNote"				},
88 		{	tcOlympusMakerNote8208,		"Olympus MakerNote 8208"		},
89 		{	tcOlympusMakerNote8224,		"Olympus MakerNote 8224"		},
90 		{	tcOlympusMakerNote8240,		"Olympus MakerNote 8240"		},
91 		{	tcOlympusMakerNote8256,		"Olympus MakerNote 8256"		},
92 		{	tcOlympusMakerNote8272,		"Olympus MakerNote 8272"		},
93 		{	tcOlympusMakerNote12288,	"Olympus MakerNote 12288"		},
94 		{	tcPanasonicMakerNote,		"Panasonic MakerNote"			},
95 		{	tcPentaxMakerNote,			"Pentax MakerNote"				},
96 		{	tcPhaseOneMakerNote,		"Phase One MakerNote"			},
97 		{	tcRicohMakerNote,			"Ricoh MakerNote"				},
98 		{	tcRicohMakerNoteCameraInfo,	"Ricoh MakerNote Camera Info"	},
99 		{	tcSonyMakerNote,			"Sony MakerNote"				},
100 		{	tcSonyMakerNoteSubInfo,		"Sony MakerNote SubInfo"		},
101 		{	tcSonyPrivateIFD1,			"Sony Private IFD 1"			},
102 		{	tcSonyPrivateIFD2,			"Sony Private IFD 2"			},
103 		{	tcSonyPrivateIFD3A,			"Sony Private IFD 3A"			},
104 		{	tcSonyPrivateIFD3B,			"Sony Private IFD 3B"			},
105 		{	tcSonyPrivateIFD3C,			"Sony Private IFD 3C"			},
106 		{	tcCanonCRW,					"Canon CRW"						},
107 		{	tcContaxRAW,				"Contax RAW"					},
108 		{	tcFujiRAF,					"Fuji RAF"						},
109 		{	tcLeafMOS,					"Leaf MOS"						},
110 		{	tcMinoltaMRW,				"Minolta MRW"					},
111 		{	tcPanasonicRAW,				"Panasonic RAW"					},
112 		{	tcFoveonX3F,				"Foveon X3F"					},
113 		{	tcJPEG,						"JPEG"							},
114 		{	tcAdobePSD,					"Adobe PSD"						}
115 		};
116 
117 	const char *name = LookupName (parentCode,
118 								   kParentCodeNames,
119 								   sizeof (kParentCodeNames    ) /
120 								   sizeof (kParentCodeNames [0]));
121 
122 	if (name)
123 		{
124 		return name;
125 		}
126 
127 	static char s [32];
128 
129 	if (parentCode >= tcFirstSubIFD &&
130 		parentCode <= tcLastSubIFD)
131 		{
132 
133 		sprintf (s, "SubIFD %u", (unsigned) (parentCode - tcFirstSubIFD + 1));
134 
135 		}
136 
137 	else if (parentCode >= tcFirstChainedIFD &&
138 			 parentCode <= tcLastChainedIFD)
139 		{
140 
141 		sprintf (s, "Chained IFD %u", (unsigned) (parentCode - tcFirstChainedIFD + 1));
142 
143 		}
144 
145 	else
146 		{
147 
148 		sprintf (s, "ParentIFD %u", (unsigned) parentCode);
149 
150 		}
151 
152 	return s;
153 
154 	}
155 
156 /*****************************************************************************/
157 
LookupTagCode(uint32 parentCode,uint32 tagCode)158 const char * LookupTagCode (uint32 parentCode,
159 							uint32 tagCode)
160 	{
161 
162 	const dng_name_table kTagNames [] =
163 		{
164 		{	tcNewSubFileType,					"NewSubFileType"				},
165 		{	tcSubFileType,						"SubFileType"					},
166 		{	tcImageWidth,						"ImageWidth"					},
167 		{	tcImageLength,						"ImageLength"					},
168 		{	tcBitsPerSample,					"BitsPerSample"					},
169 		{	tcCompression,						"Compression"					},
170 		{	tcPhotometricInterpretation,		"PhotometricInterpretation"		},
171 		{	tcThresholding,						"Thresholding"					},
172 		{	tcCellWidth,						"CellWidth"						},
173 		{	tcCellLength,						"CellLength"					},
174 		{	tcFillOrder,						"FillOrder"						},
175 		{	tcImageDescription,					"ImageDescription"				},
176 		{	tcMake,								"Make"							},
177 		{	tcModel,							"Model"							},
178 		{	tcStripOffsets,						"StripOffsets"					},
179 		{	tcOrientation,						"Orientation"					},
180 		{	tcSamplesPerPixel,					"SamplesPerPixel"				},
181 		{	tcRowsPerStrip,						"RowsPerStrip"					},
182 		{	tcStripByteCounts,					"StripByteCounts"				},
183 		{	tcMinSampleValue,					"MinSampleValue"				},
184 		{	tcMaxSampleValue,					"MaxSampleValue"				},
185 		{	tcXResolution,						"XResolution"					},
186 		{	tcYResolution,						"YResolution"					},
187 		{	tcPlanarConfiguration,				"PlanarConfiguration"			},
188 		{	tcFreeOffsets,						"FreeOffsets"					},
189 		{	tcFreeByteCounts,					"FreeByteCounts"				},
190 		{	tcGrayResponseUnit,					"GrayResponseUnit"				},
191 		{	tcGrayResponseCurve,				"GrayResponseCurve"				},
192 		{	tcResolutionUnit,					"ResolutionUnit"				},
193 		{	tcTransferFunction,					"TransferFunction"				},
194 		{	tcSoftware,							"Software"						},
195 		{	tcDateTime,							"DateTime"						},
196 		{	tcArtist,							"Artist"						},
197 		{	tcHostComputer,						"HostComputer"					},
198 		{	tcWhitePoint,						"WhitePoint"					},
199 		{	tcPrimaryChromaticities,			"PrimaryChromaticities"			},
200 		{	tcColorMap,							"ColorMap"						},
201 		{	tcTileWidth,						"TileWidth"						},
202 		{	tcTileLength,						"TileLength"					},
203 		{	tcTileOffsets,						"TileOffsets"					},
204 		{	tcTileByteCounts,					"TileByteCounts"				},
205 		{	tcSubIFDs,							"SubIFDs"						},
206 		{	tcExtraSamples,						"ExtraSamples"					},
207 		{	tcSampleFormat,						"SampleFormat"					},
208 		{	tcJPEGTables,						"JPEGTables"					},
209 		{	tcJPEGProc,							"JPEGProc"						},
210 		{	tcJPEGInterchangeFormat,			"JPEGInterchangeFormat"			},
211 		{	tcJPEGInterchangeFormatLength,		"JPEGInterchangeFormatLength"	},
212 		{	tcYCbCrCoefficients,				"YCbCrCoefficients"				},
213 		{	tcYCbCrSubSampling,					"YCbCrSubSampling"				},
214 		{	tcYCbCrPositioning,					"YCbCrPositioning"				},
215 		{	tcReferenceBlackWhite,				"ReferenceBlackWhite"			},
216 		{	tcXMP,								"XMP"							},
217 		{	tcKodakCameraSerialNumber,			"KodakCameraSerialNumber"		},
218 		{	tcCFARepeatPatternDim,				"CFARepeatPatternDim"			},
219 		{	tcCFAPattern,						"CFAPattern"					},
220 		{	tcBatteryLevel,						"BatteryLevel"					},
221 		{	tcKodakDCRPrivateIFD,				"KodakDCRPrivateIFD"			},
222 		{	tcCopyright,						"Copyright"						},
223 		{	tcExposureTime,						"ExposureTime"					},
224 		{	tcFNumber,							"FNumber"						},
225 		{	tcIPTC_NAA,							"IPTC/NAA"						},
226 		{	tcLeafPKTS,							"LeafPKTS"						},
227 		{	tcAdobeData,						"AdobeData"						},
228 		{	tcExifIFD,							"ExifIFD"						},
229 		{	tcICCProfile,						"ICCProfile"					},
230 		{	tcExposureProgram,					"ExposureProgram"				},
231 		{	tcSpectralSensitivity,				"SpectralSensitivity"			},
232 		{	tcGPSInfo,							"GPSInfo"						},
233 		{	tcISOSpeedRatings,					"ISOSpeedRatings"				},
234 		{	tcOECF,								"OECF"							},
235 		{	tcInterlace,						"Interlace"						},
236 		{	tcTimeZoneOffset,					"TimeZoneOffset"				},
237 		{	tcSelfTimerMode,					"SelfTimerMode"					},
238 		{	tcSensitivityType,					"SensitivityType"				},
239 		{	tcStandardOutputSensitivity,		"StandardOutputSensitivity"		},
240 		{	tcRecommendedExposureIndex,			"RecommendedExposureIndex"		},
241 		{	tcISOSpeed,							"ISOSpeed"						},
242 		{	tcISOSpeedLatitudeyyy,				"ISOSpeedLatitudeyyy"			},
243 		{	tcISOSpeedLatitudezzz,				"ISOSpeedLatitudezzz"			},
244 		{	tcExifVersion,						"ExifVersion"					},
245 		{	tcDateTimeOriginal,					"DateTimeOriginal"				},
246 		{	tcDateTimeDigitized,				"DateTimeDigitized"				},
247 		{	tcComponentsConfiguration,			"ComponentsConfiguration"		},
248 		{	tcCompressedBitsPerPixel,			"CompressedBitsPerPixel"		},
249 		{	tcShutterSpeedValue,				"ShutterSpeedValue"				},
250 		{	tcApertureValue,					"ApertureValue"					},
251 		{	tcBrightnessValue,					"BrightnessValue"				},
252 		{	tcExposureBiasValue,				"ExposureBiasValue"				},
253 		{	tcMaxApertureValue,					"MaxApertureValue"				},
254 		{	tcSubjectDistance,					"SubjectDistance"				},
255 		{	tcMeteringMode,						"MeteringMode"					},
256 		{	tcLightSource,						"LightSource"					},
257 		{	tcFlash,							"Flash"							},
258 		{	tcFocalLength,						"FocalLength"					},
259 		{	tcFlashEnergy,						"FlashEnergy"					},
260 		{	tcSpatialFrequencyResponse,			"SpatialFrequencyResponse"		},
261 		{	tcNoise,							"Noise"							},
262 		{	tcFocalPlaneXResolution,			"FocalPlaneXResolution"			},
263 		{	tcFocalPlaneYResolution,			"FocalPlaneYResolution"			},
264 		{	tcFocalPlaneResolutionUnit,			"FocalPlaneResolutionUnit"		},
265 		{	tcImageNumber,						"ImageNumber"					},
266 		{	tcSecurityClassification,			"SecurityClassification"		},
267 		{	tcImageHistory,						"ImageHistory"					},
268 		{	tcSubjectArea,						"SubjectArea"					},
269 		{	tcExposureIndex,					"ExposureIndex"					},
270 		{	tcTIFF_EP_StandardID,				"TIFF/EPStandardID"				},
271 		{	tcSensingMethod,					"SensingMethod"					},
272 		{	tcMakerNote,						"MakerNote"						},
273 		{	tcUserComment,						"UserComment"					},
274 		{	tcSubsecTime,						"SubsecTime"					},
275 		{	tcSubsecTimeOriginal,				"SubsecTimeOriginal"			},
276 		{	tcSubsecTimeDigitized,				"SubsecTimeDigitized"			},
277 		{	tcAdobeLayerData,					"AdobeLayerData"				},
278 		{	tcFlashPixVersion,					"FlashPixVersion"				},
279 		{	tcColorSpace,						"ColorSpace"					},
280 		{	tcPixelXDimension,					"PixelXDimension"				},
281 		{	tcPixelYDimension,					"PixelYDimension"				},
282 		{	tcRelatedSoundFile,					"RelatedSoundFile"				},
283 		{	tcInteroperabilityIFD,				"InteroperabilityIFD"			},
284 		{	tcFlashEnergyExif,					"FlashEnergyExif"				},
285 		{	tcSpatialFrequencyResponseExif,		"SpatialFrequencyResponseExif"	},
286 		{	tcFocalPlaneXResolutionExif,		"FocalPlaneXResolutionExif"		},
287 		{	tcFocalPlaneYResolutionExif,		"FocalPlaneYResolutionExif"		},
288 		{	tcFocalPlaneResolutionUnitExif,		"FocalPlaneResolutionUnitExif"	},
289 		{	tcSubjectLocation,					"SubjectLocation"				},
290 		{	tcExposureIndexExif,				"ExposureIndexExif"				},
291 		{	tcSensingMethodExif,				"SensingMethodExif"				},
292 		{	tcFileSource,						"FileSource"					},
293 		{	tcSceneType,						"SceneType"						},
294 		{	tcCFAPatternExif,					"CFAPatternExif"				},
295 		{	tcCustomRendered,					"CustomRendered"				},
296 		{	tcExposureMode,						"ExposureMode"					},
297 		{	tcWhiteBalance,						"WhiteBalance"					},
298 		{	tcDigitalZoomRatio,					"DigitalZoomRatio"				},
299 		{	tcFocalLengthIn35mmFilm,			"FocalLengthIn35mmFilm"			},
300 		{	tcSceneCaptureType,					"SceneCaptureType"				},
301 		{	tcGainControl,						"GainControl"					},
302 		{	tcContrast,							"Contrast"						},
303 		{	tcSaturation,						"Saturation"					},
304 		{	tcSharpness,						"Sharpness"						},
305 		{	tcDeviceSettingDescription,			"DeviceSettingDescription"		},
306 		{	tcSubjectDistanceRange,				"SubjectDistanceRange"			},
307 		{	tcImageUniqueID,					"ImageUniqueID"					},
308 		{	tcCameraOwnerNameExif,				"CameraOwnerNameExif"			},
309 		{	tcCameraSerialNumberExif,			"CameraSerialNumberExif"		},
310 		{	tcLensSpecificationExif,			"LensSpecificationExif"			},
311 		{	tcLensMakeExif,						"LensMakeExif"					},
312 		{	tcLensModelExif,					"LensModelExif"					},
313 		{	tcLensSerialNumberExif,				"LensSerialNumberExif"			},
314 		{	tcGamma,							"Gamma"							},
315 		{	tcPrintImageMatchingInfo,			"PrintImageMatchingInfo"		},
316 		{	tcDNGVersion,						"DNGVersion"					},
317 		{	tcDNGBackwardVersion,				"DNGBackwardVersion"			},
318 		{	tcUniqueCameraModel,				"UniqueCameraModel"				},
319 		{	tcLocalizedCameraModel,				"LocalizedCameraModel"			},
320 		{	tcCFAPlaneColor,					"CFAPlaneColor"					},
321 		{	tcCFALayout,						"CFALayout"						},
322 		{	tcLinearizationTable,				"LinearizationTable"			},
323 		{	tcBlackLevelRepeatDim,				"BlackLevelRepeatDim"			},
324 		{	tcBlackLevel,						"BlackLevel"					},
325 		{	tcBlackLevelDeltaH,					"BlackLevelDeltaH"				},
326 		{	tcBlackLevelDeltaV,					"BlackLevelDeltaV"				},
327 		{	tcWhiteLevel,						"WhiteLevel"					},
328 		{	tcDefaultScale,						"DefaultScale"					},
329 		{	tcDefaultCropOrigin,				"DefaultCropOrigin"				},
330 		{	tcDefaultCropSize,					"DefaultCropSize"				},
331 		{	tcDefaultUserCrop,					"DefaultUserCrop"				},
332 		{	tcColorMatrix1,						"ColorMatrix1"					},
333 		{	tcColorMatrix2,						"ColorMatrix2"					},
334 		{	tcCameraCalibration1,				"CameraCalibration1"			},
335 		{	tcCameraCalibration2,				"CameraCalibration2"			},
336 		{	tcReductionMatrix1,					"ReductionMatrix1"				},
337 		{	tcReductionMatrix2,					"ReductionMatrix2"				},
338 		{	tcAnalogBalance,					"AnalogBalance"					},
339 		{	tcAsShotNeutral,					"AsShotNeutral"					},
340 		{	tcAsShotWhiteXY,					"AsShotWhiteXY"					},
341 		{	tcBaselineExposure,					"BaselineExposure"				},
342 		{	tcBaselineNoise,					"BaselineNoise"					},
343 		{	tcBaselineSharpness,				"BaselineSharpness"				},
344 		{	tcBayerGreenSplit,					"BayerGreenSplit"				},
345 		{	tcLinearResponseLimit,				"LinearResponseLimit"			},
346 		{	tcCameraSerialNumber,				"CameraSerialNumber"			},
347 		{	tcLensInfo,							"LensInfo"						},
348 		{	tcChromaBlurRadius,					"ChromaBlurRadius"				},
349 		{	tcAntiAliasStrength,				"AntiAliasStrength"				},
350 		{	tcShadowScale,						"ShadowScale"					},
351 		{	tcDNGPrivateData,					"DNGPrivateData"				},
352 		{	tcMakerNoteSafety,					"MakerNoteSafety"				},
353 		{	tcCalibrationIlluminant1,			"CalibrationIlluminant1"		},
354 		{	tcCalibrationIlluminant2,			"CalibrationIlluminant2"		},
355 		{	tcBestQualityScale,					"BestQualityScale"				},
356 		{	tcRawDataUniqueID,					"RawDataUniqueID"				},
357 		{	tcOriginalRawFileName,				"OriginalRawFileName"			},
358 		{	tcOriginalRawFileData,				"OriginalRawFileData"			},
359 		{	tcActiveArea,						"ActiveArea"					},
360 		{	tcMaskedAreas,						"MaskedAreas"					},
361 		{	tcAsShotICCProfile,					"AsShotICCProfile"				},
362 		{	tcAsShotPreProfileMatrix,			"AsShotPreProfileMatrix"		},
363 		{	tcCurrentICCProfile,				"CurrentICCProfile"				},
364 		{	tcCurrentPreProfileMatrix,			"CurrentPreProfileMatrix"		},
365 		{	tcColorimetricReference,			"ColorimetricReference"			},
366 		{	tcCameraCalibrationSignature,		"CameraCalibrationSignature"	},
367 		{	tcProfileCalibrationSignature,		"ProfileCalibrationSignature"	},
368 		{	tcExtraCameraProfiles,				"ExtraCameraProfiles"			},
369 		{	tcAsShotProfileName,				"AsShotProfileName"				},
370 		{	tcNoiseReductionApplied,			"NoiseReductionApplied"			},
371 		{	tcProfileName,						"ProfileName"					},
372 		{	tcProfileHueSatMapDims,				"ProfileHueSatMapDims"			},
373 		{	tcProfileHueSatMapData1,			"ProfileHueSatMapData1"			},
374 		{	tcProfileHueSatMapData2,			"ProfileHueSatMapData2"			},
375 		{	tcProfileHueSatMapEncoding,			"ProfileHueSatMapEncoding"		},
376 		{	tcProfileToneCurve,					"ProfileToneCurve"				},
377 		{	tcProfileEmbedPolicy,				"ProfileEmbedPolicy"			},
378 		{	tcProfileCopyright,					"ProfileCopyright"				},
379 		{	tcForwardMatrix1,					"ForwardMatrix1"				},
380 		{	tcForwardMatrix2,					"ForwardMatrix2"				},
381 		{	tcPreviewApplicationName,			"PreviewApplicationName"		},
382 		{	tcPreviewApplicationVersion,		"PreviewApplicationVersion"		},
383 		{	tcPreviewSettingsName,				"PreviewSettingsName"		    },
384 		{	tcPreviewSettingsDigest,			"PreviewSettingsDigest"		    },
385 		{	tcPreviewColorSpace,				"PreviewColorSpace"				},
386 		{	tcPreviewDateTime,					"PreviewDateTime"				},
387 		{	tcRawImageDigest,					"RawImageDigest"				},
388 		{	tcOriginalRawFileDigest,			"OriginalRawFileDigest"			},
389 		{	tcSubTileBlockSize,					"SubTileBlockSize"				},
390 		{	tcRowInterleaveFactor,				"RowInterleaveFactor"			},
391 		{	tcProfileLookTableDims,				"ProfileLookTableDims"			},
392 		{	tcProfileLookTableData,				"ProfileLookTableData"			},
393 		{	tcProfileLookTableEncoding,			"ProfileLookTableEncoding"		},
394 		{	tcBaselineExposureOffset,			"BaselineExposureOffset"		},
395 		{	tcDefaultBlackRender,				"DefaultBlackRender"			},
396 		{	tcOpcodeList1,						"OpcodeList1"					},
397 		{	tcOpcodeList2,						"OpcodeList2"					},
398 		{	tcOpcodeList3,						"OpcodeList3"					},
399 		{	tcNoiseProfile,						"NoiseProfile"					},
400 		{	tcOriginalDefaultFinalSize,			"OriginalDefaultFinalSize"		},
401 		{	tcOriginalBestQualityFinalSize,		"OriginalBestQualityFinalSize"	},
402 		{	tcOriginalDefaultCropSize,			"OriginalDefaultCropSize"		},
403 		{	tcProfileHueSatMapEncoding,			"ProfileHueSatMapEncoding"		},
404 		{	tcProfileLookTableEncoding,			"ProfileLookTableEncoding"		},
405 		{	tcBaselineExposureOffset,			"BaselineExposureOffset"		},
406 		{	tcDefaultBlackRender,				"DefaultBlackRender"			},
407 		{	tcNewRawImageDigest,				"NewRawImageDigest"				},
408 		{	tcRawToPreviewGain,					"RawToPreviewGain"				},
409 		{	tcCacheBlob,						"CacheBlob"						},
410 		{	tcKodakKDCPrivateIFD,				"KodakKDCPrivateIFD"			}
411 		};
412 
413 	const dng_name_table kGPSTagNames [] =
414 		{
415 		{	tcGPSVersionID,					"GPSVersionID"			},
416 		{	tcGPSLatitudeRef,				"GPSLatitudeRef"		},
417 		{	tcGPSLatitude,					"GPSLatitude"			},
418 		{	tcGPSLongitudeRef,				"GPSLongitudeRef"		},
419 		{	tcGPSLongitude,					"GPSLongitude"			},
420 		{	tcGPSAltitudeRef,				"GPSAltitudeRef"		},
421 		{	tcGPSAltitude,					"GPSAltitude"			},
422 		{	tcGPSTimeStamp,					"GPSTimeStamp"			},
423 		{	tcGPSSatellites,				"GPSSatellites"			},
424 		{	tcGPSStatus,					"GPSStatus"				},
425 		{	tcGPSMeasureMode,				"GPSMeasureMode"		},
426 		{	tcGPSDOP,						"GPSDOP"				},
427 		{	tcGPSSpeedRef,					"GPSSpeedRef"			},
428 		{	tcGPSSpeed,						"GPSSpeed"				},
429 		{	tcGPSTrackRef,					"GPSTrackRef"			},
430 		{	tcGPSTrack,						"GPSTrack"				},
431 		{	tcGPSImgDirectionRef,			"GPSImgDirectionRef"	},
432 		{	tcGPSImgDirection,				"GPSImgDirection"		},
433 		{	tcGPSMapDatum,					"GPSMapDatum"			},
434 		{	tcGPSDestLatitudeRef,			"GPSDestLatitudeRef"	},
435 		{	tcGPSDestLatitude,				"GPSDestLatitude"		},
436 		{	tcGPSDestLongitudeRef,			"GPSDestLongitudeRef"	},
437 		{	tcGPSDestLongitude,				"GPSDestLongitude"		},
438 		{	tcGPSDestBearingRef,			"GPSDestBearingRef"		},
439 		{	tcGPSDestBearing,				"GPSDestBearing"		},
440 		{	tcGPSDestDistanceRef,			"GPSDestDistanceRef"	},
441 		{	tcGPSDestDistance,				"GPSDestDistance"		},
442 		{	tcGPSProcessingMethod,			"GPSProcessingMethod"	},
443 		{	tcGPSAreaInformation,			"GPSAreaInformation"	},
444 		{	tcGPSDateStamp,					"GPSDateStamp"			},
445 		{	tcGPSDifferential,				"GPSDifferential"		},
446 		{	tcGPSHPositioningError,			"GPSHPositioningError"	},
447 		};
448 
449 	const dng_name_table kInteroperabilityTagNames [] =
450 		{
451 		{	tcInteroperabilityIndex,		"InteroperabilityIndex"		},
452 		{	tcInteroperabilityVersion,		"InteroperabilityVersion"	},
453 		{	tcRelatedImageFileFormat,		"RelatedImageFileFormat"	},
454 		{	tcRelatedImageWidth,			"RelatedImageWidth"			},
455 		{	tcRelatedImageLength,			"RelatedImageLength"		}
456 		};
457 
458 	const dng_name_table kFujiTagNames [] =
459 		{
460 		{	tcFujiHeader,					"FujiHeader"	},
461 		{	tcFujiRawInfo1,					"FujiRawInfo1"	},
462 		{	tcFujiRawInfo2,					"FujiRawInfo2"	}
463 		};
464 
465 	const dng_name_table kContaxTagNames [] =
466 		{
467 		{	tcContaxHeader,					"ContaxHeader"	}
468 		};
469 
470 	const char *name = NULL;
471 
472 	if (parentCode == 0         										 ||
473 		parentCode == tcExifIFD 										 ||
474 		parentCode == tcLeafMOS 										 ||
475 		(parentCode >= tcFirstSubIFD     && parentCode <= tcLastSubIFD)  ||
476 		(parentCode >= tcFirstChainedIFD && parentCode <= tcLastChainedIFD))
477 		{
478 
479 		name = LookupName (tagCode,
480 						   kTagNames,
481 						   sizeof (kTagNames    ) /
482 						   sizeof (kTagNames [0]));
483 
484 		}
485 
486 	else if (parentCode == tcGPSInfo)
487 		{
488 
489 		name = LookupName (tagCode,
490 						   kGPSTagNames,
491 						   sizeof (kGPSTagNames    ) /
492 						   sizeof (kGPSTagNames [0]));
493 
494 		}
495 
496 	else if (parentCode == tcInteroperabilityIFD)
497 		{
498 
499 		name = LookupName (tagCode,
500 						   kInteroperabilityTagNames,
501 						   sizeof (kInteroperabilityTagNames    ) /
502 						   sizeof (kInteroperabilityTagNames [0]));
503 
504 		}
505 
506 	else if (parentCode == tcFujiRAF)
507 		{
508 
509 		name = LookupName (tagCode,
510 						   kFujiTagNames,
511 						   sizeof (kFujiTagNames    ) /
512 						   sizeof (kFujiTagNames [0]));
513 
514 		}
515 
516 	else if (parentCode == tcContaxRAW)
517 		{
518 
519 		name = LookupName (tagCode,
520 						   kContaxTagNames,
521 						   sizeof (kContaxTagNames    ) /
522 						   sizeof (kContaxTagNames [0]));
523 
524 		}
525 
526 	if (name)
527 		{
528 		return name;
529 		}
530 
531 	static char s [32];
532 
533 	if (parentCode == tcCanonCRW)
534 		{
535 		sprintf (s, "CRW_%04X", (unsigned) tagCode);
536 		}
537 
538 	else if (parentCode == tcMinoltaMRW)
539 		{
540 
541 		char c1 = (char) ((tagCode >> 24) & 0xFF);
542 		char c2 = (char) ((tagCode >> 16) & 0xFF);
543 		char c3 = (char) ((tagCode >>  8) & 0xFF);
544 		char c4 = (char) ((tagCode      ) & 0xFF);
545 
546 		if (c1 < ' ') c1 = '_';
547 		if (c2 < ' ') c2 = '_';
548 		if (c3 < ' ') c3 = '_';
549 		if (c4 < ' ') c4 = '_';
550 
551 		sprintf (s, "MRW%c%c%c%c", c1, c2, c3, c4);
552 
553 		}
554 
555 	else if (parentCode == tcFujiRawInfo1)
556 		{
557 		sprintf (s, "RAF1_%04X", (unsigned) tagCode);
558 		}
559 
560 	else if (parentCode == tcFujiRawInfo2)
561 		{
562 		sprintf (s, "RAF2_%04X", (unsigned) tagCode);
563 		}
564 
565 	else
566 		{
567 		sprintf (s, "Tag%u", (unsigned) tagCode);
568 		}
569 
570 	return s;
571 
572 	}
573 
574 /*****************************************************************************/
575 
LookupTagType(uint32 tagType)576 const char * LookupTagType (uint32 tagType)
577 	{
578 
579 	const dng_name_table kTagTypeNames [] =
580 		{
581 		{	ttByte,			"Byte"		},
582 		{	ttAscii,		"ASCII"		},
583 		{	ttShort,		"Short"		},
584 		{	ttLong,			"Long"		},
585 		{	ttRational,		"Rational"	},
586 		{	ttSByte,		"SByte"		},
587 		{	ttUndefined,	"Undefined"	},
588 		{	ttSShort,		"SShort"	},
589 		{	ttSLong,		"SLong"		},
590 		{	ttSRational,	"SRational"	},
591 		{	ttFloat,		"Float"		},
592 		{	ttDouble,		"Double"	},
593 		{	ttIFD,			"IFD"		},
594 		{	ttUnicode,		"Unicode"	},
595 		{	ttComplex,		"Complex"	}
596 		};
597 
598 	const char *name = LookupName (tagType,
599 								   kTagTypeNames,
600 								   sizeof (kTagTypeNames    ) /
601 								   sizeof (kTagTypeNames [0]));
602 
603 	if (name)
604 		{
605 		return name;
606 		}
607 
608 	static char s [32];
609 
610 	sprintf (s, "Type%u", (unsigned) tagType);
611 
612 	return s;
613 
614 	}
615 
616 /*****************************************************************************/
617 
LookupNewSubFileType(uint32 key)618 const char * LookupNewSubFileType (uint32 key)
619 	{
620 
621 	const dng_name_table kNewSubFileTypeNames [] =
622 		{
623 		{	sfMainImage			, "Main Image"			},
624 		{	sfPreviewImage		, "Preview Image"		},
625 		{	sfTransparencyMask	, "Transparency Mask"	},
626 		{	sfPreviewMask		, "Preview Mask"		},
627 		{	sfAltPreviewImage	, "Alt Preview Image"	}
628 		};
629 
630 	const char *name = LookupName (key,
631 								   kNewSubFileTypeNames,
632 								   sizeof (kNewSubFileTypeNames    ) /
633 								   sizeof (kNewSubFileTypeNames [0]));
634 
635 	if (name)
636 		{
637 		return name;
638 		}
639 
640 	static char s [32];
641 
642 	sprintf (s, "%u", (unsigned) key);
643 
644 	return s;
645 
646 	}
647 
648 /*****************************************************************************/
649 
LookupCompression(uint32 key)650 const char * LookupCompression (uint32 key)
651 	{
652 
653 	const dng_name_table kCompressionNames [] =
654 		{
655 		{	ccUncompressed,		"Uncompressed"	},
656 		{	ccLZW,				"LZW"			},
657 		{	ccOldJPEG,			"Old JPEG"		},
658 		{	ccJPEG,				"JPEG"			},
659 		{	ccDeflate,			"Deflate"		},
660 		{	ccPackBits,			"PackBits"		},
661 		{	ccOldDeflate,		"OldDeflate"	},
662 		{	ccLossyJPEG,		"Lossy JPEG"	}
663 		};
664 
665 	const char *name = LookupName (key,
666 								   kCompressionNames,
667 								   sizeof (kCompressionNames    ) /
668 								   sizeof (kCompressionNames [0]));
669 
670 	if (name)
671 		{
672 		return name;
673 		}
674 
675 	static char s [32];
676 
677 	sprintf (s, "%u", (unsigned) key);
678 
679 	return s;
680 
681 	}
682 
683 /*****************************************************************************/
684 
LookupPredictor(uint32 key)685 const char * LookupPredictor (uint32 key)
686 	{
687 
688 	const dng_name_table kPredictorNames [] =
689 		{
690 		{	cpNullPredictor,			"NullPredictor"				},
691 		{	cpHorizontalDifference,		"HorizontalDifference"		},
692 		{	cpFloatingPoint,			"FloatingPoint"				},
693 		{	cpHorizontalDifferenceX2,	"HorizontalDifferenceX2"	},
694 		{	cpHorizontalDifferenceX4,	"HorizontalDifferenceX4"	},
695 		{	cpFloatingPointX2,			"FloatingPointX2"			},
696 		{	cpFloatingPointX4,			"FloatingPointX4"			}
697 		};
698 
699 	const char *name = LookupName (key,
700 								   kPredictorNames,
701 								   sizeof (kPredictorNames    ) /
702 								   sizeof (kPredictorNames [0]));
703 
704 	if (name)
705 		{
706 		return name;
707 		}
708 
709 	static char s [32];
710 
711 	sprintf (s, "%u", (unsigned) key);
712 
713 	return s;
714 
715 	}
716 
717 /*****************************************************************************/
718 
LookupSampleFormat(uint32 key)719 const char * LookupSampleFormat (uint32 key)
720 	{
721 
722 	const dng_name_table kSampleFormatNames [] =
723 		{
724 		{	sfUnsignedInteger,	"UnsignedInteger"	},
725 		{	sfSignedInteger,	"SignedInteger"		},
726 		{	sfFloatingPoint,	"FloatingPoint"		},
727 		{	sfUndefined,		"Undefined"			}
728 		};
729 
730 	const char *name = LookupName (key,
731 								   kSampleFormatNames,
732 								   sizeof (kSampleFormatNames    ) /
733 								   sizeof (kSampleFormatNames [0]));
734 
735 	if (name)
736 		{
737 		return name;
738 		}
739 
740 	static char s [32];
741 
742 	sprintf (s, "%u", (unsigned) key);
743 
744 	return s;
745 
746 	}
747 
748 /*****************************************************************************/
749 
LookupPhotometricInterpretation(uint32 key)750 const char * LookupPhotometricInterpretation (uint32 key)
751 	{
752 
753 	const dng_name_table kPhotometricInterpretationNames [] =
754 		{
755 		{	piWhiteIsZero, 			"WhiteIsZero"		},
756 		{	piBlackIsZero,			"BlackIsZero"		},
757 		{	piRGB,					"RGB"				},
758 		{	piRGBPalette,			"RGBPalette"		},
759 		{	piTransparencyMask,		"TransparencyMask"	},
760 		{	piCMYK,					"CMYK"				},
761 		{	piYCbCr,				"YCbCr"				},
762 		{	piCIELab,				"CIELab"			},
763 		{	piICCLab,				"ICCLab"			},
764 		{	piCFA,					"CFA"				},
765 		{	piLinearRaw,			"LinearRaw"			}
766 		};
767 
768 	const char *name = LookupName (key,
769 								   kPhotometricInterpretationNames,
770 								   sizeof (kPhotometricInterpretationNames    ) /
771 								   sizeof (kPhotometricInterpretationNames [0]));
772 
773 	if (name)
774 		{
775 		return name;
776 		}
777 
778 	static char s [32];
779 
780 	sprintf (s, "%u", (unsigned) key);
781 
782 	return s;
783 
784 	}
785 
786 /*****************************************************************************/
787 
LookupOrientation(uint32 key)788 const char * LookupOrientation (uint32 key)
789 	{
790 
791 	const dng_name_table kOrientationNames [] =
792 		{
793 		{	1, 	"1 - 0th row is top, 0th column is left"		},
794 		{	2,	"2 - 0th row is top, 0th column is right"		},
795 		{	3,	"3 - 0th row is bottom, 0th column is right"	},
796 		{	4,	"4 - 0th row is bottom, 0th column is left"		},
797 		{	5,	"5 - 0th row is left, 0th column is top"		},
798 		{	6,	"6 - 0th row is right, 0th column is top"		},
799 		{	7,	"7 - 0th row is right, 0th column is bottom"	},
800 		{	8,	"8 - 0th row is left, 0th column is bottom"		},
801 		{	9,	"9 - unknown"									}
802 		};
803 
804 	const char *name = LookupName (key,
805 								   kOrientationNames,
806 								   sizeof (kOrientationNames    ) /
807 								   sizeof (kOrientationNames [0]));
808 
809 	if (name)
810 		{
811 		return name;
812 		}
813 
814 	static char s [32];
815 
816 	sprintf (s, "%u", (unsigned) key);
817 
818 	return s;
819 
820 	}
821 
822 /*****************************************************************************/
823 
LookupResolutionUnit(uint32 key)824 const char * LookupResolutionUnit (uint32 key)
825 	{
826 
827 	const dng_name_table kResolutionUnitNames [] =
828 		{
829 		{	ruNone, 	"None"			},
830 		{	ruInch,		"Inch"			},
831 		{	ruCM,		"cm"			},
832 		{	ruMM,		"mm"			},
833 		{	ruMicroM,	"Micrometer"	}
834 		};
835 
836 	const char *name = LookupName (key,
837 								   kResolutionUnitNames,
838 								   sizeof (kResolutionUnitNames    ) /
839 								   sizeof (kResolutionUnitNames [0]));
840 
841 	if (name)
842 		{
843 		return name;
844 		}
845 
846 	static char s [32];
847 
848 	sprintf (s, "%u", (unsigned) key);
849 
850 	return s;
851 
852 	}
853 
854 /*****************************************************************************/
855 
LookupCFAColor(uint32 key)856 const char * LookupCFAColor (uint32 key)
857 	{
858 
859 	const dng_name_table kCFAColorNames [] =
860 		{
861 		{	0, "Red"		},
862 		{	1, "Green"		},
863 		{	2, "Blue"		},
864 		{	3, "Cyan"		},
865 		{	4, "Magenta"	},
866 		{	5, "Yellow"		},
867 		{	6, "White"		}
868 		};
869 
870 	const char *name = LookupName (key,
871 								   kCFAColorNames,
872 								   sizeof (kCFAColorNames    ) /
873 								   sizeof (kCFAColorNames [0]));
874 
875 	if (name)
876 		{
877 		return name;
878 		}
879 
880 	static char s [32];
881 
882 	sprintf (s, "Color%u", (unsigned) key);
883 
884 	return s;
885 
886 	}
887 
888 /*****************************************************************************/
889 
LookupSensingMethod(uint32 key)890 const char * LookupSensingMethod (uint32 key)
891 	{
892 
893 	const dng_name_table kSensingMethodNames [] =
894 		{
895 		{	0, "Undefined"				},
896 		{	1, "MonochromeArea"			},
897 		{	2, "OneChipColorArea"		},
898 		{	3, "TwoChipColorArea"		},
899 		{	4, "ThreeChipColorArea"		},
900 		{	5, "ColorSequentialArea"	},
901 		{	6, "MonochromeLinear"		},
902 		{	7, "TriLinear"				},
903 		{	8, "ColorSequentialLinear"	}
904 		};
905 
906 	const char *name = LookupName (key,
907 								   kSensingMethodNames,
908 								   sizeof (kSensingMethodNames    ) /
909 								   sizeof (kSensingMethodNames [0]));
910 
911 	if (name)
912 		{
913 		return name;
914 		}
915 
916 	static char s [32];
917 
918 	sprintf (s, "%u", (unsigned) key);
919 
920 	return s;
921 
922 	}
923 
924 /*****************************************************************************/
925 
LookupExposureProgram(uint32 key)926 const char * LookupExposureProgram (uint32 key)
927 	{
928 
929 	const dng_name_table kExposureProgramNames [] =
930 		{
931 		{	epUnidentified,		"Unidentified"		},
932 		{	epManual,			"Manual"			},
933 		{	epProgramNormal,	"Program Normal"	},
934 		{	epAperturePriority,	"Aperture Priority"	},
935 		{	epShutterPriority, 	"Shutter Priority"	},
936 		{	epProgramCreative,	"Program Creative"	},
937 		{	epProgramAction,	"Program Action"	},
938 		{	epPortraitMode,		"Portrait Mode"		},
939 		{	epLandscapeMode,	"Landscape Mode"	}
940 		};
941 
942 	const char *name = LookupName (key,
943 								   kExposureProgramNames,
944 								   sizeof (kExposureProgramNames    ) /
945 								   sizeof (kExposureProgramNames [0]));
946 
947 	if (name)
948 		{
949 		return name;
950 		}
951 
952 	static char s [32];
953 
954 	sprintf (s, "%u", (unsigned) key);
955 
956 	return s;
957 
958 	}
959 
960 /*****************************************************************************/
961 
LookupMeteringMode(uint32 key)962 const char * LookupMeteringMode (uint32 key)
963 	{
964 
965 	const dng_name_table kMeteringModeNames [] =
966 		{
967 		{	mmUnidentified,   			"Unknown"				},
968 		{	mmAverage,   				"Average"				},
969 		{	mmCenterWeightedAverage,	"CenterWeightedAverage"	},
970 		{	mmSpot,   					"Spot"					},
971 		{	mmMultiSpot,   				"MultiSpot"				},
972 		{	mmPattern,   				"Pattern"				},
973 		{	mmPartial,   				"Partial"				},
974 		{	mmOther, 					"Other"					}
975 		};
976 
977 	const char *name = LookupName (key,
978 								   kMeteringModeNames,
979 								   sizeof (kMeteringModeNames    ) /
980 								   sizeof (kMeteringModeNames [0]));
981 
982 	if (name)
983 		{
984 		return name;
985 		}
986 
987 	static char s [32];
988 
989 	sprintf (s, "%u", (unsigned) key);
990 
991 	return s;
992 
993 	}
994 
995 /*****************************************************************************/
996 
LookupLightSource(uint32 key)997 const char * LookupLightSource (uint32 key)
998 	{
999 
1000 	const dng_name_table kLightSourceNames [] =
1001 		{
1002 		{	lsUnknown,				"Unknown"									},
1003 		{	lsDaylight,				"Daylight"									},
1004 		{	lsFluorescent,			"Fluorescent"								},
1005 		{	lsTungsten,				"Tungsten (incandescent light)"				},
1006 		{	lsFlash,				"Flash"										},
1007 		{	lsFineWeather,			"Fine weather"								},
1008 		{	lsCloudyWeather,		"Cloudy weather"							},
1009 		{	lsShade,				"Shade"										},
1010 		{	lsDaylightFluorescent,	"Daylight fluorescent (D 5700 - 7100K)"		},
1011 		{	lsDayWhiteFluorescent,	"Day white fluorescent (N 4600 - 5500K)"	},
1012 		{	lsCoolWhiteFluorescent,	"Cool white fluorescent (W 3800 - 4500K)"	},
1013 		{	lsWhiteFluorescent,		"White fluorescent (WW 3250 - 3800K)"		},
1014 		{	lsWarmWhiteFluorescent, "Warm white fluorescent (L 2600 - 3250K)"	},
1015 		{	lsStandardLightA,		"Standard light A"							},
1016 		{	lsStandardLightB,		"Standard light B"							},
1017 		{	lsStandardLightC,		"Standard light C"							},
1018 		{	lsD55,					"D55"										},
1019 		{	lsD65,					"D65"										},
1020 		{	lsD75,					"D75"										},
1021 		{	lsD50,					"D50"										},
1022 		{	lsISOStudioTungsten,	"ISO studio tungsten"						},
1023 		{	lsOther,				"Other"										}
1024 		};
1025 
1026 	const char *name = LookupName (key,
1027 								   kLightSourceNames,
1028 								   sizeof (kLightSourceNames    ) /
1029 								   sizeof (kLightSourceNames [0]));
1030 
1031 	if (name)
1032 		{
1033 		return name;
1034 		}
1035 
1036 	static char s [32];
1037 
1038 	if (key & 0x08000)
1039 		{
1040 
1041 		sprintf (s, "%uK", (unsigned) (key & 0x7FFF));
1042 
1043 		}
1044 
1045 	else
1046 		{
1047 
1048 		sprintf (s, "%u", (unsigned) key);
1049 
1050 		}
1051 
1052 	return s;
1053 
1054 	}
1055 
1056 /*****************************************************************************/
1057 
LookupColorSpace(uint32 key)1058 const char * LookupColorSpace (uint32 key)
1059 	{
1060 
1061 	const dng_name_table kColorSpaceNames [] =
1062 		{
1063 		{	1,		"sRGB"			},
1064 		{	0xFFFF,	"Uncalibrated"	}
1065 		};
1066 
1067 	const char *name = LookupName (key,
1068 								   kColorSpaceNames,
1069 								   sizeof (kColorSpaceNames    ) /
1070 								   sizeof (kColorSpaceNames [0]));
1071 
1072 	if (name)
1073 		{
1074 		return name;
1075 		}
1076 
1077 	static char s [32];
1078 
1079 	sprintf (s, "%u", (unsigned) key);
1080 
1081 	return s;
1082 
1083 	}
1084 
1085 /*****************************************************************************/
1086 
LookupFileSource(uint32 key)1087 const char * LookupFileSource (uint32 key)
1088 	{
1089 
1090 	const dng_name_table kFileSourceNames [] =
1091 		{
1092 		{	3,		"DSC"	}
1093 		};
1094 
1095 	const char *name = LookupName (key,
1096 								   kFileSourceNames,
1097 								   sizeof (kFileSourceNames    ) /
1098 								   sizeof (kFileSourceNames [0]));
1099 
1100 	if (name)
1101 		{
1102 		return name;
1103 		}
1104 
1105 	static char s [32];
1106 
1107 	sprintf (s, "%u", (unsigned) key);
1108 
1109 	return s;
1110 
1111 	}
1112 
1113 /*****************************************************************************/
1114 
LookupSceneType(uint32 key)1115 const char * LookupSceneType (uint32 key)
1116 	{
1117 
1118 	const dng_name_table kSceneTypeNames [] =
1119 		{
1120 		{	1,	"A directly photographed image"		}
1121 		};
1122 
1123 	const char *name = LookupName (key,
1124 								   kSceneTypeNames,
1125 								   sizeof (kSceneTypeNames    ) /
1126 								   sizeof (kSceneTypeNames [0]));
1127 
1128 	if (name)
1129 		{
1130 		return name;
1131 		}
1132 
1133 	static char s [32];
1134 
1135 	sprintf (s, "%u", (unsigned) key);
1136 
1137 	return s;
1138 
1139 	}
1140 
1141 /*****************************************************************************/
1142 
LookupCustomRendered(uint32 key)1143 const char * LookupCustomRendered (uint32 key)
1144 	{
1145 
1146 	const dng_name_table kCustomRenderedNames [] =
1147 		{
1148 		{	0,		"Normal process"	},
1149 		{	1,		"Custom process"	}
1150 		};
1151 
1152 	const char *name = LookupName (key,
1153 								   kCustomRenderedNames,
1154 								   sizeof (kCustomRenderedNames    ) /
1155 								   sizeof (kCustomRenderedNames [0]));
1156 
1157 	if (name)
1158 		{
1159 		return name;
1160 		}
1161 
1162 	static char s [32];
1163 
1164 	sprintf (s, "%u", (unsigned) key);
1165 
1166 	return s;
1167 
1168 	}
1169 
1170 /*****************************************************************************/
1171 
LookupExposureMode(uint32 key)1172 const char * LookupExposureMode (uint32 key)
1173 	{
1174 
1175 	const dng_name_table kExposureModeNames [] =
1176 		{
1177 		{	0,	"Auto exposure"		},
1178 		{	1,	"Manual exposure"	},
1179 		{	2,	"Auto bracket"		}
1180 		};
1181 
1182 	const char *name = LookupName (key,
1183 								   kExposureModeNames,
1184 								   sizeof (kExposureModeNames    ) /
1185 								   sizeof (kExposureModeNames [0]));
1186 
1187 	if (name)
1188 		{
1189 		return name;
1190 		}
1191 
1192 	static char s [32];
1193 
1194 	sprintf (s, "%u", (unsigned) key);
1195 
1196 	return s;
1197 
1198 	}
1199 
1200 /*****************************************************************************/
1201 
LookupWhiteBalance(uint32 key)1202 const char * LookupWhiteBalance (uint32 key)
1203 	{
1204 
1205 	const dng_name_table kWhiteBalanceNames [] =
1206 		{
1207 		{	0,	"Auto white balance"	},
1208 		{	1,	"Manual white balance"	}
1209 		};
1210 
1211 	const char *name = LookupName (key,
1212 								   kWhiteBalanceNames,
1213 								   sizeof (kWhiteBalanceNames    ) /
1214 								   sizeof (kWhiteBalanceNames [0]));
1215 
1216 	if (name)
1217 		{
1218 		return name;
1219 		}
1220 
1221 	static char s [32];
1222 
1223 	sprintf (s, "%u", (unsigned) key);
1224 
1225 	return s;
1226 
1227 	}
1228 
1229 /*****************************************************************************/
1230 
LookupSceneCaptureType(uint32 key)1231 const char * LookupSceneCaptureType (uint32 key)
1232 	{
1233 
1234 	const dng_name_table kSceneCaptureTypeNames [] =
1235 		{
1236 		{	0,	"Standard"		},
1237 		{	1,	"Landscape"		},
1238 		{	2,	"Portrait"		},
1239 		{	3,	"Night scene"	}
1240 		};
1241 
1242 	const char *name = LookupName (key,
1243 								   kSceneCaptureTypeNames,
1244 								   sizeof (kSceneCaptureTypeNames    ) /
1245 								   sizeof (kSceneCaptureTypeNames [0]));
1246 
1247 	if (name)
1248 		{
1249 		return name;
1250 		}
1251 
1252 	static char s [32];
1253 
1254 	sprintf (s, "%u", (unsigned) key);
1255 
1256 	return s;
1257 
1258 	}
1259 
1260 /*****************************************************************************/
1261 
LookupGainControl(uint32 key)1262 const char * LookupGainControl (uint32 key)
1263 	{
1264 
1265 	const dng_name_table kGainControlNames [] =
1266 		{
1267 		{	0,	"None"				},
1268 		{	1,	"Low gain up"		},
1269 		{	2,	"High gain up"		},
1270 		{	3,	"Low gain down"		},
1271 		{	4,	"High gain down"	}
1272 		};
1273 
1274 	const char *name = LookupName (key,
1275 								   kGainControlNames,
1276 								   sizeof (kGainControlNames    ) /
1277 								   sizeof (kGainControlNames [0]));
1278 
1279 	if (name)
1280 		{
1281 		return name;
1282 		}
1283 
1284 	static char s [32];
1285 
1286 	sprintf (s, "%u", (unsigned) key);
1287 
1288 	return s;
1289 
1290 	}
1291 
1292 /*****************************************************************************/
1293 
LookupContrast(uint32 key)1294 const char * LookupContrast (uint32 key)
1295 	{
1296 
1297 	const dng_name_table kContrastNames [] =
1298 		{
1299 		{	0,	"Normal"	},
1300 		{	1,	"Soft"		},
1301 		{	2,	"Hard"		}
1302 		};
1303 
1304 	const char *name = LookupName (key,
1305 								   kContrastNames,
1306 								   sizeof (kContrastNames    ) /
1307 								   sizeof (kContrastNames [0]));
1308 
1309 	if (name)
1310 		{
1311 		return name;
1312 		}
1313 
1314 	static char s [32];
1315 
1316 	sprintf (s, "%u", (unsigned) key);
1317 
1318 	return s;
1319 
1320 	}
1321 
1322 /*****************************************************************************/
1323 
LookupSaturation(uint32 key)1324 const char * LookupSaturation (uint32 key)
1325 	{
1326 
1327 	const dng_name_table kSaturationNames [] =
1328 		{
1329 		{	0,	"Normal"			},
1330 		{	1,	"Low saturation"	},
1331 		{	2,	"High saturation"	}
1332 		};
1333 
1334 	const char *name = LookupName (key,
1335 								   kSaturationNames,
1336 								   sizeof (kSaturationNames    ) /
1337 								   sizeof (kSaturationNames [0]));
1338 
1339 	if (name)
1340 		{
1341 		return name;
1342 		}
1343 
1344 	static char s [32];
1345 
1346 	sprintf (s, "%u", (unsigned) key);
1347 
1348 	return s;
1349 
1350 	}
1351 
1352 /*****************************************************************************/
1353 
LookupSharpness(uint32 key)1354 const char * LookupSharpness (uint32 key)
1355 	{
1356 
1357 	const dng_name_table kSharpnessNames [] =
1358 		{
1359 		{	0,	"Normal"	},
1360 		{	1,	"Soft"		},
1361 		{	2,	"Hard"		}
1362 		};
1363 
1364 	const char *name = LookupName (key,
1365 								   kSharpnessNames,
1366 								   sizeof (kSharpnessNames    ) /
1367 								   sizeof (kSharpnessNames [0]));
1368 
1369 	if (name)
1370 		{
1371 		return name;
1372 		}
1373 
1374 	static char s [32];
1375 
1376 	sprintf (s, "%u", (unsigned) key);
1377 
1378 	return s;
1379 
1380 	}
1381 
1382 /*****************************************************************************/
1383 
LookupSubjectDistanceRange(uint32 key)1384 const char * LookupSubjectDistanceRange (uint32 key)
1385 	{
1386 
1387 	const dng_name_table kSubjectDistanceRangeNames [] =
1388 		{
1389 		{	0,	"Unknown"		},
1390 		{	1,	"Macro"			},
1391 		{	2,	"Close view"	},
1392 		{	3,	"Distant view"	}
1393 		};
1394 
1395 	const char *name = LookupName (key,
1396 								   kSubjectDistanceRangeNames,
1397 								   sizeof (kSubjectDistanceRangeNames    ) /
1398 								   sizeof (kSubjectDistanceRangeNames [0]));
1399 
1400 	if (name)
1401 		{
1402 		return name;
1403 		}
1404 
1405 	static char s [32];
1406 
1407 	sprintf (s, "%u", (unsigned) key);
1408 
1409 	return s;
1410 
1411 	}
1412 
1413 /*****************************************************************************/
1414 
LookupComponent(uint32 key)1415 const char * LookupComponent (uint32 key)
1416 	{
1417 
1418 	const dng_name_table kComponentNames [] =
1419 		{
1420 		{	0, "-"	},
1421 		{	1, "Y"	},
1422 		{	2, "Cb"	},
1423 		{	3, "Cr"	},
1424 		{	4, "R"	},
1425 		{	5, "G"	},
1426 		{	6, "B"	}
1427 		};
1428 
1429 	const char *name = LookupName (key,
1430 								   kComponentNames,
1431 								   sizeof (kComponentNames    ) /
1432 								   sizeof (kComponentNames [0]));
1433 
1434 	if (name)
1435 		{
1436 		return name;
1437 		}
1438 
1439 	static char s [32];
1440 
1441 	sprintf (s, "%u", (unsigned) key);
1442 
1443 	return s;
1444 
1445 	}
1446 
1447 /*****************************************************************************/
1448 
LookupCFALayout(uint32 key)1449 const char * LookupCFALayout (uint32 key)
1450 	{
1451 
1452 	const dng_name_table kCFALayoutNames [] =
1453 		{
1454 		{	1,	"Rectangular (or square) layout"																		},
1455 		{	2,	"Staggered layout A: even columns are offset down by 1/2 row"											},
1456 		{	3,	"Staggered layout B: even columns are offset up by 1/2 row"												},
1457 		{	4,	"Staggered layout C: even rows are offset right by 1/2 column"											},
1458 		{	5,	"Staggered layout D: even rows are offset left by 1/2 column"											},
1459 		{	6,	"Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column"	},
1460 		{	7,	"Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column"	},
1461 		{	8,	"Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column"	},
1462 		{	9,	"Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column"	}
1463 		};
1464 
1465 	const char *name = LookupName (key,
1466 								   kCFALayoutNames,
1467 								   sizeof (kCFALayoutNames    ) /
1468 								   sizeof (kCFALayoutNames [0]));
1469 
1470 	if (name)
1471 		{
1472 		return name;
1473 		}
1474 
1475 	static char s [32];
1476 
1477 	sprintf (s, "%u", (unsigned) key);
1478 
1479 	return s;
1480 
1481 	}
1482 
1483 /*****************************************************************************/
1484 
LookupMakerNoteSafety(uint32 key)1485 const char * LookupMakerNoteSafety (uint32 key)
1486 	{
1487 
1488 	const dng_name_table kMakerNoteSafetyNames [] =
1489 		{
1490 		{	0,	"Unsafe"	},
1491 		{	1,	"Safe"		}
1492 		};
1493 
1494 	const char *name = LookupName (key,
1495 								   kMakerNoteSafetyNames,
1496 								   sizeof (kMakerNoteSafetyNames    ) /
1497 								   sizeof (kMakerNoteSafetyNames [0]));
1498 
1499 	if (name)
1500 		{
1501 		return name;
1502 		}
1503 
1504 	static char s [32];
1505 
1506 	sprintf (s, "%u", (unsigned) key);
1507 
1508 	return s;
1509 
1510 	}
1511 
1512 /*****************************************************************************/
1513 
LookupColorimetricReference(uint32 key)1514 const char * LookupColorimetricReference (uint32 key)
1515 	{
1516 
1517 	const dng_name_table kColorimetricReferenceNames [] =
1518 		{
1519 		{	crSceneReferred,	"Scene Referred"	},
1520 		{	crICCProfilePCS,	"ICC Profile PCS"	}
1521 		};
1522 
1523 	const char *name = LookupName (key,
1524 								   kColorimetricReferenceNames,
1525 								   sizeof (kColorimetricReferenceNames    ) /
1526 								   sizeof (kColorimetricReferenceNames [0]));
1527 
1528 	if (name)
1529 		{
1530 		return name;
1531 		}
1532 
1533 	static char s [32];
1534 
1535 	sprintf (s, "%u", (unsigned) key);
1536 
1537 	return s;
1538 
1539 	}
1540 
1541 /*****************************************************************************/
1542 
LookupPreviewColorSpace(uint32 key)1543 const char * LookupPreviewColorSpace (uint32 key)
1544 	{
1545 
1546 	const dng_name_table kPreviewColorSpaceNames [] =
1547 		{
1548 		{	previewColorSpace_Unknown    ,	"Unknown"			},
1549 		{	previewColorSpace_GrayGamma22,	"Gray Gamma 2.2"	},
1550 		{	previewColorSpace_sRGB       ,	"sRGB"				},
1551 		{	previewColorSpace_AdobeRGB   ,	"Adobe RGB (1998)"	},
1552 		{	previewColorSpace_ProPhotoRGB,	"Pro Photo RGB"	    }
1553 		};
1554 
1555 	const char *name = LookupName (key,
1556 								   kPreviewColorSpaceNames,
1557 								   sizeof (kPreviewColorSpaceNames    ) /
1558 								   sizeof (kPreviewColorSpaceNames [0]));
1559 
1560 	if (name)
1561 		{
1562 		return name;
1563 		}
1564 
1565 	static char s [32];
1566 
1567 	sprintf (s, "%u", (unsigned) key);
1568 
1569 	return s;
1570 
1571 	}
1572 
1573 /*****************************************************************************/
1574 
LookupJPEGMarker(uint32 key)1575 const char * LookupJPEGMarker (uint32 key)
1576 	{
1577 
1578 	const dng_name_table kJPEGMarkerNames [] =
1579 		{
1580 		{	M_TEM,		"TEM"	},
1581 		{	M_SOF0,		"SOF0"	},
1582 		{	M_SOF1,		"SOF1"	},
1583 		{	M_SOF2,		"SOF2"	},
1584 		{	M_SOF3,		"SOF3"	},
1585 		{	M_DHT,		"DHT"	},
1586 		{	M_SOF5,		"SOF5"	},
1587 		{	M_SOF6,		"SOF6"	},
1588 		{	M_SOF7,		"SOF7"	},
1589 		{	M_JPG,		"JPG"	},
1590 		{	M_SOF9,		"SOF9"	},
1591 		{	M_SOF10,	"SOF10"	},
1592 		{	M_SOF11,	"SOF11"	},
1593 		{	M_DAC,		"DAC"	},
1594 		{	M_SOF13,	"SOF13"	},
1595 		{	M_SOF14,	"SOF14"	},
1596 		{	M_SOF15,	"SOF15"	},
1597 		{	M_RST0,		"RST0"	},
1598 		{	M_RST1,		"RST1"	},
1599 		{	M_RST2,		"RST2"	},
1600 		{	M_RST3,		"RST3"	},
1601 		{	M_RST4,		"RST4"	},
1602 		{	M_RST5,		"RST5"	},
1603 		{	M_RST6,		"RST6"	},
1604 		{	M_RST7,		"RST7"	},
1605 		{	M_SOI,		"SOI"	},
1606 		{	M_EOI,		"EOI"	},
1607 		{	M_SOS,		"SOS"	},
1608 		{	M_DQT,		"DQT"	},
1609 		{	M_DNL,		"DNL"	},
1610 		{	M_DRI,		"DRI"	},
1611 		{	M_DHP,		"DHP"	},
1612 		{	M_EXP,		"EXP"	},
1613 		{	M_APP0,		"APP0"	},
1614 		{	M_APP1,		"APP1"	},
1615 		{	M_APP2,		"APP2"	},
1616 		{	M_APP3,		"APP3"	},
1617 		{	M_APP4,		"APP4"	},
1618 		{	M_APP5,		"APP5"	},
1619 		{	M_APP6,		"APP6"	},
1620 		{	M_APP7,		"APP7"	},
1621 		{	M_APP8,		"APP8"	},
1622 		{	M_APP9,		"APP9"	},
1623 		{	M_APP10,	"APP10"	},
1624 		{	M_APP11,	"APP11"	},
1625 		{	M_APP12,	"APP12"	},
1626 		{	M_APP13,	"APP13"	},
1627 		{	M_APP14,	"APP14"	},
1628 		{	M_APP15,	"APP15"	},
1629 		{	M_JPG0,		"JPG0"	},
1630 		{	M_JPG1,		"JPG1"	},
1631 		{	M_JPG2,		"JPG2"	},
1632 		{	M_JPG3,		"JPG3"	},
1633 		{	M_JPG4,		"JPG4"	},
1634 		{	M_JPG5,		"JPG5"	},
1635 		{	M_JPG6,		"JPG6"	},
1636 		{	M_JPG7,		"JPG7"	},
1637 		{	M_JPG8,		"JPG8"	},
1638 		{	M_JPG9,		"JPG9"	},
1639 		{	M_JPG10,	"JPG10"	},
1640 		{	M_JPG11,	"JPG11"	},
1641 		{	M_JPG12,	"JPG12"	},
1642 		{	M_JPG13,	"JPG13"	},
1643 		{	M_COM,		"COM"	},
1644 		{	M_ERROR,	"ERROR"	}
1645 		};
1646 
1647 	const char *name = LookupName (key,
1648 								   kJPEGMarkerNames,
1649 								   sizeof (kJPEGMarkerNames    ) /
1650 								   sizeof (kJPEGMarkerNames [0]));
1651 
1652 	if (name)
1653 		{
1654 		return name;
1655 		}
1656 
1657 	static char s [32];
1658 
1659 	sprintf (s, "0x%02X", (unsigned) key);
1660 
1661 	return s;
1662 
1663 	}
1664 
1665 /*****************************************************************************/
1666 
LookupSensitivityType(uint32 key)1667 const char * LookupSensitivityType (uint32 key)
1668 	{
1669 
1670 	const dng_name_table kSensitivityTypeNames [] =
1671 		{
1672 		{	stUnknown,					 "Unknown"																				},
1673 		{	stStandardOutputSensitivity, "Standard Output Sensitivity (SOS)"													},
1674 		{	stRecommendedExposureIndex,	 "Recommended Exposure Index (REI)"														},
1675 		{	stISOSpeed,					 "ISO Speed"																			},
1676 		{	stSOSandREI,				 "Standard Output Sensitivity (SOS) and Recommended Exposure Index (REI)"				},
1677 		{	stSOSandISOSpeed,			 "Standard Output Sensitivity (SOS) and ISO Speed"										},
1678 		{	stREIandISOSpeed,			 "Recommended Exposure Index (REI) and ISO Speed"										},
1679 		{	stSOSandREIandISOSpeed,		 "Standard Output Sensitivity (SOS) and Recommended Exposure Index (REI) and ISO Speed" },
1680 		};
1681 
1682 	const char *name = LookupName (key,
1683 								   kSensitivityTypeNames,
1684 								   sizeof (kSensitivityTypeNames	) /
1685 								   sizeof (kSensitivityTypeNames [0]));
1686 
1687 	if (name)
1688 		{
1689 		return name;
1690 		}
1691 
1692 	static char s [32];
1693 
1694 	sprintf (s, "%u", (unsigned) key);
1695 
1696 	return s;
1697 
1698 	}
1699 
1700 /*****************************************************************************/
1701 
DumpHexAscii(dng_stream & stream,uint32 count)1702 void DumpHexAscii (dng_stream &stream,
1703 				   uint32 count)
1704 	{
1705 
1706 	uint32 rows = (count + 15) >> 4;
1707 
1708 	if (rows > gDumpLineLimit)
1709 		rows = gDumpLineLimit;
1710 
1711 	for (uint32 row = 0; row < rows; row++)
1712 		{
1713 
1714 		printf ("    ");
1715 
1716 		uint32 col;
1717 
1718 		uint32 cols = count - (row << 4);
1719 
1720 		if (cols > 16)
1721 			cols = 16;
1722 
1723 		uint8 x [16];
1724 
1725 		for (col = 0; col < 16; col++)
1726 			{
1727 
1728 			x [col] = ' ';
1729 
1730 			if (col < cols)
1731 				{
1732 
1733 				x [col] = stream.Get_uint8 ();
1734 
1735 				printf ("%02x ", x [col]);
1736 
1737 				}
1738 
1739 			else
1740 				{
1741 				printf ("   ");
1742 				}
1743 
1744 			}
1745 
1746 		printf ("   ");
1747 
1748 		for (col = 0; col < 16; col++)
1749 			{
1750 
1751 			if (x [col] >= (uint8) ' ' && x [col] <= (uint8) '~')
1752 				{
1753 				printf ("%c", x [col]);
1754 				}
1755 
1756 			else
1757 				{
1758 				printf (".");
1759 				}
1760 
1761 			}
1762 
1763 		printf ("\n");
1764 
1765 		}
1766 
1767 	if (count > rows * 16)
1768 		{
1769 		printf ("    ... %u more bytes\n", (unsigned) (count - rows * 16));
1770 		}
1771 
1772 	}
1773 
1774 /*****************************************************************************/
1775 
DumpHexAscii(const uint8 * buf,uint32 count)1776 void DumpHexAscii (const uint8 *buf,
1777 				   uint32 count)
1778 	{
1779 
1780 	uint32 rows = (count + 15) >> 4;
1781 
1782 	if (rows > gDumpLineLimit)
1783 		rows = gDumpLineLimit;
1784 
1785 	for (uint32 row = 0; row < rows; row++)
1786 		{
1787 
1788 		printf ("    ");
1789 
1790 		uint32 col;
1791 
1792 		uint32 cols = count - (row << 4);
1793 
1794 		if (cols > 16)
1795 			cols = 16;
1796 
1797 		uint8 x [16];
1798 
1799 		for (col = 0; col < 16; col++)
1800 			{
1801 
1802 			x [col] = ' ';
1803 
1804 			if (col < cols)
1805 				{
1806 
1807 				x [col] = *(buf++);
1808 
1809 				printf ("%02x ", x [col]);
1810 
1811 				}
1812 
1813 			else
1814 				{
1815 				printf ("   ");
1816 				}
1817 
1818 			}
1819 
1820 		printf ("   ");
1821 
1822 		for (col = 0; col < 16; col++)
1823 			{
1824 
1825 			if (x [col] >= (uint8) ' ' && x [col] <= (uint8) '~')
1826 				{
1827 				printf ("%c", x [col]);
1828 				}
1829 
1830 			else
1831 				{
1832 				printf (".");
1833 				}
1834 
1835 			}
1836 
1837 		printf ("\n");
1838 
1839 		}
1840 
1841 	if (count > rows * 16)
1842 		{
1843 		printf ("    ... %u more bytes\n", (unsigned) (count - rows * 16));
1844 		}
1845 
1846 	}
1847 
1848 /*****************************************************************************/
1849 
DumpXMP(dng_stream & stream,uint32 count)1850 void DumpXMP (dng_stream &stream,
1851 			  uint32 count)
1852 	{
1853 
1854 	uint32 lineLength = 0;
1855 
1856 	while (count > 0)
1857 		{
1858 
1859 		uint32 x = stream.Get_uint8 ();
1860 
1861 		if (x == 0) break;
1862 
1863 		count--;
1864 
1865 		if (lineLength == 0)
1866 			{
1867 
1868 			printf ("XMP: ");
1869 
1870 			lineLength = 5;
1871 
1872 			}
1873 
1874 		if (x == '\n' ||
1875 			x == '\r')
1876 			{
1877 
1878 			printf ("\n");
1879 
1880 			lineLength = 0;
1881 
1882 			}
1883 
1884 		else
1885 			{
1886 
1887 			if (lineLength >= 128)
1888 				{
1889 
1890 				printf ("\nXMP: ");
1891 
1892 				lineLength = 5;
1893 
1894 				}
1895 
1896 			if (x >= ' ' && x <= '~')
1897 				{
1898 
1899 				printf ("%c", (char) x);
1900 
1901 				lineLength += 1;
1902 
1903 				}
1904 
1905 			else
1906 				{
1907 
1908 				printf ("\\%03o", (unsigned) x);
1909 
1910 				lineLength += 4;
1911 
1912 				}
1913 
1914 			}
1915 
1916 		}
1917 
1918 	if (lineLength != 0)
1919 		{
1920 
1921 		printf ("\n");
1922 
1923 		}
1924 
1925 	}
1926 
1927 /*****************************************************************************/
1928 
DumpString(const dng_string & s)1929 void DumpString (const dng_string &s)
1930 	{
1931 
1932 	const uint32 kMaxDumpString = gDumpLineLimit * 64;
1933 
1934 	printf ("\"");
1935 
1936 	const char *ss = s.Get ();
1937 
1938 	uint32 total = 0;
1939 
1940 	while (*ss != 0 && total++ < kMaxDumpString)
1941 		{
1942 
1943 		uint32 c = dng_string::DecodeUTF8 (ss);
1944 
1945 		if (c >= ' ' && c <= '~')
1946 			{
1947 			printf ("%c", (char) c);
1948 			}
1949 
1950 		else switch (c)
1951 			{
1952 
1953 			case '\t':
1954 				{
1955 				printf ("\\t");
1956 				break;
1957 				}
1958 
1959 			case '\n':
1960 				{
1961 				printf ("\\n");
1962 				break;
1963 				}
1964 
1965 			case '\r':
1966 				{
1967 				printf ("\\r");
1968 				break;
1969 				}
1970 
1971 			default:
1972 				{
1973 				printf ("[%X]", (unsigned) c);
1974 				}
1975 
1976 			}
1977 
1978 		}
1979 
1980 	uint32 extra = (uint32) strlen (ss);
1981 
1982 	if (extra > 0)
1983 		{
1984 		printf ("...\" (%u more bytes)", (unsigned) extra);
1985 		}
1986 
1987 	else
1988 		{
1989 		printf ("\"");
1990 		}
1991 
1992 	}
1993 
1994 /*****************************************************************************/
1995 
DumpTagValues(dng_stream & stream,const char * entry_name,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,const char * tag_name)1996 void DumpTagValues (dng_stream &stream,
1997 					const char *entry_name,
1998 					uint32 parentCode,
1999 					uint32 tagCode,
2000 					uint32 tagType,
2001 					uint32 tagCount,
2002 					const char *tag_name)
2003 	{
2004 
2005 	const uint32 kMaxDumpSingleLine = 4;
2006 
2007 	const uint32 kMaxDumpArray = Max_uint32 (gDumpLineLimit, kMaxDumpSingleLine);
2008 
2009 	printf ("%s:", tag_name ? tag_name
2010 							: LookupTagCode (parentCode, tagCode));
2011 
2012 	switch (tagType)
2013 		{
2014 
2015 		case ttShort:
2016 		case ttLong:
2017 		case ttIFD:
2018 		case ttSByte:
2019 		case ttSShort:
2020 		case ttSLong:
2021 		case ttRational:
2022 		case ttSRational:
2023 		case ttFloat:
2024 		case ttDouble:
2025 			{
2026 
2027 			if (tagCount > kMaxDumpSingleLine)
2028 				{
2029 
2030 				printf (" %u entries", (unsigned) tagCount);
2031 
2032 				}
2033 
2034 			for (uint32 j = 0; j < tagCount && j < kMaxDumpArray; j++)
2035 				{
2036 
2037 				if (tagCount <= kMaxDumpSingleLine)
2038 					{
2039 
2040 					if (j == 0)
2041 						{
2042 
2043 						printf (" %s =", entry_name);
2044 
2045 						}
2046 
2047 					printf (" ");
2048 
2049 					}
2050 
2051 				else
2052 					{
2053 
2054 					printf ("\n    %s [%u] = ", entry_name, (unsigned) j);
2055 
2056 					}
2057 
2058 				switch (tagType)
2059 					{
2060 
2061 					case ttByte:
2062 					case ttShort:
2063 					case ttLong:
2064 					case ttIFD:
2065 						{
2066 
2067 						uint32 x = stream.TagValue_uint32 (tagType);
2068 
2069 						printf ("%u", (unsigned) x);
2070 
2071 						break;
2072 
2073 						}
2074 
2075 					case ttSByte:
2076 					case ttSShort:
2077 					case ttSLong:
2078 						{
2079 
2080 						int32 x = stream.TagValue_int32 (tagType);
2081 
2082 						printf ("%d", (int) x);
2083 
2084 						break;
2085 
2086 						}
2087 
2088 					case ttRational:
2089 						{
2090 
2091 						dng_urational x = stream.TagValue_urational (tagType);
2092 
2093 						printf ("%u/%u", (unsigned) x.n, (unsigned) x.d);
2094 
2095 						break;
2096 
2097 						}
2098 
2099 					case ttSRational:
2100 						{
2101 
2102 						dng_srational x = stream.TagValue_srational (tagType);
2103 
2104 						printf ("%d/%d", (int) x.n, (int) x.d);
2105 
2106 						break;
2107 
2108 						}
2109 
2110 					default:
2111 						{
2112 
2113 						real64 x = stream.TagValue_real64 (tagType);
2114 
2115 						printf ("%f", x);
2116 
2117 						}
2118 
2119 					}
2120 
2121 				}
2122 
2123 			printf ("\n");
2124 
2125 			if (tagCount > kMaxDumpArray)
2126 				{
2127 
2128 				printf ("    ... %u more entries\n", (unsigned) (tagCount - kMaxDumpArray));
2129 
2130 				}
2131 
2132 			break;
2133 
2134 			}
2135 
2136 		case ttAscii:
2137 			{
2138 
2139 			dng_string s;
2140 
2141 			ParseStringTag (stream,
2142 							parentCode,
2143 							tagCode,
2144 							tagCount,
2145 							s,
2146 							false);
2147 
2148 			printf (" ");
2149 
2150 			DumpString (s);
2151 
2152 			printf ("\n");
2153 
2154 			break;
2155 
2156 			}
2157 
2158 		default:
2159 			{
2160 
2161 			uint32 tagSize = tagCount * TagTypeSize (tagType);
2162 
2163 			if (tagCount == 1 && (tagType == ttByte ||
2164 								  tagType == ttUndefined))
2165 				{
2166 
2167 				uint8 x = stream.Get_uint8 ();
2168 
2169 				printf (" %s = %u\n", LookupTagType (tagType), x);
2170 
2171 				}
2172 
2173 			else
2174 				{
2175 
2176 				printf (" %s, size = %u\n", LookupTagType (tagType), (unsigned) tagSize);
2177 
2178 				DumpHexAscii (stream, tagSize);
2179 
2180 				}
2181 
2182 			}
2183 
2184 		}
2185 
2186 	}
2187 
2188 /*****************************************************************************/
2189 
DumpMatrix(const dng_matrix & m)2190 void DumpMatrix (const dng_matrix &m)
2191 	{
2192 
2193 	for (uint32 row = 0; row < m.Rows (); row++)
2194 		{
2195 
2196 		for (uint32 col = 0; col < m.Cols (); col++)
2197 			{
2198 
2199 			if (col == 0)
2200 				printf ("    ");
2201 			else
2202 				printf (" ");
2203 
2204 			printf ("%8.4f", m [row] [col]);
2205 
2206 			}
2207 
2208 		printf ("\n");
2209 
2210 		}
2211 
2212 	}
2213 
2214 /*****************************************************************************/
2215 
DumpVector(const dng_vector & v)2216 void DumpVector (const dng_vector &v)
2217 	{
2218 
2219 	for (uint32 index = 0; index < v.Count (); index++)
2220 		{
2221 
2222 		printf (" %0.4f", v [index]);
2223 
2224 		}
2225 
2226 	printf ("\n");
2227 
2228 	}
2229 
2230 /*****************************************************************************/
2231 
DumpDateTime(const dng_date_time & dt)2232 void DumpDateTime (const dng_date_time &dt)
2233 	{
2234 
2235 	printf ("%04d:%02d:%02d %02d:%02d:%02d",
2236 			(int) dt.fYear,
2237 			(int) dt.fMonth,
2238 			(int) dt.fDay,
2239 			(int) dt.fHour,
2240 			(int) dt.fMinute,
2241 			(int) dt.fSecond);
2242 
2243 	}
2244 
2245 /*****************************************************************************/
2246 
DumpExposureTime(real64 x)2247 void DumpExposureTime (real64 x)
2248 	{
2249 
2250 	if (x > 0.0)
2251 		{
2252 
2253 		if (x >= 0.25)
2254 			{
2255 			printf ("%0.2f sec", x);
2256 			}
2257 
2258 		else if (x >= 0.01)
2259 			{
2260 			printf ("1/%0.1f sec", 1.0 / x);
2261 			}
2262 
2263 		else
2264 			{
2265 			printf ("1/%0.0f sec", 1.0 / x);
2266 			}
2267 
2268 		}
2269 
2270 	else
2271 		{
2272 
2273 		printf ("<invalid>");
2274 
2275 		}
2276 
2277 	}
2278 
2279 /*****************************************************************************/
2280 
DumpFingerprint(const dng_fingerprint & p)2281 void DumpFingerprint (const dng_fingerprint &p)
2282 	{
2283 
2284 	printf ("<");
2285 
2286 	for (uint32 j = 0; j < 16; j++)
2287 		{
2288 		printf ("%02x", p.data [j]);
2289 		}
2290 
2291 	printf (">");
2292 
2293 	}
2294 
2295 /*****************************************************************************/
2296 
DumpHueSatMap(dng_stream & stream,uint32 hues,uint32 sats,uint32 vals,bool skipSat0)2297 void DumpHueSatMap (dng_stream &stream,
2298 				    uint32 hues,
2299 					uint32 sats,
2300 					uint32 vals,
2301 					bool skipSat0)
2302 	{
2303 
2304 	uint32 doneLines = 0;
2305 	uint32 skipLines = 0;
2306 
2307 	for (uint32 v = 0; v < vals; v++)
2308 		{
2309 
2310 		for (uint32 h = 0; h < hues; h++)
2311 			{
2312 
2313 			for (uint32 s = skipSat0 ? 1 : 0; s < sats; s++)
2314 				{
2315 
2316 				real32 dh = stream.Get_real32 ();
2317 				real32 ds = stream.Get_real32 ();
2318 				real32 dv = stream.Get_real32 ();
2319 
2320 				if (gDumpLineLimit == 0 ||
2321 					gDumpLineLimit > doneLines)
2322 					{
2323 
2324 					doneLines++;
2325 
2326 					if (vals == 1)
2327 						{
2328 
2329 						printf ("    h [%2u] s [%2u]:  h=%8.4f s=%6.4f v=%6.4f\n",
2330 								(unsigned) h,
2331 								(unsigned) s,
2332 								(double) dh,
2333 								(double) ds,
2334 								(double) dv);
2335 
2336 						}
2337 
2338 					else
2339 						{
2340 
2341 						printf ("    v [%2u] h [%2u] s [%2u]:  h=%8.4f s=%6.4f v=%6.4f\n",
2342 								(unsigned) v,
2343 								(unsigned) h,
2344 								(unsigned) s,
2345 								(double) dh,
2346 								(double) ds,
2347 								(double) dv);
2348 
2349 						}
2350 
2351 					}
2352 
2353 				else
2354 					{
2355 
2356 					skipLines++;
2357 
2358 					}
2359 
2360 				}
2361 
2362 			}
2363 
2364 		}
2365 
2366 	if (skipLines > 0)
2367 		{
2368 
2369 		printf ("    ... %u more entries\n", (unsigned) skipLines);
2370 
2371 		}
2372 
2373 	}
2374 
2375 /*****************************************************************************/
2376 
2377 #endif
2378 
2379 /*****************************************************************************/
2380 
CheckTagType(uint32 parentCode,uint32 tagCode,uint32 tagType,uint16 validType0,uint16 validType1,uint16 validType2,uint16 validType3)2381 bool CheckTagType (uint32 parentCode,
2382 				   uint32 tagCode,
2383 				   uint32 tagType,
2384 				   uint16 validType0,
2385 				   uint16 validType1,
2386 				   uint16 validType2,
2387 				   uint16 validType3)
2388 	{
2389 
2390 	if (tagType != validType0 &&
2391 		tagType != validType1 &&
2392 		tagType != validType2 &&
2393 		tagType != validType3)
2394 		{
2395 
2396 		#if qDNGValidate
2397 
2398 			{
2399 
2400 			char message [256];
2401 
2402 			sprintf (message,
2403 					 "%s %s has unexpected type (%s)",
2404 					 LookupParentCode (parentCode),
2405 					 LookupTagCode (parentCode, tagCode),
2406 					 LookupTagType (tagType));
2407 
2408 			ReportWarning (message);
2409 
2410 			}
2411 
2412 		#else
2413 
2414 		(void) parentCode;		// Unused
2415 		(void) tagCode;		// Unused
2416 
2417 		#endif
2418 
2419 		return false;
2420 
2421 		}
2422 
2423 	return true;
2424 
2425 	}
2426 
2427 /*****************************************************************************/
2428 
CheckTagCount(uint32 parentCode,uint32 tagCode,uint32 tagCount,uint32 minCount,uint32 maxCount)2429 bool CheckTagCount (uint32 parentCode,
2430 					uint32 tagCode,
2431 				    uint32 tagCount,
2432 				    uint32 minCount,
2433 				    uint32 maxCount)
2434 	{
2435 
2436 	if (maxCount < minCount)
2437 		maxCount = minCount;
2438 
2439 	if (tagCount < minCount ||
2440 		tagCount > maxCount)
2441 		{
2442 
2443 		#if qDNGValidate
2444 
2445 			{
2446 
2447 			char message [256];
2448 
2449 			sprintf (message,
2450 					 "%s %s has unexpected count (%u)",
2451 					 LookupParentCode (parentCode),
2452 					 LookupTagCode (parentCode, tagCode),
2453 					 (unsigned) tagCount);
2454 
2455 			ReportWarning (message);
2456 
2457 			}
2458 
2459 		#else
2460 
2461 		(void) parentCode;		// Unused
2462 		(void) tagCode;		// Unused
2463 
2464 		#endif
2465 
2466 		return false;
2467 
2468 		}
2469 
2470 	return true;
2471 
2472 	}
2473 
2474 /*****************************************************************************/
2475 
CheckColorImage(uint32 parentCode,uint32 tagCode,uint32 colorPlanes)2476 bool CheckColorImage (uint32 parentCode,
2477 					  uint32 tagCode,
2478 				      uint32 colorPlanes)
2479 	{
2480 
2481 	if (colorPlanes == 0)
2482 		{
2483 
2484 		#if qDNGValidate
2485 
2486 			{
2487 
2488 			char message [256];
2489 
2490 			sprintf (message,
2491 					 "%s %s is not allowed with unknown color plane count "
2492 					 " (missing ColorMatrix1 tag?)",
2493 					 LookupParentCode (parentCode),
2494 					 LookupTagCode (parentCode, tagCode));
2495 
2496 			ReportWarning (message);
2497 
2498 			}
2499 
2500 		#else
2501 
2502 		(void) parentCode;		// Unused
2503 		(void) tagCode;		// Unused
2504 
2505 		#endif
2506 
2507 		return false;
2508 
2509 		}
2510 
2511 	if (colorPlanes == 1)
2512 		{
2513 
2514 		#if qDNGValidate
2515 
2516 			{
2517 
2518 			char message [256];
2519 
2520 			sprintf (message,
2521 					 "%s %s is not allowed with monochrome images",
2522 					 LookupParentCode (parentCode),
2523 					 LookupTagCode (parentCode, tagCode));
2524 
2525 			ReportWarning (message);
2526 
2527 			}
2528 
2529 		#endif
2530 
2531 		return false;
2532 
2533 		}
2534 
2535 	return true;
2536 
2537 	}
2538 
2539 /*****************************************************************************/
2540 
CheckMainIFD(uint32 parentCode,uint32 tagCode,uint32 newSubFileType)2541 bool CheckMainIFD (uint32 parentCode,
2542 				   uint32 tagCode,
2543 				   uint32 newSubFileType)
2544 	{
2545 
2546 	if (newSubFileType != sfMainImage)
2547 		{
2548 
2549 		#if qDNGValidate
2550 
2551 			{
2552 
2553 			char message [256];
2554 
2555 			sprintf (message,
2556 					 "%s %s is not allowed IFDs with NewSubFileType != 0",
2557 					 LookupParentCode (parentCode),
2558 					 LookupTagCode (parentCode, tagCode));
2559 
2560 			ReportWarning (message);
2561 
2562 			}
2563 
2564 		#else
2565 
2566 		(void) parentCode;		// Unused
2567 		(void) tagCode;			// Unused
2568 
2569 		#endif
2570 
2571 		return false;
2572 
2573 		}
2574 
2575 	return true;
2576 
2577 	}
2578 
2579 /*****************************************************************************/
2580 
CheckRawIFD(uint32 parentCode,uint32 tagCode,uint32 photometricInterpretation)2581 bool CheckRawIFD (uint32 parentCode,
2582 				  uint32 tagCode,
2583 				  uint32 photometricInterpretation)
2584 	{
2585 
2586 	if (photometricInterpretation != piCFA &&
2587 		photometricInterpretation != piLinearRaw)
2588 		{
2589 
2590 		#if qDNGValidate
2591 
2592 			{
2593 
2594 			char message [256];
2595 
2596 			sprintf (message,
2597 					 "%s %s is not allowed in IFDs with a non-raw PhotometricInterpretation",
2598 					 LookupParentCode (parentCode),
2599 					 LookupTagCode (parentCode, tagCode));
2600 
2601 			ReportWarning (message);
2602 
2603 			}
2604 
2605 		#else
2606 
2607 		(void) parentCode;		// Unused
2608 		(void) tagCode;			// Unused
2609 
2610 		#endif
2611 
2612 		return false;
2613 
2614 		}
2615 
2616 	return true;
2617 
2618 	}
2619 
2620 /*****************************************************************************/
2621 
CheckCFA(uint32 parentCode,uint32 tagCode,uint32 photometricInterpretation)2622 bool CheckCFA (uint32 parentCode,
2623 			   uint32 tagCode,
2624 		       uint32 photometricInterpretation)
2625 	{
2626 
2627 	if (photometricInterpretation != piCFA)
2628 		{
2629 
2630 		#if qDNGValidate
2631 
2632 			{
2633 
2634 			char message [256];
2635 
2636 			sprintf (message,
2637 					 "%s %s is not allowed in IFDs with a non-CFA PhotometricInterpretation",
2638 					 LookupParentCode (parentCode),
2639 					 LookupTagCode (parentCode, tagCode));
2640 
2641 			ReportWarning (message);
2642 
2643 			}
2644 
2645 		#else
2646 
2647 		(void) parentCode;		// Unused
2648 		(void) tagCode;			// Unused
2649 
2650 		#endif
2651 
2652 		return false;
2653 
2654 		}
2655 
2656 	return true;
2657 
2658 	}
2659 
2660 /*****************************************************************************/
2661 
ParseStringTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagCount,dng_string & s,bool trimBlanks)2662 void ParseStringTag (dng_stream &stream,
2663 					 uint32 parentCode,
2664 					 uint32 tagCode,
2665 				     uint32 tagCount,
2666 				     dng_string &s,
2667 				     bool trimBlanks)
2668 	{
2669 
2670 	if (tagCount == 0 ||
2671 		tagCount == 0xFFFFFFFF)
2672 		{
2673 
2674 		s.Clear ();
2675 
2676 		return;
2677 
2678 		}
2679 
2680 	dng_memory_data temp_buffer (tagCount + 1);
2681 
2682 	char *buffer = temp_buffer.Buffer_char ();
2683 
2684 	stream.Get (buffer, tagCount);
2685 
2686 	// Make sure the string is null terminated.
2687 
2688 	if (buffer [tagCount - 1] != 0)
2689 		{
2690 
2691 		buffer [tagCount] = 0;
2692 
2693 		#if qDNGValidate
2694 
2695 			{
2696 
2697 			bool hasNull = false;
2698 
2699 			for (uint32 j = 0; j < tagCount; j++)
2700 				{
2701 
2702 				if (buffer [j] == 0)
2703 					{
2704 
2705 					hasNull = true;
2706 
2707 					break;
2708 
2709 					}
2710 
2711 				}
2712 
2713 			if (!hasNull && parentCode < tcFirstMakerNoteIFD)
2714 				{
2715 
2716 				char message [256];
2717 
2718 				sprintf (message,
2719 						 "%s %s is not NULL terminated",
2720 						 LookupParentCode (parentCode),
2721 						 LookupTagCode (parentCode, tagCode));
2722 
2723 				ReportWarning (message);
2724 
2725 				}
2726 
2727 			}
2728 
2729 		#else
2730 
2731 		(void) parentCode;		// Unused
2732 		(void) tagCode;			// Unused
2733 
2734 		#endif
2735 
2736 		}
2737 
2738 	// Medata working group - Allow UTF-8
2739 
2740 	s.Set_UTF8_or_System (buffer);
2741 
2742 	if (trimBlanks)
2743 		{
2744 
2745 		s.TrimTrailingBlanks ();
2746 
2747 		}
2748 
2749 	}
2750 
2751 /*****************************************************************************/
2752 
ParseDualStringTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagCount,dng_string & s1,dng_string & s2)2753 void ParseDualStringTag (dng_stream &stream,
2754 					 	 uint32 parentCode,
2755 					 	 uint32 tagCode,
2756 				     	 uint32 tagCount,
2757 				     	 dng_string &s1,
2758 				     	 dng_string &s2)
2759 	{
2760 
2761 	if (tagCount == 0 ||
2762 		tagCount == 0xFFFFFFFF)
2763 		{
2764 
2765 		s1.Clear ();
2766 		s2.Clear ();
2767 
2768 		return;
2769 
2770 		}
2771 
2772 	dng_memory_data temp_buffer (tagCount + 1);
2773 
2774 	char *buffer = temp_buffer.Buffer_char ();
2775 
2776 	stream.Get (buffer, tagCount);
2777 
2778 	// Make sure the string is null terminated.
2779 
2780 	if (buffer [tagCount - 1] != 0)
2781 		{
2782 
2783 		buffer [tagCount] = 0;
2784 
2785 		#if qDNGValidate
2786 
2787 			{
2788 
2789 			uint32 nullCount = 0;
2790 
2791 			for (uint32 j = 0; j < tagCount; j++)
2792 				{
2793 
2794 				if (buffer [j] == 0)
2795 					{
2796 
2797 					nullCount++;
2798 
2799 					}
2800 
2801 				}
2802 
2803 			if (nullCount < 2 && parentCode < tcFirstMakerNoteIFD)
2804 				{
2805 
2806 				char message [256];
2807 
2808 				sprintf (message,
2809 						 "%s %s is not NULL terminated",
2810 						 LookupParentCode (parentCode),
2811 						 LookupTagCode (parentCode, tagCode));
2812 
2813 				ReportWarning (message);
2814 
2815 				}
2816 
2817 			}
2818 
2819 		#else
2820 
2821 		(void) parentCode;		// Unused
2822 		(void) tagCode;			// Unused
2823 
2824 		#endif
2825 
2826 		}
2827 
2828 	// Medata working group - Allow UTF-8
2829 
2830 	s1.Set_UTF8_or_System (buffer);
2831 
2832 	s2.Set_ASCII (NULL);
2833 
2834 	for (uint32 j = 1; j < tagCount - 1; j++)
2835 		{
2836 
2837 		if (buffer [j - 1] != 0 &&
2838 			buffer [j    ] == 0)
2839 			{
2840 
2841 			// Medata working group - Allow UTF-8
2842 
2843 			s2.Set_UTF8_or_System (buffer + j + 1);
2844 
2845 			break;
2846 
2847 			}
2848 
2849 		}
2850 
2851 	s1.TrimTrailingBlanks ();
2852 	s2.TrimTrailingBlanks ();
2853 
2854 	}
2855 
2856 /*****************************************************************************/
2857 
ParseEncodedStringTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagCount,dng_string & s)2858 void ParseEncodedStringTag (dng_stream &stream,
2859 							uint32 parentCode,
2860 							uint32 tagCode,
2861 				    		uint32 tagCount,
2862 				    		dng_string &s)
2863 	{
2864 
2865 	if (tagCount < 8)
2866 		{
2867 
2868 		#if qDNGValidate
2869 
2870 			{
2871 
2872 			char message [256];
2873 
2874 			sprintf (message,
2875 					 "%s %s has unexpected count (%u)",
2876 					 LookupParentCode (parentCode),
2877 					 LookupTagCode (parentCode, tagCode),
2878 					 (unsigned) tagCount);
2879 
2880 			ReportWarning (message);
2881 
2882 			}
2883 
2884 		#else
2885 
2886 		(void) parentCode;		// Unused
2887 		(void) tagCode;			// Unused
2888 
2889 		#endif
2890 
2891 		s.Clear ();
2892 
2893 		return;
2894 
2895 		}
2896 
2897 	char label [8];
2898 
2899 	stream.Get (label, 8);
2900 
2901 	// Sometimes lowercase is used by mistake.  Accept this, but issue
2902 	// warning.
2903 
2904 		{
2905 
2906 		bool hadLower = false;
2907 
2908 		for (uint32 j = 0; j < 8; j++)
2909 			{
2910 
2911 			if (label [j] >= 'a' && label [j] <= 'z')
2912 				{
2913 
2914 				label [j] = 'A' + (label [j] - 'a');
2915 
2916 				hadLower = true;
2917 
2918 				}
2919 
2920 			}
2921 
2922 		#if qDNGValidate
2923 
2924 		if (hadLower)
2925 			{
2926 
2927 			char message [256];
2928 
2929 			sprintf (message,
2930 					 "%s %s text encoding label not all uppercase",
2931 					 LookupParentCode (parentCode),
2932 					 LookupTagCode (parentCode, tagCode));
2933 
2934 			ReportWarning (message);
2935 
2936 			}
2937 
2938 		#endif
2939 
2940 		}
2941 
2942 	if (memcmp (label, "UNICODE\000", 8) == 0)
2943 		{
2944 
2945 		uint32 uChars = (tagCount - 8) >> 1;
2946 
2947 		dng_memory_data temp_buffer ((uChars + 1) * 2);
2948 
2949 		uint16 *buffer = temp_buffer.Buffer_uint16 ();
2950 
2951 		for (uint32 j = 0; j < uChars; j++)
2952 			{
2953 
2954 			buffer [j] = stream.Get_uint16 ();
2955 
2956 			}
2957 
2958 		buffer [uChars] = 0;
2959 
2960 		#if qDNGValidate
2961 
2962 			{
2963 
2964 			// If the writer used UTF-8 rather than UTF-16, and padded
2965 			// the string with blanks, then there will be lots of 0x2020
2966 			// (unicode dagger symbol) characters in the string.
2967 
2968 			uint32 count2020 = 0;
2969 
2970 			for (uint32 k = 0; buffer [k] != 0; k++)
2971 				{
2972 
2973 				if (buffer [k] == 0x2020)
2974 					{
2975 
2976 					count2020++;
2977 
2978 					}
2979 
2980 				}
2981 
2982 			if (count2020 > 1)
2983 				{
2984 
2985 				char message [256];
2986 
2987 				sprintf (message,
2988 						 "%s %s text appears to be UTF-8 rather than UTF-16",
2989 						 LookupParentCode (parentCode),
2990 						 LookupTagCode (parentCode, tagCode));
2991 
2992 				ReportWarning (message);
2993 
2994 				}
2995 
2996 			}
2997 
2998 		#endif
2999 
3000 		s.Set_UTF16 (buffer);
3001 
3002 		}
3003 
3004 	else
3005 		{
3006 
3007 		uint32 aChars = tagCount - 8;
3008 
3009 		dng_memory_data temp_buffer (aChars + 1);
3010 
3011 		char *buffer = temp_buffer.Buffer_char ();
3012 
3013 		stream.Get (buffer, aChars);
3014 
3015 		buffer [aChars] = 0;
3016 
3017 		enum dng_encoding
3018 			{
3019 			dng_encoding_ascii,
3020 			dng_encoding_jis_x208_1990,
3021 			dng_encoding_unknown
3022 			};
3023 
3024 		dng_encoding encoding = dng_encoding_unknown;
3025 
3026 		if (memcmp (label, "ASCII\000\000\000", 8) == 0)
3027 			{
3028 
3029 			encoding = dng_encoding_ascii;
3030 
3031 			}
3032 
3033 		else if (memcmp (label, "JIS\000\000\000\000\000\000", 8) == 0)
3034 			{
3035 
3036 			encoding = dng_encoding_jis_x208_1990;
3037 
3038 			}
3039 
3040 		else
3041 			{
3042 
3043 			// Some Nikon D1 files have UserComment tags with zero encoding bits and
3044 			// garbage text values.  So don't try to parse tags with unknown text
3045 			// encoding unless all the characters are printing ASCII.
3046 
3047 			#if qDNGValidate
3048 
3049 			if (memcmp (label, "\000\000\000\000\000\000\000\000\000", 8) == 0)
3050 				{
3051 
3052 				// Many camera makes store null tags with all zero encoding, so
3053 				// don't report a warning message for null strings.
3054 
3055 				if (buffer [0] != 0)
3056 					{
3057 
3058 					char message [256];
3059 
3060 					sprintf (message,
3061 							 "%s %s has unknown encoding",
3062 							 LookupParentCode (parentCode),
3063 							 LookupTagCode (parentCode, tagCode));
3064 
3065 					ReportWarning (message);
3066 
3067 					}
3068 
3069 				}
3070 
3071 			else
3072 				{
3073 
3074 				char message [256];
3075 
3076 				sprintf (message,
3077 						 "%s %s has unexpected text encoding",
3078 						 LookupParentCode (parentCode),
3079 						 LookupTagCode (parentCode, tagCode));
3080 
3081 				ReportWarning (message);
3082 
3083 				}
3084 
3085 			#endif
3086 
3087 			}
3088 
3089 		// If text encoding was unknown, and the text is anything
3090 		// other than pure ASCII, then ignore it.
3091 
3092 		if (encoding == dng_encoding_unknown)
3093 			{
3094 
3095 			encoding = dng_encoding_ascii;
3096 
3097 			for (uint32 i = 0; i < aChars && buffer [i] != 0; i++)
3098 				{
3099 
3100 				if (buffer [i] < ' ' ||
3101 					buffer [i] > '~')
3102 					{
3103 
3104 					buffer [0] = 0;
3105 
3106 					break;
3107 
3108 					}
3109 
3110 				}
3111 
3112 			}
3113 
3114 		switch (encoding)
3115 			{
3116 
3117 			case dng_encoding_ascii:
3118 				{
3119 
3120 				// Medata working group - allow UTF-8 for ASCII tags.
3121 
3122 				s.Set_UTF8_or_System (buffer);
3123 
3124 				break;
3125 
3126 				}
3127 
3128 			case dng_encoding_jis_x208_1990:
3129 				{
3130 				s.Set_JIS_X208_1990 (buffer);
3131 				break;
3132 				}
3133 
3134 			case dng_encoding_unknown:
3135 				{
3136 				s.Set_SystemEncoding (buffer);
3137 				break;
3138 				}
3139 
3140 			default:
3141 				break;
3142 
3143 			}
3144 
3145 		#if qDNGValidate
3146 
3147 			{
3148 
3149 			if (encoding == dng_encoding_ascii && !s.IsASCII ())
3150 				{
3151 
3152 				char message [256];
3153 
3154 				sprintf (message,
3155 						 "%s %s has non-ASCII characters",
3156 						 LookupParentCode (parentCode),
3157 						 LookupTagCode (parentCode, tagCode));
3158 
3159 				ReportWarning (message);
3160 
3161 				}
3162 
3163 			}
3164 
3165 		#endif
3166 
3167 		}
3168 
3169 	s.TrimTrailingBlanks ();
3170 
3171 	}
3172 
3173 /*****************************************************************************/
3174 
ParseMatrixTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint32 rows,uint32 cols,dng_matrix & m)3175 bool ParseMatrixTag (dng_stream &stream,
3176 					 uint32 parentCode,
3177 					 uint32 tagCode,
3178 					 uint32 tagType,
3179 					 uint32 tagCount,
3180 					 uint32 rows,
3181 					 uint32 cols,
3182 					 dng_matrix &m)
3183 	{
3184 
3185 	if (CheckTagCount (parentCode, tagCode, tagCount, rows * cols))
3186 		{
3187 
3188 		dng_matrix temp (rows, cols);
3189 
3190 		for (uint32 row = 0; row < rows; row++)
3191 			for (uint32 col = 0; col < cols; col++)
3192 				{
3193 
3194 				temp [row] [col] = stream.TagValue_real64 (tagType);
3195 
3196 				}
3197 
3198 		m = temp;
3199 
3200 		return true;
3201 
3202 		}
3203 
3204 	return false;
3205 
3206 	}
3207 
3208 /*****************************************************************************/
3209 
ParseVectorTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint32 count,dng_vector & v)3210 bool ParseVectorTag (dng_stream &stream,
3211 					 uint32 parentCode,
3212 					 uint32 tagCode,
3213 					 uint32 tagType,
3214 					 uint32 tagCount,
3215 					 uint32 count,
3216 					 dng_vector &v)
3217 	{
3218 
3219 	if (CheckTagCount (parentCode, tagCode, tagCount, count))
3220 		{
3221 
3222 		dng_vector temp (count);
3223 
3224 		for (uint32 index = 0; index < count; index++)
3225 			{
3226 
3227 			temp [index] = stream.TagValue_real64 (tagType);
3228 
3229 			}
3230 
3231 		v = temp;
3232 
3233 		return true;
3234 
3235 		}
3236 
3237 	return false;
3238 
3239 	}
3240 
3241 /*****************************************************************************/
3242 
ParseDateTimeTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,dng_date_time & dt)3243 bool ParseDateTimeTag (dng_stream &stream,
3244 					   uint32 parentCode,
3245 					   uint32 tagCode,
3246 					   uint32 tagType,
3247 					   uint32 tagCount,
3248 					   dng_date_time &dt)
3249 	{
3250 
3251 	if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3252 		{
3253 		return false;
3254 		}
3255 
3256 	// Kludge: Some versions of PaintShop Pro write these fields
3257 	// with a length of 21 rather than 20.  Otherwise they are
3258 	// correctly formated.  So relax this test and allow these
3259 	// these longer than standard tags to be parsed.
3260 
3261 	(void) CheckTagCount (parentCode, tagCode, tagCount, 20);
3262 
3263 	if (tagCount < 20)
3264 		{
3265 		return false;
3266 		}
3267 
3268 	char s [21];
3269 
3270 	stream.Get (s, 20);
3271 
3272 	s [20] = 0;
3273 
3274 	// See if this is a valid date/time string.
3275 
3276 	if (dt.Parse (s))
3277 		{
3278 		return true;
3279 		}
3280 
3281 	// Accept strings that contain only blanks, colons, and zeros as
3282 	// valid "null" dates.
3283 
3284 	dt = dng_date_time ();
3285 
3286 	for (uint32 index = 0; index < 21; index++)
3287 		{
3288 
3289 		char c = s [index];
3290 
3291 		if (c == 0)
3292 			{
3293 			return true;
3294 			}
3295 
3296 		if (c != ' ' && c != ':' && c != '0')
3297 			{
3298 
3299 			#if qDNGValidate
3300 
3301 				{
3302 
3303 				char message [256];
3304 
3305 				sprintf (message,
3306 						 "%s %s is not a valid date/time",
3307 						 LookupParentCode (parentCode),
3308 						 LookupTagCode (parentCode, tagCode));
3309 
3310 				ReportWarning (message);
3311 
3312 				}
3313 
3314 			#endif
3315 
3316 			return false;
3317 
3318 			}
3319 
3320 		}
3321 
3322 	return false;
3323 
3324 	}
3325 
3326 /*****************************************************************************/
3327