xref: /freebsd/sys/fs/udf/osta.c (revision 51a7b740a11434580f649a98c2b44b98d60e4292)
151a7b740SScott Long /*
251a7b740SScott Long  * Various routines from the OSTA 2.01 specs.  Copyrights are included with
351a7b740SScott Long  * each code segment.  Slight whitespace modifications have been made for
451a7b740SScott Long  * formatting purposes.  Typos/bugs have been fixed.
551a7b740SScott Long  *
651a7b740SScott Long  * $FreeBSD$
751a7b740SScott Long  */
851a7b740SScott Long 
951a7b740SScott Long #include <fs/udf/osta.h>
1051a7b740SScott Long 
1151a7b740SScott Long /*****************************************************************************/
1251a7b740SScott Long /***********************************************************************
1351a7b740SScott Long  * OSTA compliant Unicode compression, uncompression routines.
1451a7b740SScott Long  * Copyright 1995 Micro Design International, Inc.
1551a7b740SScott Long  * Written by Jason M. Rinn.
1651a7b740SScott Long  * Micro Design International gives permission for the free use of the
1751a7b740SScott Long  * following source code.
1851a7b740SScott Long  */
1951a7b740SScott Long 
2051a7b740SScott Long #include <stddef.h>
2151a7b740SScott Long /***********************************************************************
2251a7b740SScott Long  * Takes an OSTA CS0 compressed unicode name, and converts
2351a7b740SScott Long  * it to Unicode.
2451a7b740SScott Long  * The Unicode output will be in the byte order
2551a7b740SScott Long  * that the local compiler uses for 16-bit values.
2651a7b740SScott Long  * NOTE: This routine only performs error checking on the compID.
2751a7b740SScott Long  * It is up to the user to ensure that the unicode buffer is large
2851a7b740SScott Long  * enough, and that the compressed unicode name is correct.
2951a7b740SScott Long  *
3051a7b740SScott Long  * RETURN VALUE
3151a7b740SScott Long  *
3251a7b740SScott Long  * The number of unicode characters which were uncompressed.
3351a7b740SScott Long  * A -1 is returned if the compression ID is invalid.
3451a7b740SScott Long  */
3551a7b740SScott Long int
3651a7b740SScott Long udf_UncompressUnicode(
3751a7b740SScott Long 	int numberOfBytes,	/* (Input) number of bytes read from media. */
3851a7b740SScott Long 	byte *UDFCompressed,	/* (Input) bytes read from media. */
3951a7b740SScott Long 	unicode_t *unicode)	/* (Output) uncompressed unicode characters. */
4051a7b740SScott Long {
4151a7b740SScott Long 	unsigned int compID;
4251a7b740SScott Long 	int returnValue, unicodeIndex, byteIndex;
4351a7b740SScott Long 
4451a7b740SScott Long 	/* Use UDFCompressed to store current byte being read. */
4551a7b740SScott Long 	compID = UDFCompressed[0];
4651a7b740SScott Long 
4751a7b740SScott Long 	/* First check for valid compID. */
4851a7b740SScott Long 	if (compID != 8 && compID != 16) {
4951a7b740SScott Long 		returnValue = -1;
5051a7b740SScott Long 	} else {
5151a7b740SScott Long 		unicodeIndex = 0;
5251a7b740SScott Long 		byteIndex = 1;
5351a7b740SScott Long 
5451a7b740SScott Long 		/* Loop through all the bytes. */
5551a7b740SScott Long 		while (byteIndex < numberOfBytes) {
5651a7b740SScott Long 			if (compID == 16) {
5751a7b740SScott Long 				/* Move the first byte to the high bits of the
5851a7b740SScott Long 				 * unicode char.
5951a7b740SScott Long 				 */
6051a7b740SScott Long 				unicode[unicodeIndex] =
6151a7b740SScott Long 				    UDFCompressed[byteIndex++] << 8;
6251a7b740SScott Long 			} else {
6351a7b740SScott Long 				unicode[unicodeIndex] = 0;
6451a7b740SScott Long 			}
6551a7b740SScott Long 			if (byteIndex < numberOfBytes) {
6651a7b740SScott Long 				/*Then the next byte to the low bits. */
6751a7b740SScott Long 				unicode[unicodeIndex] |=
6851a7b740SScott Long 				    UDFCompressed[byteIndex++];
6951a7b740SScott Long 			}
7051a7b740SScott Long 			unicodeIndex++;
7151a7b740SScott Long 		}
7251a7b740SScott Long 		returnValue = unicodeIndex;
7351a7b740SScott Long 	}
7451a7b740SScott Long 	return(returnValue);
7551a7b740SScott Long }
7651a7b740SScott Long 
7751a7b740SScott Long /***********************************************************************
7851a7b740SScott Long  * DESCRIPTION:
7951a7b740SScott Long  * Takes a string of unicode wide characters and returns an OSTA CS0
8051a7b740SScott Long  * compressed unicode string. The unicode MUST be in the byte order of
8151a7b740SScott Long  * the compiler in order to obtain correct results. Returns an error
8251a7b740SScott Long  * if the compression ID is invalid.
8351a7b740SScott Long  *
8451a7b740SScott Long  * NOTE: This routine assumes the implementation already knows, by
8551a7b740SScott Long  * the local environment, how many bits are appropriate and
8651a7b740SScott Long  * therefore does no checking to test if the input characters fit
8751a7b740SScott Long  * into that number of bits or not.
8851a7b740SScott Long  *
8951a7b740SScott Long  * RETURN VALUE
9051a7b740SScott Long  *
9151a7b740SScott Long  * The total number of bytes in the compressed OSTA CS0 string,
9251a7b740SScott Long  * including the compression ID.
9351a7b740SScott Long  * A -1 is returned if the compression ID is invalid.
9451a7b740SScott Long  */
9551a7b740SScott Long int
9651a7b740SScott Long udf_CompressUnicode(
9751a7b740SScott Long 	int numberOfChars,	/* (Input) number of unicode characters. */
9851a7b740SScott Long 	int compID,		/* (Input) compression ID to be used. */
9951a7b740SScott Long 	unicode_t *unicode,	/* (Input) unicode characters to compress. */
10051a7b740SScott Long 	byte *UDFCompressed)	/* (Output) compressed string, as bytes. */
10151a7b740SScott Long {
10251a7b740SScott Long 	int byteIndex, unicodeIndex;
10351a7b740SScott Long 
10451a7b740SScott Long 	if (compID != 8 && compID != 16) {
10551a7b740SScott Long 		byteIndex = -1; /* Unsupported compression ID ! */
10651a7b740SScott Long 	} else {
10751a7b740SScott Long 		/* Place compression code in first byte. */
10851a7b740SScott Long 		UDFCompressed[0] = compID;
10951a7b740SScott Long 
11051a7b740SScott Long 		byteIndex = 1;
11151a7b740SScott Long 		unicodeIndex = 0;
11251a7b740SScott Long 		while (unicodeIndex < numberOfChars) {
11351a7b740SScott Long 			if (compID == 16) {
11451a7b740SScott Long 				/* First, place the high bits of the char
11551a7b740SScott Long 				 * into the byte stream.
11651a7b740SScott Long 				 */
11751a7b740SScott Long 				UDFCompressed[byteIndex++] =
11851a7b740SScott Long 				    (unicode[unicodeIndex] & 0xFF00) >> 8;
11951a7b740SScott Long 			}
12051a7b740SScott Long 			/*Then place the low bits into the stream. */
12151a7b740SScott Long 			UDFCompressed[byteIndex++] =
12251a7b740SScott Long 			    unicode[unicodeIndex] & 0x00FF;
12351a7b740SScott Long 			unicodeIndex++;
12451a7b740SScott Long 		}
12551a7b740SScott Long 	}
12651a7b740SScott Long 	return(byteIndex);
12751a7b740SScott Long }
12851a7b740SScott Long 
12951a7b740SScott Long /*****************************************************************************/
13051a7b740SScott Long /*
13151a7b740SScott Long  * CRC 010041
13251a7b740SScott Long  */
13351a7b740SScott Long static unsigned short crc_table[256] = {
13451a7b740SScott Long 	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
13551a7b740SScott Long 	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
13651a7b740SScott Long 	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
13751a7b740SScott Long 	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
13851a7b740SScott Long 	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
13951a7b740SScott Long 	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
14051a7b740SScott Long 	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
14151a7b740SScott Long 	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
14251a7b740SScott Long 	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
14351a7b740SScott Long 	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
14451a7b740SScott Long 	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
14551a7b740SScott Long 	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
14651a7b740SScott Long 	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
14751a7b740SScott Long 	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
14851a7b740SScott Long 	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
14951a7b740SScott Long 	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
15051a7b740SScott Long 	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
15151a7b740SScott Long 	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
15251a7b740SScott Long 	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
15351a7b740SScott Long 	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
15451a7b740SScott Long 	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
15551a7b740SScott Long 	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
15651a7b740SScott Long 	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
15751a7b740SScott Long 	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
15851a7b740SScott Long 	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
15951a7b740SScott Long 	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
16051a7b740SScott Long 	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
16151a7b740SScott Long 	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
16251a7b740SScott Long 	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
16351a7b740SScott Long 	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
16451a7b740SScott Long 	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
16551a7b740SScott Long 	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
16651a7b740SScott Long };
16751a7b740SScott Long 
16851a7b740SScott Long unsigned short
16951a7b740SScott Long udf_cksum(s, n)
17051a7b740SScott Long 	unsigned char *s;
17151a7b740SScott Long 	int n;
17251a7b740SScott Long {
17351a7b740SScott Long 	unsigned short crc=0;
17451a7b740SScott Long 
17551a7b740SScott Long 	while (n-- > 0)
17651a7b740SScott Long 		crc = crc_table[(crc>>8 ^ *s++) & 0xff] ^ (crc<<8);
17751a7b740SScott Long 	return crc;
17851a7b740SScott Long }
17951a7b740SScott Long 
18051a7b740SScott Long /* UNICODE Checksum */
18151a7b740SScott Long unsigned short
18251a7b740SScott Long udf_unicode_cksum(s, n)
18351a7b740SScott Long 	unsigned short *s;
18451a7b740SScott Long 	int n;
18551a7b740SScott Long {
18651a7b740SScott Long 	unsigned short crc=0;
18751a7b740SScott Long 
18851a7b740SScott Long 	while (n-- > 0) {
18951a7b740SScott Long 		/* Take high order byte first--corresponds to a big endian
19051a7b740SScott Long 		 * byte stream.
19151a7b740SScott Long 		 */
19251a7b740SScott Long 		crc = crc_table[(crc>>8 ^ (*s>>8)) & 0xff] ^ (crc<<8);
19351a7b740SScott Long 		crc = crc_table[(crc>>8 ^ (*s++ & 0xff)) & 0xff] ^ (crc<<8);
19451a7b740SScott Long 	}
19551a7b740SScott Long 	return crc;
19651a7b740SScott Long }
19751a7b740SScott Long 
19851a7b740SScott Long #ifdef MAIN
19951a7b740SScott Long unsigned char bytes[] = { 0x70, 0x6A, 0x77 };
20051a7b740SScott Long 
20151a7b740SScott Long main()
20251a7b740SScott Long {
20351a7b740SScott Long 	unsigned short x;
20451a7b740SScott Long 	x = cksum(bytes, sizeof bytes);
20551a7b740SScott Long 	printf("checksum: calculated=%4.4x, correct=%4.4x\en", x, 0x3299);
20651a7b740SScott Long 	exit(0);
20751a7b740SScott Long }
20851a7b740SScott Long #endif
20951a7b740SScott Long 
21051a7b740SScott Long /*****************************************************************************/
21151a7b740SScott Long #ifdef NEEDS_ISPRINT
21251a7b740SScott Long /***********************************************************************
21351a7b740SScott Long  * OSTA UDF compliant file name translation routine for OS/2,
21451a7b740SScott Long  * Windows 95, Windows NT, Macintosh and UNIX.
21551a7b740SScott Long  * Copyright 1995 Micro Design International, Inc.
21651a7b740SScott Long  * Written by Jason M. Rinn.
21751a7b740SScott Long  * Micro Design International gives permission for the free use of the
21851a7b740SScott Long  * following source code.
21951a7b740SScott Long  */
22051a7b740SScott Long 
22151a7b740SScott Long /***********************************************************************
22251a7b740SScott Long  * To use these routines with different operating systems.
22351a7b740SScott Long  *
22451a7b740SScott Long  * OS/2
22551a7b740SScott Long  * Define OS2
22651a7b740SScott Long  * Define MAXLEN = 254
22751a7b740SScott Long  *
22851a7b740SScott Long  * Windows 95
22951a7b740SScott Long  * Define WIN_95
23051a7b740SScott Long  * Define MAXLEN = 255
23151a7b740SScott Long  *
23251a7b740SScott Long  * Windows NT
23351a7b740SScott Long  * Define WIN_NT
23451a7b740SScott Long  * Define MAXLEN = 255
23551a7b740SScott Long  *
23651a7b740SScott Long  * Macintosh:
23751a7b740SScott Long  * Define MAC.
23851a7b740SScott Long  * Define MAXLEN = 31.
23951a7b740SScott Long  *
24051a7b740SScott Long  * UNIX
24151a7b740SScott Long  * Define UNIX.
24251a7b740SScott Long  * Define MAXLEN as specified by unix version.
24351a7b740SScott Long  */
24451a7b740SScott Long 
24551a7b740SScott Long #define	ILLEGAL_CHAR_MARK	0x005F
24651a7b740SScott Long #define	CRC_MARK	0x0023
24751a7b740SScott Long #define	EXT_SIZE	5
24851a7b740SScott Long #define	TRUE	1
24951a7b740SScott Long #define	FALSE	0
25051a7b740SScott Long #define	PERIOD	0x002E
25151a7b740SScott Long #define	SPACE	0x0020
25251a7b740SScott Long 
25351a7b740SScott Long /*** PROTOTYPES ***/
25451a7b740SScott Long int IsIllegal(unicode_t ch);
25551a7b740SScott Long 
25651a7b740SScott Long /* Define a function or macro which determines if a Unicode character is
25751a7b740SScott Long  * printable under your implementation.
25851a7b740SScott Long  */
25951a7b740SScott Long int UnicodeIsPrint(unicode_t);
26051a7b740SScott Long 
26151a7b740SScott Long /***********************************************************************
26251a7b740SScott Long  * Translates a long file name to one using a MAXLEN and an illegal
26351a7b740SScott Long  * char set in accord with the OSTA requirements. Assumes the name has
26451a7b740SScott Long  * already been translated to Unicode.
26551a7b740SScott Long  *
26651a7b740SScott Long  * RETURN VALUE
26751a7b740SScott Long  *
26851a7b740SScott Long  * Number of unicode characters in translated name.
26951a7b740SScott Long  */
27051a7b740SScott Long int UDFTransName(
27151a7b740SScott Long 	unicode_t *newName,	/* (Output)Translated name. Must be of length
27251a7b740SScott Long 				 * MAXLEN */
27351a7b740SScott Long 	unicode_t *udfName,	/* (Input) Name from UDF volume.*/
27451a7b740SScott Long 	int udfLen)		/* (Input) Length of UDF Name. */
27551a7b740SScott Long {
27651a7b740SScott Long 	int index, newIndex = 0, needsCRC = FALSE;
27751a7b740SScott Long 	int extIndex = 0, newExtIndex = 0, hasExt = FALSE;
27851a7b740SScott Long #if defined OS2 || defined WIN_95 || defined WIN_NT
27951a7b740SScott Long 	int trailIndex = 0;
28051a7b740SScott Long #endif
28151a7b740SScott Long 	unsigned short valueCRC;
28251a7b740SScott Long 	unicode_t current;
28351a7b740SScott Long 	const char hexChar[] = "0123456789ABCDEF";
28451a7b740SScott Long 
28551a7b740SScott Long 	for (index = 0; index < udfLen; index++) {
28651a7b740SScott Long 		current = udfName[index];
28751a7b740SScott Long 
28851a7b740SScott Long 		if (IsIllegal(current) || !UnicodeIsPrint(current)) {
28951a7b740SScott Long 			needsCRC = TRUE;
29051a7b740SScott Long 			/* Replace Illegal and non-displayable chars with
29151a7b740SScott Long 			 * underscore.
29251a7b740SScott Long 			 */
29351a7b740SScott Long 			current = ILLEGAL_CHAR_MARK;
29451a7b740SScott Long 			/* Skip any other illegal or non-displayable
29551a7b740SScott Long 			 * characters.
29651a7b740SScott Long 			 */
29751a7b740SScott Long 			while(index+1 < udfLen && (IsIllegal(udfName[index+1])
29851a7b740SScott Long 			    || !UnicodeIsPrint(udfName[index+1]))) {
29951a7b740SScott Long 				index++;
30051a7b740SScott Long 			}
30151a7b740SScott Long 		}
30251a7b740SScott Long 
30351a7b740SScott Long 		/* Record position of extension, if one is found. */
30451a7b740SScott Long 		if (current == PERIOD && (udfLen - index -1) <= EXT_SIZE) {
30551a7b740SScott Long 			if (udfLen == index + 1) {
30651a7b740SScott Long 				/* A trailing period is NOT an extension. */
30751a7b740SScott Long 				hasExt = FALSE;
30851a7b740SScott Long 			} else {
30951a7b740SScott Long 				hasExt = TRUE;
31051a7b740SScott Long 				extIndex = index;
31151a7b740SScott Long 				newExtIndex = newIndex;
31251a7b740SScott Long 			}
31351a7b740SScott Long 		}
31451a7b740SScott Long 
31551a7b740SScott Long #if defined OS2 || defined WIN_95 || defined WIN_NT
31651a7b740SScott Long 		/* Record position of last char which is NOT period or space. */
31751a7b740SScott Long 		else if (current != PERIOD && current != SPACE) {
31851a7b740SScott Long 			trailIndex = newIndex;
31951a7b740SScott Long 		}
32051a7b740SScott Long #endif
32151a7b740SScott Long 
32251a7b740SScott Long 		if (newIndex < MAXLEN) {
32351a7b740SScott Long 			newName[newIndex++] = current;
32451a7b740SScott Long 		} else {
32551a7b740SScott Long 			needsCRC = TRUE;
32651a7b740SScott Long 		}
32751a7b740SScott Long 	}
32851a7b740SScott Long 
32951a7b740SScott Long #if defined OS2 || defined WIN_95 || defined WIN_NT
33051a7b740SScott Long 	/* For OS2, 95 & NT, truncate any trailing periods and\or spaces. */
33151a7b740SScott Long 	if (trailIndex != newIndex - 1) {
33251a7b740SScott Long 		newIndex = trailIndex + 1;
33351a7b740SScott Long 		needsCRC = TRUE;
33451a7b740SScott Long 		hasExt = FALSE; /* Trailing period does not make an
33551a7b740SScott Long 				 * extension. */
33651a7b740SScott Long 	}
33751a7b740SScott Long #endif
33851a7b740SScott Long 
33951a7b740SScott Long 	if (needsCRC) {
34051a7b740SScott Long 		unicode_t ext[EXT_SIZE];
34151a7b740SScott Long 		int localExtIndex = 0;
34251a7b740SScott Long 		if (hasExt) {
34351a7b740SScott Long 			int maxFilenameLen;
34451a7b740SScott Long 			/* Translate extension, and store it in ext. */
34551a7b740SScott Long 			for(index = 0; index<EXT_SIZE &&
34651a7b740SScott Long 			    extIndex + index +1 < udfLen; index++ ) {
34751a7b740SScott Long 				current = udfName[extIndex + index + 1];
34851a7b740SScott Long 				if (IsIllegal(current) ||
34951a7b740SScott Long 				    !UnicodeIsPrint(current)) {
35051a7b740SScott Long 					needsCRC = 1;
35151a7b740SScott Long 					/* Replace Illegal and non-displayable
35251a7b740SScott Long 					 * chars with underscore.
35351a7b740SScott Long 					 */
35451a7b740SScott Long 					current = ILLEGAL_CHAR_MARK;
35551a7b740SScott Long 					/* Skip any other illegal or
35651a7b740SScott Long 					 * non-displayable characters.
35751a7b740SScott Long 					 */
35851a7b740SScott Long 					while(index + 1 < EXT_SIZE
35951a7b740SScott Long 					    && (IsIllegal(udfName[extIndex +
36051a7b740SScott Long 					    index + 2]) ||
36151a7b740SScott Long 					    !isprint(udfName[extIndex +
36251a7b740SScott Long 					    index + 2]))) {
36351a7b740SScott Long 						index++;
36451a7b740SScott Long 					}
36551a7b740SScott Long 				}
36651a7b740SScott Long 				ext[localExtIndex++] = current;
36751a7b740SScott Long 			}
36851a7b740SScott Long 
36951a7b740SScott Long 			/* Truncate filename to leave room for extension and
37051a7b740SScott Long 			 * CRC.
37151a7b740SScott Long 			 */
37251a7b740SScott Long 			maxFilenameLen = ((MAXLEN - 5) - localExtIndex - 1);
37351a7b740SScott Long 			if (newIndex > maxFilenameLen) {
37451a7b740SScott Long 				newIndex = maxFilenameLen;
37551a7b740SScott Long 			} else {
37651a7b740SScott Long 				newIndex = newExtIndex;
37751a7b740SScott Long 			}
37851a7b740SScott Long 		} else if (newIndex > MAXLEN - 5) {
37951a7b740SScott Long 			/*If no extension, make sure to leave room for CRC. */
38051a7b740SScott Long 			newIndex = MAXLEN - 5;
38151a7b740SScott Long 		}
38251a7b740SScott Long 		newName[newIndex++] = CRC_MARK; /* Add mark for CRC. */
38351a7b740SScott Long 
38451a7b740SScott Long 		/*Calculate CRC from original filename from FileIdentifier. */
38551a7b740SScott Long 		valueCRC = udf_unicode_cksum(udfName, udfLen);
38651a7b740SScott Long 		/* Convert 16-bits of CRC to hex characters. */
38751a7b740SScott Long 		newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
38851a7b740SScott Long 		newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
38951a7b740SScott Long 		newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
39051a7b740SScott Long 		newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
39151a7b740SScott Long 
39251a7b740SScott Long 		/* Place a translated extension at end, if found. */
39351a7b740SScott Long 		if (hasExt) {
39451a7b740SScott Long 			newName[newIndex++] = PERIOD;
39551a7b740SScott Long 			for (index = 0;index < localExtIndex ;index++ ) {
39651a7b740SScott Long 				newName[newIndex++] = ext[index];
39751a7b740SScott Long 			}
39851a7b740SScott Long 		}
39951a7b740SScott Long 	}
40051a7b740SScott Long 	return(newIndex);
40151a7b740SScott Long }
40251a7b740SScott Long 
40351a7b740SScott Long #if defined OS2 || defined WIN_95 || defined WIN_NT
40451a7b740SScott Long /***********************************************************************
40551a7b740SScott Long  * Decides if a Unicode character matches one of a list
40651a7b740SScott Long  * of ASCII characters.
40751a7b740SScott Long  * Used by OS2 version of IsIllegal for readability, since all of the
40851a7b740SScott Long  * illegal characters above 0x0020 are in the ASCII subset of Unicode.
40951a7b740SScott Long  * Works very similarly to the standard C function strchr().
41051a7b740SScott Long  *
41151a7b740SScott Long  * RETURN VALUE
41251a7b740SScott Long  *
41351a7b740SScott Long  * Non-zero if the Unicode character is in the given ASCII string.
41451a7b740SScott Long  */
41551a7b740SScott Long int UnicodeInString(
41651a7b740SScott Long 	unsigned char *string,	/* (Input) String to search through. */
41751a7b740SScott Long 	unicode_t ch)		/* (Input) Unicode char to search for. */
41851a7b740SScott Long {
41951a7b740SScott Long 	int found = FALSE;
42051a7b740SScott Long 	while (*string != '\0' && found == FALSE) {
42151a7b740SScott Long 		/* These types should compare, since both are unsigned
42251a7b740SScott Long 		 * numbers. */
42351a7b740SScott Long 		if (*string == ch) {
42451a7b740SScott Long 			found = TRUE;
42551a7b740SScott Long 		}
42651a7b740SScott Long 		string++;
42751a7b740SScott Long 	}
42851a7b740SScott Long 	return(found);
42951a7b740SScott Long }
43051a7b740SScott Long #endif /* OS2 */
43151a7b740SScott Long 
43251a7b740SScott Long /***********************************************************************
43351a7b740SScott Long  * Decides whether the given character is illegal for a given OS.
43451a7b740SScott Long  *
43551a7b740SScott Long  * RETURN VALUE
43651a7b740SScott Long  *
43751a7b740SScott Long  * Non-zero if char is illegal.
43851a7b740SScott Long  */
43951a7b740SScott Long int IsIllegal(unicode_t ch)
44051a7b740SScott Long {
44151a7b740SScott Long #ifdef MAC
44251a7b740SScott Long 	/* Only illegal character on the MAC is the colon. */
44351a7b740SScott Long 	if (ch == 0x003A) {
44451a7b740SScott Long 		return(1);
44551a7b740SScott Long 	} else {
44651a7b740SScott Long 		return(0);
44751a7b740SScott Long 	}
44851a7b740SScott Long 
44951a7b740SScott Long #elif defined UNIX
45051a7b740SScott Long 	/* Illegal UNIX characters are NULL and slash. */
45151a7b740SScott Long 	if (ch == 0x0000 || ch == 0x002F) {
45251a7b740SScott Long 		return(1);
45351a7b740SScott Long 	} else {
45451a7b740SScott Long 		return(0);
45551a7b740SScott Long 	}
45651a7b740SScott Long 
45751a7b740SScott Long #elif defined OS2 || defined WIN_95 || defined WIN_NT
45851a7b740SScott Long 	/* Illegal char's for OS/2 according to WARP toolkit. */
45951a7b740SScott Long 	if (ch < 0x0020 || UnicodeInString("\\/:*?\"<>|", ch)) {
46051a7b740SScott Long 		return(1);
46151a7b740SScott Long 	} else {
46251a7b740SScott Long 		return(0);
46351a7b740SScott Long 	}
46451a7b740SScott Long #endif
46551a7b740SScott Long }
46651a7b740SScott Long #endif
467