1 /*! \file	types.h
2  *	\brief	The main MXF data types
3  *
4  *	\version $Id: types.h,v 1.8 2006/08/30 15:30:26 matt-beard Exp $
5  *
6  */
7 /*
8  *	Copyright (c) 2003, Matt Beard
9  *
10  *	This software is provided 'as-is', without any express or implied warranty.
11  *	In no event will the authors be held liable for any damages arising from
12  *	the use of this software.
13  *
14  *	Permission is granted to anyone to use this software for any purpose,
15  *	including commercial applications, and to alter it and redistribute it
16  *	freely, subject to the following restrictions:
17  *
18  *	  1. The origin of this software must not be misrepresented; you must
19  *	     not claim that you wrote the original software. If you use this
20  *	     software in a product, an acknowledgment in the product
21  *	     documentation would be appreciated but is not required.
22  *
23  *	  2. Altered source versions must be plainly marked as such, and must
24  *	     not be misrepresented as being the original software.
25  *
26  *	  3. This notice may not be removed or altered from any source
27  *	     distribution.
28  */
29 
30 #ifndef MXFLIB__TYPES_H
31 #define MXFLIB__TYPES_H
32 
33 // Ensure NULL is available
34 #include <stdlib.h>
35 
36 // Standard library includes
37 #include <cstring>
38 #include <list>
39 
40 
41 /*                        */
42 /* Basic type definitions */
43 /*                        */
44 
45 namespace mxflib
46 {
47 	typedef Int64 Length;				//!< Lenth of an item in bytes
48 	typedef Int64 Position;				//!< Position within an MXF file
49 
50 	typedef UInt16 Tag;					//!< 2-byte tag for local sets
51 
52 	//! Pair of UInt32 values
53 	typedef std::pair<UInt32, UInt32> U32Pair;
54 }
55 
56 
57 // Some string conversion utilities
58 namespace mxflib
59 {
60 	//! String version of a tag
Tag2String(Tag value)61 	inline std::string Tag2String(Tag value)
62 	{
63 		char Buffer[8];
64 		sprintf(Buffer, "%02x.%02x", value >> 8, value & 0xff);
65 		return std::string(Buffer);
66 	}
67 }
68 
69 
70 namespace mxflib
71 {
72 	template <int SIZE> class Identifier /*: public RefCount<Identifier<SIZE> >*/
73 	{
74 	protected:
75 		UInt8 Ident[SIZE];
76 	public:
77 		Identifier(const UInt8 *ID = NULL) { if(ID == NULL) memset(Ident,0,SIZE); else memcpy(Ident,ID, SIZE); };
Identifier(const SmartPtr<Identifier> ID)78 		Identifier(const SmartPtr<Identifier> ID) { ASSERT(SIZE == ID->Size()); if(!ID) memset(Ident,0,SIZE); else memcpy(Ident,ID->Ident, SIZE); };
79 
80 		//! Set the value of the Identifier
81 		void Set(const UInt8 *ID = NULL) { if(ID == NULL) memset(Ident,0,SIZE); else memcpy(Ident,ID, SIZE); };
82 
83 		//! Set an individual byte of the identifier
Set(int Index,UInt8 Value)84 		void Set(int Index, UInt8 Value) { if(Index < SIZE) Ident[Index] = Value; };
85 
86 		//! Get a read-only pointer to the identifier value
GetValue(void)87 		const UInt8 *GetValue(void) const { return Ident; };
88 
89 		//! Get the size of the identifier
Size(void)90 		int Size(void) const { return SIZE; };
91 
92 		bool operator!(void) const
93 		{
94 			int i;
95 			for(i=0; i<SIZE; i++) if(Ident[i]) return false;
96 			return true;
97 		}
98 
99 		bool operator<(const Identifier& Other) const
100 		{
101 			if(Other.Size() < SIZE ) return (memcmp(Ident, Other.Ident, Other.Size()) < 0);
102 			                    else return (memcmp(Ident, Other.Ident, SIZE) < 0);
103 		}
104 
105 		bool operator==(const Identifier& Other) const
106 		{
107 			if(Other.Size() != SIZE ) return false;
108 								 else return (memcmp(Ident, Other.Ident, SIZE) == 0);
109 		}
110 
GetString(void)111 		std::string GetString(void) const
112 		{
113 			std::string Ret;
114 			char Buffer[8];
115 
116 			for(int i=0; i<SIZE; i++)
117 			{
118 				sprintf(Buffer, "%02x", Ident[i]);
119 				if(i!=0) Ret += " ";
120 
121 				Ret += Buffer;
122 			}
123 
124 			return Ret;
125 		}
126 	};
127 
128 }
129 
130 namespace mxflib
131 {
132 	// Forward declare UUID
133 	class UUID;
134 
135 	//! A smart pointer to a UUID object
136 	typedef SmartPtr<UUID> UUIDPtr;
137 
138 	//! 16-byte identifier
139 	typedef Identifier<16> Identifier16;
140 
141 	//! Universal Label class with optimized comparison and string formatting
142 	class UL : public RefCount<UL>, public Identifier16
143 	{
144 	private:
145 		//! Prevent default construction
146 		UL();
147 
148 	public:
149 		//! Construct a UL from a sequence of bytes
150 		/*! \note The byte string must contain at least 16 bytes or errors will be produced when it is used
151 		 */
UL(const UInt8 * ID)152 		UL(const UInt8 *ID) : Identifier16(ID) {};
153 
154 		//! Construct a UL as a copy of another UL
UL(const SmartPtr<UL> ID)155 		UL(const SmartPtr<UL> ID) { if(!ID) memset(Ident,0,16); else memcpy(Ident,ID->Ident, 16); };
156 
157 		//! Copy constructor
UL(const UL & RHS)158 		UL(const UL &RHS) { memcpy(Ident,RHS.Ident, 16); };
159 
160 		//! Construct a UL from an end-swapped UUID
UL(const UUID & RHS)161 		UL(const UUID &RHS) { operator=(RHS); }
162 
163 		//! Construct a UL from an end-swapped UUID
UL(const UUIDPtr & RHS)164 		UL(const UUIDPtr &RHS) { operator=(*RHS); }
165 
166 		//! Construct a UL from an end-swapped UUID
UL(const UUID * RHS)167 		UL(const UUID *RHS) { operator=(*RHS); }
168 
169 		//! Fast compare a UL based on testing most-likely to fail bytes first
170 		/*! We use an unrolled loop with modified order for best efficiency
171 		 *  DRAGONS: There may be a slightly faster way that will prevent pipeline stalling, but this is fast enough!
172 		 */
173 		bool operator==(const UL &RHS) const
174 		{
175 			// Most differences are in the second 8 bytes so we check those first
176 			UInt8 const *pLHS = &Ident[8];
177 			UInt8 const *pRHS = &RHS.Ident[8];
178 
179 			if(*pLHS++ != *pRHS++) return false;		// Test byte 8
180 			if(*pLHS++ != *pRHS++) return false;		// Test byte 9
181 			if(*pLHS++ != *pRHS++) return false;		// Test byte 10
182 			if(*pLHS++ != *pRHS++) return false;		// Test byte 11
183 			if(*pLHS++ != *pRHS++) return false;		// Test byte 12
184 			if(*pLHS++ != *pRHS++) return false;		// Test byte 13
185 			if(*pLHS++ != *pRHS++) return false;		// Test byte 14
186 			if(*pLHS != *pRHS) return false;			// Test byte 15
187 
188 			// Now we test the first 8 bytes, but in reverse as the first 4 are almost certainly "06 0e 2b 34"
189 			// We use predecrement from the original start values so that the compiler will optimize the address calculation if possible
190 			pLHS = &Ident[8];
191 			pRHS = &RHS.Ident[8];
192 
193 			if(*--pLHS != *--pRHS) return false;		// Test byte 7
194 			if(*--pLHS != *--pRHS) return false;		// Test byte 6
195 			if(*--pLHS != *--pRHS) return false;		// Test byte 5
196 			if(*--pLHS != *--pRHS) return false;		// Test byte 4
197 			if(*--pLHS != *--pRHS) return false;		// Test byte 3
198 			if(*--pLHS != *--pRHS) return false;		// Test byte 2
199 			if(*--pLHS != *--pRHS) return false;		// Test byte 1
200 
201 			return (*--pLHS == *--pRHS);				// Test byte 0
202 		}
203 
204 		//! Fast compare a UL based on testing most-likely to fail bytes first *IGNORING THE VERSION NUMBER*
205 		/*! We use an unrolled loop with modified order for best efficiency
206 		 *  DRAGONS: There may be a slightly faster way that will prevent pipeline stalling, but this is fast enough!
207 		 */
Matches(const UL & RHS)208 		bool Matches(const UL &RHS) const
209 		{
210 			// Most differences are in the second 8 bytes so we check those first
211 			UInt8 const *pLHS = &Ident[8];
212 			UInt8 const *pRHS = &RHS.Ident[8];
213 
214 			if(*pLHS++ != *pRHS++) return false;		// Test byte 8
215 			if(*pLHS++ != *pRHS++) return false;		// Test byte 9
216 			if(*pLHS++ != *pRHS++) return false;		// Test byte 10
217 			if(*pLHS++ != *pRHS++) return false;		// Test byte 11
218 			if(*pLHS++ != *pRHS++) return false;		// Test byte 12
219 			if(*pLHS++ != *pRHS++) return false;		// Test byte 13
220 			if(*pLHS++ != *pRHS++) return false;		// Test byte 14
221 			if(*pLHS != *pRHS) return false;			// Test byte 15
222 
223 			// Now we test the first 8 bytes, but in reverse as the first 4 are almost certainly "06 0e 2b 34"
224 			// We use predecrement from the original start values so that the compiler will optimize the address calculation if possible
225 			pLHS = &Ident[8];
226 			pRHS = &RHS.Ident[8];
227 
228 			// Skip the UL version number
229 			--pLHS;
230 			--pRHS;
231 
232 			if(*--pLHS != *--pRHS) return false;		// Test byte 6
233 			if(*--pLHS != *--pRHS) return false;		// Test byte 5
234 			if(*--pLHS != *--pRHS) return false;		// Test byte 4
235 			if(*--pLHS != *--pRHS) return false;		// Test byte 3
236 			if(*--pLHS != *--pRHS) return false;		// Test byte 2
237 			if(*--pLHS != *--pRHS) return false;		// Test byte 1
238 
239 			return (*--pLHS == *--pRHS);				// Test byte 0
240 		}
241 
242 		//! Set a UL from a UUID, does end swapping
243 		UL &operator=(const UUID &RHS);
244 
245 		//! Set a UL from a UUID, does end swapping
246 		UL &operator=(const UUIDPtr &RHS) { return operator=(*RHS); }
247 
248 		//! Set a UL from a UUID, does end swapping
249 		UL &operator=(const UUID *RHS) { return operator=(*RHS); }
250 
251 		//! Produce a human-readable string in one of the "standard" formats
GetString(void)252 		std::string GetString(void) const
253 		{
254 			char Buffer[100];
255 
256 			// Check which format should be used
257 			if( !(0x80&Ident[0]) )
258 			{
259 				// This is a UL rather than a UUID packed into a UL datatype
260 				// Print as compact SMPTE format [060e2b34.rrss.mmvv.ccs1s2s3.s4s5s6s7]
261 				// Stored in the following 0-based index order: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
262 				// (i.e. network byte order)
263 				sprintf (Buffer, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
264 							       Ident[0], Ident[1], Ident[2], Ident[3], Ident[4], Ident[5], Ident[6], Ident[7],
265 							       Ident[8], Ident[9], Ident[10], Ident[11], Ident[12], Ident[13], Ident[14], Ident[15]
266 						);
267 			}
268 			else
269 			{
270 				// Half-swapped UUID
271 				// Print as compact GUID format {8899aabb-ccdd-eeff-0011-223344556677}
272 				sprintf (Buffer, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
273 							       Ident[8], Ident[9], Ident[10], Ident[11], Ident[12], Ident[13], Ident[14], Ident[15],
274 							       Ident[0], Ident[1], Ident[2], Ident[3], Ident[4], Ident[5], Ident[6], Ident[7]
275 						);
276 			}
277 
278 			return std::string(Buffer);
279 		}
280 	};
281 
282 	//! A smart pointer to a UL object
283 	typedef SmartPtr<UL> ULPtr;
284 
285 	//! A list of smart pointers to UL objects
286 	typedef std::list<ULPtr> ULList;
287 }
288 
289 
290 namespace mxflib
291 {
292 	//! Universally Unique Identifier class with string formatting
293 	class UUID : public Identifier16, public RefCount<UUID>
294 	{
295 	public:
296 		//! Construct a new UUID with a new unique value
UUID()297 		UUID() { MakeUUID(Ident); };
298 
299 		//! Construct a UUID from a sequence of bytes
300 		/*! \note The byte string must contain at least 16 bytes or errors will be produced when it is used
301 		 */
UUID(const UInt8 * ID)302 		UUID(const UInt8 *ID) : Identifier16(ID) {};
303 
304 		//! Construct a UUID as a copy of another UUID
UUID(const SmartPtr<UUID> ID)305 		UUID(const SmartPtr<UUID> ID) { if(!ID) memset(Ident,0,16); else memcpy(Ident,ID->Ident, 16); };
306 
307 		//! Copy constructor
UUID(const UUID & RHS)308 		UUID(const UUID &RHS) { memcpy(Ident,RHS.Ident, 16); };
309 
310 		//! Construct a UUID from an end-swapped UL
UUID(const UL & RHS)311 		UUID(const UL &RHS) { operator=(RHS); }
312 
313 		//! Construct a UUID from an end-swapped UL
UUID(const ULPtr & RHS)314 		UUID(const ULPtr &RHS) { operator=(*RHS); }
315 
316 		//! Construct a UUID from an end-swapped UL
UUID(const UL * RHS)317 		UUID(const UL *RHS) { operator=(*RHS); }
318 
319 		//! Set a UUID from a UL, does end swapping
320 		UUID &operator=(const UL &RHS)
321 		{
322 			memcpy(Ident, &RHS.GetValue()[8], 8);
323 			memcpy(&Ident[8], RHS.GetValue(), 8);
324 			return *this;
325 		}
326 
327 		//! Set a UUID from a UL, does end swapping
328 		UUID &operator=(const ULPtr &RHS) { return operator=(*RHS); }
329 
330 		//! Set a UUID from a UL, does end swapping
331 		UUID &operator=(const UL *RHS) { return operator=(*RHS); }
332 
333 		//! Produce a human-readable string in one of the "standard" formats
GetString(void)334 		std::string GetString(void) const
335 		{
336 			char Buffer[100];
337 
338 			// Check which format should be used
339 			if( !(0x80&Ident[8]) )
340 			{	// Half-swapped UL packed into a UUID datatype
341 				// Print as compact SMPTE format [bbaa9988.ddcc.ffee.00010203.04050607]
342 				// Stored with upper/lower 8 bytes exchanged
343 				// Stored in the following 0-based index order: 88 99 aa bb cc dd ee ff 00 01 02 03 04 05 06 07
344 				sprintf (Buffer, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
345 							       Ident[8], Ident[9], Ident[10], Ident[11], Ident[12], Ident[13], Ident[14], Ident[15],
346 							       Ident[0], Ident[1], Ident[2], Ident[3], Ident[4], Ident[5], Ident[6], Ident[7]
347 						);
348 			}
349 			else
350 			{	// UUID
351 				// Stored in the following 0-based index order: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
352 				// (i.e. network byte order)
353 				// Print as compact GUID format {00112233-4455-6677-8899-aabbccddeeff}
354 				sprintf (Buffer, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
355 							       Ident[0], Ident[1], Ident[2], Ident[3], Ident[4], Ident[5], Ident[6], Ident[7],
356 							       Ident[8], Ident[9], Ident[10], Ident[11], Ident[12], Ident[13], Ident[14], Ident[15]
357 						);
358 			}
359 
360 			return std::string(Buffer);
361 		}
362 	};
363 }
364 
365 
366 namespace mxflib
367 {
368 	//! Set a UL from a UUID, does end swapping
369 	/*  DRAGONS: Defined here as we need UUID to be fully defined */
370 	inline UL &UL::operator=(const UUID &RHS)
371 	{
372 		memcpy(Ident, &RHS.GetValue()[8], 8);
373 		memcpy(&Ident[8], RHS.GetValue(), 8);
374 		return *this;
375 	}
376 }
377 
378 
379 namespace mxflib
380 {
381 	typedef Identifier<32> Identifier32;
382 	class UMID : public Identifier32, public RefCount<UMID>
383 	{
384 	public:
385 		//! Construct a new UMID either from a sequence of bytes, or as a NULL UMID (32 zero bytes)
386 		/*! \note The byte string must contain at least 32 bytes or errors will be produced when it is used
387 		 */
Identifier32(ID)388 		UMID(const UInt8 *ID = NULL) : Identifier32(ID) {};
389 
390 		//! Construct a UMID from a sequence of bytes
391 		/*! \note The byte string must contain at least 16 bytes or errors will be produced when it is used
392 		 */
UMID(const SmartPtr<UMID> ID)393 		UMID(const SmartPtr<UMID> ID) { if(!ID) memset(Ident,0,32); else memcpy(Ident,ID->Ident, 32); };
394 
395 		//! Copy constructor
UMID(const UMID & RHS)396 		UMID(const UMID &RHS) { memcpy(Ident,RHS.Ident, 16); };
397 
398 		//! Get the UMID's instance number
399 		/*! \note The number returned interprets the instance number as big-endian */
GetInstance(void)400 		UInt32 GetInstance(void) const
401 		{
402 			return (Ident[13] << 16) | (Ident[14] << 8) | Ident[15];
403 		}
404 
405 		//! Set the UMID's instance number
406 		/*! \note The number is set as big-endian */
407 		//	TODO: Should add an option to generate a random instance number
408 		void SetInstance(int Instance, int Method = -1)
409 		{
410 			UInt8 Buffer[4];
411 			PutU32(Instance, Buffer);
412 
413 			// Set the instance number
414 			memcpy(&Ident[13], &Buffer[1], 3);
415 
416 			// Set the method if a new one is specified
417 			if(Method >= 0)
418 			{
419 				Ident[11] = (Ident[11] & 0xf0) | Method;
420 			}
421 		}
422 
423 		//! Set the UMID's material number
SetMaterial(ULPtr aUL)424 		void SetMaterial( ULPtr aUL )
425 		{
426 			// Set the instance number
427 			memcpy(&Ident[16], aUL->GetValue(), 16);
428 
429 			// DRAGONS: Is this the right method for a UL?
430 			Ident[11] = (Ident[11] & 0x0f) | 2<<4;
431 		}
432 	};
433 
434 	//! A smart pointer to a UMID object
435 	typedef SmartPtr<UMID> UMIDPtr;
436 }
437 
438 
439 namespace mxflib
440 {
441 	//! Structure for holding fractions
442 	class Rational
443 	{
444 	public:
445 		Int32 Numerator;				//!< Numerator of the fraction (top number)
446 		Int32 Denominator;				//!< Denominator of the fraction (bottom number)
447 
448 		//! Build an empty Rational
Rational()449 		Rational() : Numerator(0), Denominator(0) {};
450 
451 		//! Initialise a Rational with a value
Rational(Int32 Num,Int32 Den)452 		Rational(Int32 Num, Int32 Den) : Numerator(Num), Denominator(Den) {};
453 
454 		//! Determine the greatest common divisor using the Euclidean algorithm
GreatestCommonDivisor(void)455 		Int32 GreatestCommonDivisor(void)
456 		{
457 			Int32 a;			//! The larger value for Euclidean algorithm
458 			Int32 b;			//! The smaller value for Euclidean algorithm
459 
460 			// Set the larger and smaller values
461 			if(Numerator>Denominator)
462 			{
463 				a = Numerator;
464 				b = Denominator;
465 			}
466 			else
467 			{
468 				a = Denominator;
469 				b = Numerator;
470 			}
471 
472 			// Euclid's Algorithm
473 			while (b != 0)
474 			{
475 				Int32 Temp = b;
476 				b = a % b;
477 				a = Temp;
478 			}
479 
480 			// Return the GCD
481 			return a;
482 		}
483 
484 		//! Reduce a rational to its lowest integer form
Reduce(void)485 		void Reduce(void)
486 		{
487 			Int32 GCD = GreatestCommonDivisor();
488 			Numerator /= GCD;
489 			Denominator /= GCD;
490 		}
491 
492 		//! Check for exact equality (not just the same ratio)
493 		inline bool operator==(const Rational &RHS)
494 		{
495 			return (Numerator == RHS.Numerator) && (Denominator == RHS.Denominator);
496 		}
497 	};
498 
499 	//! Determine the greatest common divisor of a 64-bit / 64-bit pair using the Euclidean algorithm
GreatestCommonDivisor(Int64 Numerator,Int64 Denominator)500 	inline Int64 GreatestCommonDivisor( Int64 Numerator, Int64 Denominator )
501 	{
502 		Int64 a;			//! The larger value for Euclidean algorithm
503 		Int64 b;			//! The smaller value for Euclidean algorithm
504 
505 		// Set the larger and smaller values
506 		if(Numerator>Denominator)
507 		{
508 			a = Numerator;
509 			b = Denominator;
510 		}
511 		else
512 		{
513 			a = Denominator;
514 			b = Numerator;
515 		}
516 
517 		// Euclid's Algorithm
518 		while (b != 0)
519 		{
520 			Int64 Temp = b;
521 			b = a % b;
522 			a = Temp;
523 		}
524 
525 		// Return the GCD
526 		return a;
527 	}
528 
529 	//! Divide one rational by another
530 	inline Rational operator/(const Rational Dividend, const Rational Divisor)
531 	{
532 		// Multiply the numerator of the dividend by the denominator of the divisor (getting a 64-bit result)
533 		Int64 Numerator = Dividend.Numerator;
534 		Numerator *= Divisor.Denominator;
535 
536 		// Multiply the denominator of the dividend by the numerator of the divisor (getting a 64-bit result)
537 		Int64 Denominator = Dividend.Denominator;
538 		Denominator *= Divisor.Numerator;
539 
540 		// Calculate the greated common divisor
541 		Int64 GCD = GreatestCommonDivisor(Numerator, Denominator);
542 
543 		Numerator /= GCD;
544 		Denominator /= GCD;
545 
546 		// Lossy-reduction of any fractions that won't fit in a 32-bit/ 32-bit rational
547 		// TDOD: Check if this is ever required
548 		while( (Numerator & INT64_C(0xffffffff00000000)) ||  (Denominator & INT64_C(0xffffffff00000000)))
549 		{
550 			Numerator >>= 1;
551 			Denominator >>= 1;
552 		}
553 
554 		return Rational(static_cast<Int32>(Numerator), static_cast<Int32>(Denominator));
555 	}
556 
557 	//! Multiply one rational by another
558 	inline Rational operator*(const Rational Multiplicand, const Rational Multiplier)
559 	{
560 		// Multiply the numerator of the multiplicand by the numerator of the multiplier (getting a 64-bit result)
561 		Int64 Numerator = Multiplicand.Numerator;
562 		Numerator *= Multiplier.Numerator;
563 
564 		// Multiply the denominator of the multiplicand by the denominator of the multiplier (getting a 64-bit result)
565 		Int64 Denominator = Multiplicand.Denominator;
566 		Denominator *= Multiplier.Denominator;
567 
568 		// Calculate the greated common divisor
569 		Int64 GCD = GreatestCommonDivisor(Numerator, Denominator);
570 
571 		Numerator /= GCD;
572 		Denominator /= GCD;
573 
574 		// Lossy-reduction of any fractions that won't fit in a 32-bit/ 32-bit rational
575 		// TDOD: Check if this is ever required
576 		while( (Numerator & INT64_C(0xffffffff00000000)) ||  (Denominator & INT64_C(0xffffffff00000000)))
577 		{
578 			Numerator >>= 1;
579 			Denominator >>= 1;
580 		}
581 
582 		return Rational(static_cast<Int32>(Numerator), static_cast<Int32>(Denominator));
583 	}
584 
585 	//! Multiply a position by a rational
586 	inline Position operator*(const Position Multiplicand, const Rational Multiplier)
587 	{
588 		Position Ret = Multiplicand * Multiplier.Numerator;
589 
590 		Int64 Remainder = Ret % Multiplier.Denominator;
591 
592         Ret = Ret / Multiplier.Denominator;
593 
594 		// Round up any result that is nearer to the next position
595 		if(Remainder >= (Multiplier.Denominator/2)) Ret++;
596 
597 		return Ret;
598 	}
599 }
600 
601 
602 #endif // MXFLIB__TYPES_H
603 
604