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