1 // -*- mode: C++; tab-width: 4 -*-
2 // vi: ts=4
3 
4 /*
5  * Copyright (c) 2009, Patrick A. Palmer.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  *   - Redistributions of source code must retain the above copyright notice,
12  *     this list of conditions and the following disclaimer.
13  *
14  *   - Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *
18  *   - Neither the name of Patrick A. Palmer nor the names of its
19  *     contributors may be used to endorse or promote products derived from
20  *     this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 
36 
37 #include <cassert>
38 #include <cstdio>
39 #include <cstring>
40 #include <ctime>
41 #include <limits>
42 
43 #include <OpenImageIO/sysutil.h>
44 
45 #include "DPXHeader.h"
46 #include "EndianSwap.h"
47 
48 
49 
50 // function prototypes
51 static void EmptyString(char *, const int);
52 
53 
54 
55 
Hex(char x)56 char Hex(char x)
57 {
58 	if (x >= 10)
59 		return (x-10+'A');
60 	else
61 		return (x+'0');
62 }
63 
64 
65 
Header()66 dpx::Header::Header() : GenericHeader(), IndustryHeader(), datumSwap(true)
67 {
68 }
69 
70 
71 
GenericHeader()72 dpx::GenericHeader::GenericHeader()
73 {
74 	this->Reset();
75 }
76 
77 
Reset()78 void dpx::GenericHeader::Reset()
79 {
80 	// File Information
81 	this->magicNumber = MAGIC_COOKIE;
82 	this->imageOffset = ~0;
83 	EmptyString(this->version, sizeof(this->version));
84 	OIIO::Strutil::safe_strcpy(this->version, SMPTE_VERSION, sizeof(this->version));
85 	fileSize = sizeof(dpx::Header);
86 	this->dittoKey = 1;									// new
87 
88 	// genericSize is the size of the file/image/orientation headers
89 	// sizeof(dpx::GenericHeader) won't give the correct results because
90 	// of compiler padding
91 	//		file header is 768 bytes
92 	//		image header is 640 bytes
93 	//		orientation header 256 bytes
94 
95 	this->genericSize = 768 + 640 + 256;
96 
97 	// industrySize is the size of the motion picture/television headers
98 	//		motion picture header is 256 bytes
99 	//		television header is 128 bytes
100 	this->industrySize = 256 + 128;
101 
102 	this->userSize = 0;
103 	EmptyString(this->fileName, sizeof(this->fileName));
104 	EmptyString(this->creationTimeDate, sizeof(this->creationTimeDate));
105 	EmptyString(this->creator, sizeof(this->creator));
106 	EmptyString(this->project, sizeof(this->project));
107 	EmptyString(this->copyright, sizeof(this->copyright));
108 	this->encryptKey = 0xffffffff;
109 	EmptyString(this->reserved1, sizeof(this->reserved1));
110 
111 	// Image Information
112 	this->imageOrientation = kUndefinedOrientation;
113 	this->numberOfElements = 0xffff;
114 	this->pixelsPerLine = this->linesPerElement = 0xffffffff;
115 	EmptyString(this->reserved2, sizeof(this->reserved2));
116 
117 	// Image Orientation
118 	this->xOffset = this->yOffset = 0xffffffff;
119 	this->xCenter = this->yCenter = std::numeric_limits<float>::quiet_NaN();
120 	this->xOriginalSize = this->yOriginalSize = 0xffffffff;
121 	EmptyString(this->sourceImageFileName, sizeof(this->sourceImageFileName));
122 	EmptyString(this->sourceTimeDate, sizeof(this->sourceTimeDate));
123 	EmptyString(this->inputDevice, sizeof(this->inputDevice));
124 	EmptyString(this->inputDeviceSerialNumber, sizeof(this->inputDeviceSerialNumber));
125 	this->border[0] = this->border[1] = this->border[2] = this->border[3] = 0xffff;
126 	this->aspectRatio[0] = this->aspectRatio[1] = 0xffffffff;
127 	this->xScannedSize = this->yScannedSize = std::numeric_limits<float>::quiet_NaN();
128 	EmptyString(this->reserved3, sizeof(this->reserved3));
129 }
130 
131 
IndustryHeader()132 dpx::IndustryHeader::IndustryHeader()
133 {
134 	this->Reset();
135 }
136 
137 
Reset()138 void dpx::IndustryHeader::Reset()
139 {
140 	// Motion Picture Industry Specific
141 	EmptyString(this->filmManufacturingIdCode, sizeof(this->filmManufacturingIdCode));
142 	EmptyString(this->filmType, sizeof(this->filmType));
143 	EmptyString(this->perfsOffset, sizeof(this->perfsOffset));
144 	EmptyString(this->prefix, sizeof(this->prefix));
145 	EmptyString(this->count, sizeof(this->count));
146 	EmptyString(this->format, sizeof(this->format));
147 	this->framePosition = this->sequenceLength = this->heldCount = 0xffffffff;
148 	this->frameRate = this->shutterAngle = std::numeric_limits<float>::quiet_NaN();
149 	EmptyString(this->frameId, sizeof(this->frameId));
150 	EmptyString(this->slateInfo, sizeof(this->slateInfo));
151 	EmptyString(this->reserved4, sizeof(this->reserved4));
152 
153 	// Television Industry Specific
154 	this->timeCode = this->userBits = 0xffffffff;
155 	this->interlace = this->fieldNumber = 0xff;
156 	this->videoSignal = kUndefined;
157 	this->zero = 0xff;
158 	this->horizontalSampleRate = this->verticalSampleRate = this->temporalFrameRate = std::numeric_limits<float>::quiet_NaN();
159 	this->timeOffset = this->gamma = std::numeric_limits<float>::quiet_NaN();
160 	this->blackLevel = this->blackGain = std::numeric_limits<float>::quiet_NaN();
161 	this->breakPoint = this->whiteLevel = this->integrationTimes = std::numeric_limits<float>::quiet_NaN();
162 	EmptyString(this->reserved5, sizeof(this->reserved5));
163 }
164 
165 
ImageElement()166 dpx::ImageElement::ImageElement()
167 {
168 	this->dataSign = 0xffffffff;
169 	this->lowData = 0xffffffff;
170 	this->lowQuantity = R32(0xffffffff);
171 	this->highData = 0xffffffff;
172 	this->highQuantity = R32(0xffffffff);
173 	this->descriptor = kUndefinedDescriptor;
174 	this->transfer = kUndefinedCharacteristic;
175 	this->colorimetric = kUndefinedCharacteristic;
176 	this->bitDepth = 0xff;
177 	this->packing = this->encoding = 0xffff;
178 	this->dataOffset = this->endOfLinePadding = this->endOfImagePadding = 0xffffffff;
179 	EmptyString(this->description, sizeof(this->description));
180 }
181 
182 
Read(InStream * io)183 bool dpx::Header::Read(InStream *io)
184 {
185 	// rewind file
186 	io->Rewind();
187 
188 	// read in the header from the file
189 	size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
190 	if (io->Read(&(this->magicNumber), r) != r)
191 		return false;
192 
193 	// validate
194 	return this->Validate();
195 }
196 
197 
198 // Check to see if the compiler placed the data members in the expected memory offsets
199 
Check()200 bool dpx::Header::Check()
201 {
202 	// genericSize is the size of the file/image/orientation headers
203 	// sizeof(dpx::GenericHeader) won't give the correct results because
204 	// of compiler padding
205 	//		file header is 768 bytes
206 	//		image header is 640 bytes
207 	//		orientation header 256 bytes
208 
209 	if (sizeof(GenericHeader) != (768 + 640 + 256))
210 		return false;
211 
212 	// industrySize is the size of the motion picture/television headers
213 	//		motion picture header is 256 bytes
214 	//		television header is 128 bytes
215 	if (sizeof(IndustryHeader) != (256 + 128))
216 		return false;
217 
218 	// data size checks
219 	if (sizeof(U8) != 1 || sizeof(U16) != 2 || sizeof(U32) != 4 || sizeof(R32) != 4 || sizeof(R64) != 8)
220 		return false;
221 
222 	return true;
223 }
224 
225 
226 
Write(OutStream * io)227 bool dpx::Header::Write(OutStream *io)
228 {
229 	// validate and byte swap, if necessary
230 	if (!this->Validate())
231 		return false;
232 
233 	// write the header to the file
234 	size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
235 	if (! io->WriteCheck(&(this->magicNumber), r))
236 		return false;
237 
238 	// swap back - data is in file, now we need it native again
239 	this->Validate();
240 	return true;
241 }
242 
243 
WriteOffsetData(OutStream * io)244 bool dpx::Header::WriteOffsetData(OutStream *io)
245 {
246 	// calculate the number of elements
247 	this->CalculateNumberOfElements();
248 
249 	// write the image offset
250 	const long FIELD2 = 4;			// offset to image in header
251 	if (io->Seek(FIELD2, OutStream::kStart) == false)
252 		return false;
253 	if (this->RequiresByteSwap())
254 		SwapBytes(this->imageOffset);
255 	if (!io->WriteCheck(&this->imageOffset, sizeof(U32)))
256 		return false;
257 	if (this->RequiresByteSwap())
258 		SwapBytes(this->imageOffset);
259 
260 
261 	// write the file size
262 	const long FIELD4 = 16;			// offset to total image file size in header
263 	if (io->Seek(FIELD4, OutStream::kStart) == false)
264 		return false;
265 	if (this->RequiresByteSwap())
266 		SwapBytes(this->fileSize);
267 	if (! io->WriteCheck(&this->fileSize, sizeof(U32)))
268 		return false;
269 	if (this->RequiresByteSwap())
270 		SwapBytes(this->fileSize);
271 
272 	// write the number of elements
273 	const long FIELD19 = 770;		// offset to number of image elements in header
274 	if (io->Seek(FIELD19, OutStream::kStart) == false)
275 		return false;
276 	if (this->RequiresByteSwap())
277 		SwapBytes(this->numberOfElements);
278 	if (! io->WriteCheck(&this->numberOfElements, sizeof(U16)))
279 		return false;
280 	if (this->RequiresByteSwap())
281 		SwapBytes(this->numberOfElements);
282 
283 	// write the image offsets
284 	const long FIELD21_12 = 808;	// offset to image offset in image element data structure
285 	const long IMAGE_STRUCTURE = 72;	// sizeof the image data structure
286 
287 	int i;
288 	for (i = 0; i < MAX_ELEMENTS; i++)
289 	{
290 			// only write if there is a defined image description
291 			if (this->chan[i].descriptor == kUndefinedDescriptor)
292 				continue;
293 
294 			// seek to the image offset entry in each image element
295 			if (io->Seek((FIELD21_12 + (IMAGE_STRUCTURE * i)), OutStream::kStart) == false)
296 				return false;
297 
298 			// write
299 			if (this->RequiresByteSwap())
300 				SwapBytes(this->chan[i].dataOffset);
301 			if (! io->WriteCheck(&this->chan[i].dataOffset, sizeof(U32)))
302 				return false;
303 			if (this->RequiresByteSwap())
304 				SwapBytes(this->chan[i].dataOffset);
305 
306 	}
307 
308 	return true;
309 }
310 
311 
ValidMagicCookie(const U32 magic)312 bool dpx::Header::ValidMagicCookie(const U32 magic)
313 {
314 	U32 mc = MAGIC_COOKIE;
315 
316 	if (magic == mc)
317 		return true;
318 	else if (magic == SwapBytes(mc))
319 		return true;
320 	else
321 		return false;
322 }
323 
324 
DetermineByteSwap(const U32 magic) const325 bool dpx::Header::DetermineByteSwap(const U32 magic) const
326 {
327 	U32 mc = MAGIC_COOKIE;
328 
329 	bool byteSwap = false;
330 
331 	if (magic != mc)
332 		byteSwap = true;
333 
334 	return byteSwap;
335 }
336 
337 
Validate()338 bool dpx::Header::Validate()
339 {
340 	// check magic cookie
341 	if (!this->ValidMagicCookie(this->magicNumber))
342 		return false;
343 
344 	// determine if bytes needs to be swapped around
345 	if (this->DetermineByteSwap(this->magicNumber))
346 	{
347 		// File information
348 		SwapBytes(this->imageOffset);
349 		SwapBytes(this->fileSize);
350 		SwapBytes(this->dittoKey);
351 		SwapBytes(this->genericSize);
352 		SwapBytes(this->industrySize);
353 		SwapBytes(this->userSize);
354 		SwapBytes(this->encryptKey);
355 
356 		// Image information
357 		SwapBytes(this->imageOrientation);
358 		SwapBytes(this->numberOfElements);
359 		SwapBytes(this->pixelsPerLine);
360 		SwapBytes(this->linesPerElement);
361 		for (int i = 0; i < MAX_ELEMENTS; i++)
362 		{
363 			SwapBytes(this->chan[i].dataSign);
364 			SwapBytes(this->chan[i].lowData);
365 			SwapBytes(this->chan[i].lowQuantity);
366 			SwapBytes(this->chan[i].highData);
367 			SwapBytes(this->chan[i].highQuantity);
368 			SwapBytes(this->chan[i].descriptor);
369 			SwapBytes(this->chan[i].transfer);
370 			SwapBytes(this->chan[i].colorimetric);
371 			SwapBytes(this->chan[i].bitDepth);
372 			SwapBytes(this->chan[i].packing);
373 			SwapBytes(this->chan[i].encoding);
374 			SwapBytes(this->chan[i].dataOffset);
375 			SwapBytes(this->chan[i].endOfLinePadding);
376 			SwapBytes(this->chan[i].endOfImagePadding);
377 		}
378 
379 
380 		// Image Origination information
381 		SwapBytes(this->xOffset);
382 		SwapBytes(this->yOffset);
383 		SwapBytes(this->xCenter);
384 		SwapBytes(this->yCenter);
385 		SwapBytes(this->xOriginalSize);
386 		SwapBytes(this->yOriginalSize);
387 		SwapBytes(this->border[0]);
388 		SwapBytes(this->border[1]);
389 		SwapBytes(this->border[2]);
390 		SwapBytes(this->border[3]);
391 		SwapBytes(this->aspectRatio[0]);
392 		SwapBytes(this->aspectRatio[1]);
393 
394 
395 		// Motion Picture Industry Specific
396 		SwapBytes(this->framePosition);
397 		SwapBytes(this->sequenceLength);
398 		SwapBytes(this->heldCount);
399 		SwapBytes(this->frameRate);
400 		SwapBytes(this->shutterAngle);
401 
402 
403 		// Television Industry Specific
404 		SwapBytes(this->timeCode);
405 		SwapBytes(this->userBits);
406 		SwapBytes(this->interlace);
407 		SwapBytes(this->fieldNumber);
408 		SwapBytes(this->videoSignal);
409 		SwapBytes(this->zero);
410 		SwapBytes(this->horizontalSampleRate);
411 		SwapBytes(this->verticalSampleRate);
412 		SwapBytes(this->temporalFrameRate);
413 		SwapBytes(this->timeOffset);
414 		SwapBytes(this->gamma);
415 		SwapBytes(this->blackLevel);
416 		SwapBytes(this->blackGain);
417 		SwapBytes(this->breakPoint);
418 		SwapBytes(this->whiteLevel);
419 		SwapBytes(this->integrationTimes);
420 	}
421 
422 	return true;
423 }
424 
425 
426 
Reset()427 void dpx::Header::Reset()
428 {
429 	GenericHeader::Reset();
430 	IndustryHeader::Reset();
431 }
432 
433 
ImageElementComponentCount(const int element) const434 int dpx::GenericHeader::ImageElementComponentCount(const int element) const
435 {
436 	int count = 1;
437 
438 	switch (this->chan[element].descriptor)
439 	{
440 	case kUserDefinedDescriptor:
441 	case kRed:
442 	case kGreen:
443 	case kBlue:
444 	case kAlpha:
445 	case kLuma:
446 	case kColorDifference:
447 	case kDepth:
448 		count = 1;
449 		break;
450 	case kCompositeVideo:
451 		count = 1;
452 		break;
453 	case kRGB:
454 		count = 3;
455 		break;
456 	case kRGBA:
457 	case kABGR:
458 		count = 4;
459 		break;
460 	case kCbYCrY:
461 		count = 2;
462 		break;
463 	case kCbYACrYA:
464 		count = 3;
465 		break;
466 	case kCbYCr:
467 		count = 3;
468 		break;
469 	case kCbYCrA:
470 		count = 4;
471 		break;
472 	case kUserDefined2Comp:
473 		count = 2;
474 		break;
475 	case kUserDefined3Comp:
476 		count = 3;
477 		break;
478 	case kUserDefined4Comp:
479 		count = 4;
480 		break;
481 	case kUserDefined5Comp:
482 		count = 5;
483 		break;
484 	case kUserDefined6Comp:
485 		count = 6;
486 		break;
487 	case kUserDefined7Comp:
488 		count = 7;
489 		break;
490 	case kUserDefined8Comp:
491 		count = 8;
492 		break;
493 	};
494 
495 	return count;
496 }
497 
498 
ImageElementCount() const499 int dpx::GenericHeader::ImageElementCount() const
500 {
501 	if(this->numberOfElements>0 && this->numberOfElements<=MAX_ELEMENTS)
502 		return this->numberOfElements;
503 
504 	// If the image header does not list a valid number of elements,
505 	// count how many defined image descriptors we have...
506 
507 	int i = 0;
508 
509 	while (i < MAX_ELEMENTS )
510 	{
511 		if (this->ImageDescriptor(i) == kUndefinedDescriptor)
512 			break;
513 		i++;
514 	}
515 
516 	return i;
517 }
518 
519 
CalculateNumberOfElements()520 void dpx::GenericHeader::CalculateNumberOfElements()
521 {
522 	this->numberOfElements = 0xffff;
523 	int i = this->ImageElementCount();
524 
525 	if (i == 0)
526 		this->numberOfElements = 0xffff;
527 	else
528 		this->numberOfElements = U16(i);
529 }
530 
531 
CalculateOffsets()532 void dpx::Header::CalculateOffsets()
533 {
534 	int i;
535 
536 	for (i = 0; i < MAX_ELEMENTS; i++)
537 	{
538 		// only write if there is a defined image description
539 		if (this->chan[i].descriptor == kUndefinedDescriptor)
540 			continue;
541 
542 
543 	}
544 }
545 
546 
ComponentDataSize(const int element) const547 dpx::DataSize dpx::GenericHeader::ComponentDataSize(const int element) const
548 {
549 	if (element < 0 || element >= MAX_ELEMENTS)
550 		return kByte;
551 
552 	dpx::DataSize ret;
553 
554 	switch (this->chan[element].bitDepth)
555 	{
556 	case 8:
557 		ret = kByte;
558 		break;
559 	case 10:
560 	case 12:
561 	case 16:
562 		ret = kWord;
563 		break;
564 	case 32:
565 		ret = kFloat;
566 		break;
567 	case 64:
568 		ret = kDouble;
569 		break;
570 	default:
571 		assert(0 && "Unknown bit depth");
572 		ret = kDouble;
573 		break;
574 	}
575 
576 	return ret;
577 }
578 
579 
ComponentByteCount(const int element) const580 int dpx::GenericHeader::ComponentByteCount(const int element) const
581 {
582 	if (element < 0 || element >= MAX_ELEMENTS)
583 		return kByte;
584 
585 	int ret;
586 
587 	switch (this->chan[element].bitDepth)
588 	{
589 	case 8:
590 		ret = sizeof(U8);
591 		break;
592 	case 10:
593 	case 12:
594 	case 16:
595 		ret = sizeof(U16);
596 		break;
597 	case 32:
598 		ret = sizeof(R32);
599 		break;
600 	case 64:
601 		ret = sizeof(R64);
602 		break;
603 	default:
604 		assert(0 && "Unknown bit depth");
605 		ret = sizeof(R64);
606 		break;
607 	}
608 
609 	return ret;
610 }
611 
612 
DataSizeByteCount(const DataSize ds)613 int dpx::GenericHeader::DataSizeByteCount(const DataSize ds)
614 {
615 
616 	int ret;
617 
618 	switch (ds)
619 	{
620 	case kByte:
621 		ret = sizeof(U8);
622 		break;
623 	case kWord:
624 		ret = sizeof(U16);
625 		break;
626 	case kInt:
627 		ret = sizeof(U32);
628 		break;
629 	case kFloat:
630 		ret = sizeof(R32);
631 		break;
632 	case kDouble:
633 		ret = sizeof(R64);
634 		break;
635 	default:
636 		assert(0 && "Unknown data size");
637 		ret = sizeof(R64);
638 		break;
639 	}
640 
641 	return ret;
642 }
643 
644 
FilmEdgeCode(char * edge) const645 void dpx::IndustryHeader::FilmEdgeCode(char *edge) const
646 {
647 	edge[0] = this->filmManufacturingIdCode[0];
648 	edge[1] = this->filmManufacturingIdCode[1];
649 	edge[2] = this->filmType[0];
650 	edge[3] = this->filmType[1];
651 	edge[4] = this->perfsOffset[0];
652 	edge[5] = this->perfsOffset[1];
653 	edge[6] = this->prefix[0];
654 	edge[7] = this->prefix[1];
655 	edge[8] = this->prefix[2];
656 	edge[9] = this->prefix[3];
657 	edge[10] = this->prefix[4];
658 	edge[11] = this->prefix[5];
659 	edge[12] = this->count[0];
660 	edge[13] = this->count[1];
661 	edge[14] = this->count[2];
662 	edge[15] = this->count[3];
663 	edge[16] = '\0';
664 }
665 
666 
SetFileEdgeCode(const char * edge)667 void dpx::IndustryHeader::SetFileEdgeCode(const char *edge)
668 {
669 	this->filmManufacturingIdCode[0] = edge[0];
670 	this->filmManufacturingIdCode[1] = edge[1];
671 	this->filmType[0] = edge[2];
672 	this->filmType[1] = edge[3];
673 	this->perfsOffset[0] = edge[4];
674 	this->perfsOffset[1] = edge[5];
675 	this->prefix[0] = edge[6];
676 	this->prefix[1] = edge[7];
677 	this->prefix[2] = edge[8];
678 	this->prefix[3] = edge[9];
679 	this->prefix[4] = edge[10];
680 	this->prefix[5] = edge[11];
681 	this->count[0] = edge[12];
682 	this->count[1] = edge[13];
683 	this->count[2] = edge[14];
684 	this->count[3] = edge[15];
685 }
686 
687 
TimeCode(char * str) const688 void dpx::IndustryHeader::TimeCode(char *str) const
689 {
690 	U32 tc = this->timeCode;
691 	::sprintf(str, "%c%c:%c%c:%c%c:%c%c",
692 		Hex((tc & 0xf0000000) >> 28),  Hex((tc & 0xf000000) >> 24),
693 		Hex((tc & 0xf00000) >> 20),  Hex((tc & 0xf0000) >> 16),
694 		Hex((tc & 0xf000) >> 12),  Hex((tc & 0xf00) >> 8),
695 		Hex((tc & 0xf0) >> 4),  Hex(tc & 0xf));
696 }
697 
698 
UserBits(char * str) const699 void dpx::IndustryHeader::UserBits(char *str) const
700 {
701 	U32 ub = this->userBits;
702 	::sprintf(str, "%c%c:%c%c:%c%c:%c%c",
703 		Hex((ub & 0xf0000000) >> 28),  Hex((ub & 0xf000000) >> 24),
704 		Hex((ub & 0xf00000) >> 20),  Hex((ub & 0xf0000) >> 16),
705 		Hex((ub & 0xf000) >> 12),  Hex((ub & 0xf00) >> 8),
706 		Hex((ub & 0xf0) >> 4),  Hex(ub & 0xf));
707 }
708 
709 
TCFromString(const char * str) const710 dpx::U32 dpx::IndustryHeader::TCFromString(const char *str) const
711 {
712 	// make sure the string is the correct length
713 	if (::strlen(str) != 11)
714 		return U32(~0);
715 
716 	U32 tc = 0;
717 	int i, idx = 0;
718 	U8 ch;
719 	U32 value, mask;
720 
721 	for (i = 0; i < 8; i++, idx++)
722 	{
723 		// determine string index skipping :
724 		idx += idx % 3 == 2 ? 1 : 0;
725 		ch = str[idx];
726 
727 		// error check
728 		if (ch < '0' || ch > '9')
729 			return 0xffffffff;
730 
731 		value = U32(ch - '0') << (28 - (i*4));
732 		mask = 0xf << (28 - (i*4));
733 
734 		// mask in new value
735 		tc = (tc & ~mask) | (value & mask);
736 	}
737 
738 	return tc;
739 }
740 
741 
SetTimeCode(const char * str)742 void dpx::IndustryHeader::SetTimeCode(const char *str)
743 {
744 	U32 tc = this->TCFromString(str);
745 	if (tc != 0xffffffff)
746 		this->timeCode = tc;
747 }
748 
749 
SetUserBits(const char * str)750 void dpx::IndustryHeader::SetUserBits(const char *str)
751 {
752 	U32 ub = this->TCFromString(str);
753 	if (ub != 0xffffffff)
754 		this->userBits = ub;
755 }
756 
757 
758 
EmptyString(char * str,const int len)759 static void EmptyString(char *str, const int len)
760 {
761 	for (int i = 0; i < len; i++)
762 		str[i] = '\0';
763 }
764 
765 
SetCreationTimeDate(const long sec)766 void dpx::GenericHeader::SetCreationTimeDate(const long sec)
767 {
768     char str[32];
769 
770 #ifdef _WIN32
771 	_tzset();
772 #endif
773 
774     const time_t t = time_t(sec);
775     struct tm localtm;
776     OIIO::Sysutil::get_local_time(&t, &localtm);
777     ::strftime(str, 32, "%Y:%m:%d:%H:%M:%S%Z", &localtm);
778 	OIIO::Strutil::safe_strcpy(this->creationTimeDate, str, 24);
779 }
780 
781 
SetSourceTimeDate(const long sec)782 void dpx::GenericHeader::SetSourceTimeDate(const long sec)
783 {
784     char str[32];
785 
786 #ifdef _WIN32
787 	_tzset();
788 #endif
789 
790     const time_t t = time_t(sec);
791     struct tm localtm;
792     OIIO::Sysutil::get_local_time(&t, &localtm);
793     ::strftime(str, 32, "%Y:%m:%d:%H:%M:%S%Z", &localtm);
794 	OIIO::Strutil::safe_strcpy(this->sourceTimeDate, str, 24);
795 }
796 
797 
798 
DatumSwap(const int element) const799 bool dpx::Header::DatumSwap(const int element) const
800 {
801 	if (this->datumSwap)
802 	{
803 		if (this->ImageDescriptor(element) == kRGB || this->ImageDescriptor(element) == kCbYCrY)
804 			return true;
805 	}
806 	return false;
807 }
808 
809 
SetDatumSwap(const bool swap)810 void dpx::Header::SetDatumSwap(const bool swap)
811 {
812 	this->datumSwap = swap;
813 }
814 
815 // Height()
816 // this function determines the height of the image taking in account for the image orientation
817 // if an image is 1920x1080 but is oriented top to bottom, left to right then the height stored
818 // in the image is 1920 rather than 1080
819 
Height() const820 dpx::U32 dpx::Header::Height() const
821 {
822 	U32 h;
823 
824 	switch (this->ImageOrientation())
825 	{
826 	case kTopToBottomLeftToRight:
827 	case kTopToBottomRightToLeft:
828 	case kBottomToTopLeftToRight:
829 	case kBottomToTopRightToLeft:
830 		h = this->PixelsPerLine();
831 		break;
832 	default:
833 		h = this->LinesPerElement();
834 		break;
835 	}
836 
837 	return h;
838 }
839 
840 
841 // Width()
842 // this function determines the width of the image taking in account for the image orientation
843 // if an image is 1920x1080 but is oriented top to bottom, left to right then the width stored
844 // in the image is 1920 rather than 1080
845 
Width() const846 dpx::U32 dpx::Header::Width() const
847 {
848 	U32 w;
849 
850 	switch (this->ImageOrientation())
851 	{
852 	case kTopToBottomLeftToRight:
853 	case kTopToBottomRightToLeft:
854 	case kBottomToTopLeftToRight:
855 	case kBottomToTopRightToLeft:
856 		w = this->LinesPerElement();
857 		break;
858 	default:
859 		w = this->PixelsPerLine();
860 		break;
861 	}
862 
863 	return w;
864 }
865 
866 
867 
868