/* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 1, or (at your option) ** any later version. ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Author : Alexandre Parenteau --- December 1997 */ #ifdef __MACH__ #include "cvs.h" #include "system.h" #include "error.h" #include #include #include #include #include #include "hqx.h" #include "cvs_hqx.h" #include "apsingle.h" #include #include #include extern int quiet; extern int really_quiet; extern int cvs_output(const char*, size_t); OSStatus PathToFSRef(const char *filename, FSRef * res) { return FSPathMakeRef((UInt8 *)filename, res, 0L); } OSStatus StrToUnicode(const char *str, UniChar *ustr, SInt32 *uniLen, TextEncoding *outEncoder) { TextEncoding encoder = kTextEncodingMacRoman; TextToUnicodeInfo textToUnicodeInfo; ByteCount oUnicodeLen; OSStatus status; Str255 pstr; c2pstrcpy(pstr, str); status = CreateTextToUnicodeInfoByEncoding(encoder, &textToUnicodeInfo); if(status != noErr) return status; status = ConvertFromPStringToUnicode(textToUnicodeInfo, pstr, *uniLen * sizeof(UniChar), &oUnicodeLen, ustr); DisposeTextToUnicodeInfo(&textToUnicodeInfo); if(status == noErr) { *uniLen = oUnicodeLen / sizeof(UniChar); if(outEncoder != 0L) *outEncoder = encoder; } return status; } struct TypeEntry { OSType type; CFStringRef ext; }; static void fillSemiColonTypes(const char *envVar, TypeEntry *& allTypes, int & numTypes, const char* defaults) { allTypes = 0L; numTypes = 0; const char *envRes = CProtocolLibrary::GetEnvironment(envVar); if ( envRes == 0L ) envRes = defaults; if(envRes == 0L) return; char *tmpStr = (char *)malloc(strlen(envRes) + 1); if(tmpStr == 0L) error (1, errno, "Running out of memory !"); strcpy(tmpStr, envRes); char *tmp = tmpStr, *colon = 0L, *start = tmpStr; while((tmp = strchr(tmp, ';')) != 0L) { *tmp = '\0'; if((tmp - start) == 4) { if(allTypes == 0L) allTypes = (TypeEntry *)malloc(sizeof(TypeEntry)); else allTypes = (TypeEntry *)realloc(allTypes, (numTypes + 1) * sizeof(TypeEntry)); if(allTypes == 0L) error (1, errno, "Running out of memory !"); OSType atype; ((char *)&atype)[0] = *start++; ((char *)&atype)[1] = *start++; ((char *)&atype)[2] = *start++; ((char *)&atype)[3] = *start; allTypes[numTypes].type = atype; allTypes[numTypes].ext = NULL; numTypes++; } else if((tmp - start) > 4 && start[4] == '/') { if(allTypes == 0L) allTypes = (TypeEntry *)malloc(sizeof(TypeEntry)); else allTypes = (TypeEntry *)realloc(allTypes, (numTypes + 1) * sizeof(TypeEntry)); if(allTypes == 0L) error (1, errno, "Running out of memory !"); OSType atype; ((char *)&atype)[0] = *start++; ((char *)&atype)[1] = *start++; ((char *)&atype)[2] = *start++; ((char *)&atype)[3] = *start++; ++start; // skip delimiter '/' allTypes[numTypes].type = atype; if ( *start != 0 ) { allTypes[numTypes].ext = CFStringCreateWithCString(NULL, start, kCFStringEncodingUTF8); if ( allTypes[numTypes].ext == NULL ) error(0, coreFoundationUnknownErr, "Warning: can't create CFStringRef for extension %s (variable : %s) !", start, envRes); } else allTypes[numTypes].ext = NULL; numTypes++; } else { error (0, errno, "Warning unknown signature %s (variable : %s) !", start, envRes); } start = ++tmp; } } static bool isTypeInList(OSType inFileType, CFStringRef inFileExtension, const TypeEntry* inTypeList, int inNumTypes, const char* mappingsName) { if ( inTypeList == NULL ) return false; // check for type _and_ extension match if ( inFileType != 0 && inFileType != '\?\?\?\?' && inFileExtension != NULL ) for(int i = 0; i < inNumTypes; i++) { if ( inTypeList[i].ext != NULL && inTypeList[i].type != '\?\?\?\?' ) if ( inTypeList[i].type == inFileType && CFStringCompare(inFileExtension, inTypeList[i].ext, kCFCompareCaseInsensitive|kCFCompareNonliteral) == kCFCompareEqualTo ) return true; } // check for extension only match if ( inFileExtension != NULL ) for(int i = 0; i < inNumTypes; i++) { if ( inTypeList[i].ext != NULL && inTypeList[i].type == '\?\?\?\?') if (CFStringCompare(inFileExtension, inTypeList[i].ext, kCFCompareCaseInsensitive|kCFCompareNonliteral) == kCFCompareEqualTo) return true; } // check for file type only match if ( inFileType != 0 && inFileType != '\?\?\?\?' ) for(int i = 0; i < inNumTypes; i++) { if( inTypeList[i].type != '\?\?\?\?' && inTypeList[i].ext == NULL && inTypeList[i].type == inFileType ) return true; } return false; } static Boolean isPlainBinary(OSType ftype, CFStringRef extension) { static TypeEntry *allTypes = (TypeEntry *)-1; static int numTypes; if(allTypes == (TypeEntry *)-1) { fillSemiColonTypes("MAC_BINARY_TYPES_PLAIN", allTypes, numTypes, "\?\?\?\?/gif;\?\?\?\?/tif;\?\?\?\?/tiff;\?\?\?\?/jpg;\?\?\?\?/jpeg;\?\?\?\?/png;\?\?\?\?.icns"); } return isTypeInList(ftype, extension, allTypes, numTypes, "plain binary mappings"); } static Boolean testHQXEncoding(OSType ftype, CFStringRef extension) { static TypeEntry *allTypes = (TypeEntry *)-1; static int numTypes; if(allTypes == (TypeEntry *)-1) { fillSemiColonTypes("MAC_BINARY_TYPES_HQX", allTypes, numTypes, "rsrc;RSRC;\?\?\?\?/rsrc;\?\?\?\?.ppob"); } return isTypeInList(ftype, extension, allTypes, numTypes, "HQX mappings"); } static Boolean testAppleSingleEncoding(OSType ftype, CFStringRef extension) { static TypeEntry *allTypes = (TypeEntry *)-1; static int numTypes; if(allTypes == (TypeEntry *)-1) { fillSemiColonTypes("MAC_BINARY_TYPES_SINGLE", allTypes, numTypes, NULL); } return isTypeInList(ftype, extension, allTypes, numTypes, "AppleSingle mappings"); } // - Tells which encoder to use. Check the env. variables "MAC_BINARY_TYPES_HQX" // and "MAC_BINARY_TYPES_SINGLE". If the type is not inside, return the // default encoder "MAC_DEFAULT_RESOURCE_ENCODING". // - Note that the plain binary test has to overide this one in every cases. typedef enum { eEncodeDefault = -1, eEncodeHQX, eEncodeAppleSingle, eEncodePlainBinary } encodingPolicy; static encodingPolicy determineEncodingPolicy(OSType ftype, CFStringRef extension) { if(isPlainBinary(ftype, extension)) { return eEncodePlainBinary; } else if(testHQXEncoding(ftype, extension)) { return eEncodeHQX; } else if(testAppleSingleEncoding(ftype, extension)) { return eEncodeAppleSingle; } else { return eEncodeDefault; } } static void getDefaultEncodingPolicy(encodingPolicy *policy) { char mac_default_resource_encoding[]="MAC_DEFAULT_RESOURCE_ENCODING"; char cvs_default_resource_encoding[]="CVS_DEFAULT_RESOURCE_ENCODING"; // get the default encoder static char *envRes = (char *)CProtocolLibrary::GetEnvironment(mac_default_resource_encoding); if(envRes == 0L) envRes = (char *)CProtocolLibrary::GetEnvironment(cvs_default_resource_encoding); if(envRes == 0L) { // default to plain binary, to avoid problems when working cross-platform *policy = eEncodePlainBinary; return; } if(strcmp(envRes, "HQX") == 0) { *policy = eEncodeHQX; return; } else if(strcmp(envRes, "AppleSingle") == 0) { *policy = eEncodeAppleSingle; return; } else if(strcmp(envRes, "PlainBinary") == 0) { *policy = eEncodePlainBinary; return; } error (1, errno, "Unknown resource encoding '%s' !\n", envRes); } static FILE *gDestFile; static FILE *gSrcFile; static OSErr MyDest(void* buffer, long count, long param) { fwrite(buffer, count, 1, gDestFile); return noErr; } static OSErr MySource(void* buffer, long *count, long param) { *count = fread(buffer, 1, *count, gSrcFile); return noErr; } struct AutoCFStringRef { CFStringRef ref; AutoCFStringRef() : ref(NULL) {} ~AutoCFStringRef() { if ( ref ) CFRelease(ref); } operator CFStringRef() const { return ref; } }; int convert_hqx_file (const char *infile, int encode, const char *outfile, int *bin) { OSErr err = fnfErr; encodingPolicy inFileType; OSType filetype = 0; OSType filecreator; FSRef inspec, outspec; FSCatalogInfo catalogInfo, catalogDestInfo; HFSUniStr255 fileName; AutoCFStringRef extension; if (!encode) { // the cvswrapper has to be coherent !!! if((*bin) == 0) return 0; gSrcFile = fopen(infile, "r"); if(gSrcFile == NULL) error(1, errno, "Cannot open %s (%s %d)", infile, __FILE__, __LINE__); char buf[100]; static char hqxheader[] = "(This file must be converted with BinHex 4.0)"; UInt32 asheader = AS_MAGIC_NUM; fread (buf, sizeof(char), 100, gSrcFile); // Determine whether the file is one of the known encodings if ( memcmp(hqxheader, buf, strlen(hqxheader) * sizeof(char)) == 0) { inFileType = eEncodeHQX; fseek(gSrcFile, 0, SEEK_SET); } else if ( memcmp(&asheader, buf, sizeof(asheader)) == 0 ) { fclose(gSrcFile); inFileType = eEncodeAppleSingle; } else { // it is a "plain" binary fclose(gSrcFile); return 0; } } else { // check if it is a text file OSStatus status = PathToFSRef(infile, &inspec); if(status != noErr) error(1, status, "Internal error: %s, %d", __FILE__, __LINE__); status = ::FSGetCatalogInfo(&inspec, kFSCatInfoFinderInfo | kFSCatInfoRsrcSizes, &catalogInfo, &fileName, 0L, 0L); if(status != noErr) error(1, status, "Internal error: %s, %d", __FILE__, __LINE__); filetype = ((FInfo *)catalogInfo.finderInfo)->fdType; if(filetype == 'TEXT') return 0; if ( *bin == 0 ) { const char *envRes = CProtocolLibrary::GetEnvironment("MAC_ENCODE_ONLY_BINARY_FILES"); if ( envRes == NULL || strcmp(envRes, "0") != 0 ) { if ( !really_quiet && catalogInfo.rsrcLogicalSize != 0 ) { cvs_output ("Resource fork of non-binary file '", 0); cvs_output (infile, 0); cvs_output ("' discarded.\n", 0); } return 0; } } } if(encode) { encodingPolicy policy; AutoCFStringRef fname; CFIndex extensionStart; // we won't use LSGetExtensionInfo to determine the extension, since this will only detect 'known' extensions, // but some of the extensions used for resource fork handling might not be detected by LSGetExtensionInfo. Thus, // we'll just search for the last '.' and use any following characters as the extension. fname.ref = CFStringCreateWithCharactersNoCopy(NULL, fileName.unicode, fileName.length, kCFAllocatorNull); if ( fname.ref ) { CFRange foundRange; if ( CFStringFindWithOptions(fname, CFSTR("."), CFRangeMake(0, fileName.length), kCFCompareBackwards|kCFCompareNonliteral|kCFCompareCaseInsensitive, &foundRange) && (foundRange.location + 1 < fileName.length) ) { extension.ref = CFStringCreateWithCharactersNoCopy(NULL, fileName.unicode + foundRange.location + 1, fileName.length - foundRange.location - 1, kCFAllocatorNull); if ( extension.ref == NULL ) error (0, 0, "Warning: Can't determine extension of file '%s', thus resource fork handling might not be correct.\n", infile); } } else { error (0, 0, "Warning: Can't determine extension of file '%s', thus resource fork handling might not be correct.\n", infile); } policy = determineEncodingPolicy(filetype, extension); // special case, some files may be forced as plain binary. // (env. variable "MAC_BINARY_TYPES_PLAIN") if(policy == eEncodePlainBinary) { if ( !really_quiet && catalogInfo.rsrcLogicalSize != 0 ) { cvs_output ("Resource fork of file '", 0); cvs_output (infile, 0); cvs_output ("' discarded because plain binary mapping was specified.\n", 0); } *bin = 1; return 0; } else if(policy == eEncodeDefault) { // Never encode any files that have no resource fork // Should we just use the test: if ( if(catalogInfo.rsrcLogicalSize == 0) { // it is a "plain" binary *bin = 1; return 0; } // get default policy getDefaultEncodingPolicy(&policy); if(policy == eEncodePlainBinary) { if ( !really_quiet && catalogInfo.rsrcLogicalSize != 0 ) { cvs_output ("Resource fork of file '", 0); cvs_output (infile, 0); cvs_output ("' discarded because default mapping 'plain binary' was used.\n", 0); } *bin = 1; return 0; } } if(policy == eEncodeHQX) { if ( !really_quiet ) { cvs_output ("Using BinHex encoding for file '", 0); cvs_output (infile, 0); cvs_output ("'.\n", 0); } gDestFile = fopen(outfile, "w"); if(gDestFile == NULL) error(1, errno, "Internal error: %s, %d", __FILE__, __LINE__); err = HQXEncode(infile, MyDest, 0); fflush(gDestFile); fclose(gDestFile); if(err != noErr) error(1, err, "Internal error: %s, %d", __FILE__, __LINE__); } else if ( policy == eEncodeAppleSingle ) { if ( !really_quiet ) { cvs_output ("Using AppleSingle encoding for file '", 0); cvs_output (infile, 0); cvs_output ("'.\n", 0); } #define APPLESINGLE_WANTED_ENTRIES ((UInt32)AS_DATA_BIT | AS_RESOURCE_BIT | AS_COMMENT_BIT | AS_FINDERINFO_BIT | AS_MACINFO_BIT) UInt32 wantedEntries = APPLESINGLE_WANTED_ENTRIES; err = encodeAppleSingle(infile, outfile, wantedEntries); if (err != noErr) error(1, err, "Internal error: %s, %d", __FILE__, __LINE__); } else { error(1, errno, "Internal error: %s, %d", __FILE__, __LINE__); } } else // decoding { if ( inFileType == eEncodeHQX ) { err = HQXDecode(MySource, outfile, true, true, 0); fclose(gSrcFile); if(err != noErr) error(1, err, "Internal error: %s, %d", __FILE__, __LINE__); } else if ( inFileType == eEncodeAppleSingle) { UInt32 wantedEntries = APPLESINGLE_WANTED_ENTRIES; err = decodeAppleSingle(infile, outfile, wantedEntries); if (err != noErr) error(1, err, "Internal error: %s, %d", __FILE__, __LINE__); // Sometimes, type/creator information is not encoded inside the AS file // If so, we want to set type/creator using Internet Config OSStatus status = PathToFSRef(outfile, &outspec); if(status != noErr) error(1, status, "Internal error: %s, %d", __FILE__, __LINE__); status = ::FSGetCatalogInfo(&outspec, kFSCatInfoFinderInfo, &catalogDestInfo, 0L, 0L, 0L); if(status != noErr) error(1, status, "Internal error: %s, %d", __FILE__, __LINE__); filetype = ((FInfo *)catalogDestInfo.finderInfo)->fdType; filecreator = ((FInfo *)catalogDestInfo.finderInfo)->fdCreator; if(filetype == AS_DEFAULT_TYPE && filecreator == AS_DEFAULT_CREATOR) { set_file_type(outfile, true); } } else { error(1, errno, "Internal error: %s, %d", __FILE__, __LINE__); } } return 1; } static OSStatus CachedICStart (ICInstance* outInstance) { static ICInstance inst = 0; static OSErr theErr = noErr; if(inst == 0 && theErr == noErr) theErr = ICStart(&inst, 'CVS '); // Use your creator code if you have one! if (theErr == noErr) *outInstance = inst; return theErr; } void set_file_type(const char *outfile, Boolean warnOnFail) { OSStatus err; ICInstance inst; Str255 filename; c2pstrcpy(filename, outfile); err = CachedICStart(&inst); // Use your creator code if you have one! if (err != noErr) { static Boolean firsttime = true; if(firsttime) { error(0, err, "WARNING Internet config's missing !"); firsttime = false; } return; } ICMapEntry entry; err = ICMapFilename(inst, filename, &entry); if(err == icPrefNotFoundErr) { #if 0 // TODO: to restore. create a new protocol getenv entry.fileCreator = FOUR_CHAR_CODE('CWIE'); entry.fileType = FOUR_CHAR_CODE('TEXT'); err = noErr; #endif } if (err != noErr) { if (warnOnFail) error(0, err, "WARNING: Internet Config cannot map file %s", outfile); return; } FInfo *fndrInfo; FSRef outspec; OSStatus status; err = PathToFSRef(outfile, &outspec); if(err != noErr) { error(0, err, "Internal error: %s, %d", __FILE__, __LINE__); return; } FSCatalogInfo catalogInfo; status = ::FSGetCatalogInfo(&outspec, kFSCatInfoFinderInfo, &catalogInfo, 0L, 0L, 0L); if(status != noErr) { error(0, status, "Internal error: %s, %d", __FILE__, __LINE__); return; } fndrInfo = (FInfo *)catalogInfo.finderInfo; if(entry.fileCreator != 0) fndrInfo->fdCreator = entry.fileCreator; if(entry.fileType != 0) fndrInfo->fdType = entry.fileType; status = ::FSSetCatalogInfo(&outspec, kFSCatInfoFinderInfo, &catalogInfo); if(status != noErr) { error(0, status, "Internal error: %s, %d", __FILE__, __LINE__); } } unsigned char const mac_to_iso_maccvspro[256] = { 0, 1, 2, 3, 4, 5, 6, 7, /* 0 - 7 */ 8, 9, 10, 11, 12, 13, 14, 15, /* 8 - 15 */ 16, 17, 18, 19, 20, 21, 22, 23, /* 16 - 23 */ 24, 25, 26, 27, 28, 29, 30, 31, /* 24 - 31 */ 32, 33, 34, 35, 36, 37, 38, 39, /* 32 - 39 */ 40, 41, 42, 43, 44, 45, 46, 47, /* 40 - 47 */ 48, 49, 50, 51, 52, 53, 54, 55, /* 48 - 55 */ 56, 57, 58, 59, 60, 61, 62, 63, /* 56 - 63 */ 64, 65, 66, 67, 68, 69, 70, 71, /* 64 - 71 */ 72, 73, 74, 75, 76, 77, 78, 79, /* 72 - 79 */ 80, 81, 82, 83, 84, 85, 86, 87, /* 80 - 87 */ 88, 89, 90, 91, 92, 93, 94, 95, /* 88 - 95 */ 96, 97, 98, 99, 100, 101, 102, 103, /* 96 - 103 */ 104, 105, 106, 107, 108, 109, 110, 111, /* 104 - 111 */ 112, 113, 114, 115, 116, 117, 118, 119, /* 112 - 119 */ 120, 121, 122, 123, 124, 125, 126, 127, /* 120 - 127 */ 196, 197, 199, 201, 209, 214, 220, 225, /* 128 - 135 */ 224, 226, 228, 227, 229, 231, 233, 232, /* 136 - 143 */ 234, 235, 237, 236, 238, 239, 241, 243, /* 144 - 151 */ 242, 244, 246, 245, 250, 249, 251, 252, /* 152 - 159 */ 190, 176, 162, 163, 167, 130, 182, 223, /* 160 - 167 */ 174, 169, 142, 180, 168, 173, 198, 216, /* 168 - 175 */ 141, 177, 178, 179, 165, 181, 166, 135, /* 176 - 183 */ 159, 185, 188, 170, 186, 189, 230, 248, /* 184 - 191 */ 191, 161, 172, 146, 128, 129, 140, 171, /* 192 - 199 */ 187, 131, 160, 192, 195, 144, 145, 147, /* 200 - 207 */ 208, 132, 150, 148, 149, 213, 247, 215, /* 208 - 215 */ 255, 153, 152, 164, 134, 221, 222, 151, /* 216 - 223 */ 136, 183, 137, 139, 138, 194, 202, 193, /* 224 - 231 */ 203, 200, 205, 206, 207, 204, 211, 212, /* 232 - 239 */ 240, 210, 218, 219, 217, 155, 154, 133, /* 240 - 247 */ 175, 157, 156, 158, 184, 253, 254, 143, /* 248 - 255 */ }; /* Conversion table generated mechanically by Free `recode' 3.5 for sequence ISO-8859-1..macintosh (reversible). */ unsigned char const iso_to_mac_maccvspro[256] = { 0, 1, 2, 3, 4, 5, 6, 7, /* 0 - 7 */ 8, 9, 10, 11, 12, 13, 14, 15, /* 8 - 15 */ 16, 17, 18, 19, 20, 21, 22, 23, /* 16 - 23 */ 24, 25, 26, 27, 28, 29, 30, 31, /* 24 - 31 */ 32, 33, 34, 35, 36, 37, 38, 39, /* 32 - 39 */ 40, 41, 42, 43, 44, 45, 46, 47, /* 40 - 47 */ 48, 49, 50, 51, 52, 53, 54, 55, /* 48 - 55 */ 56, 57, 58, 59, 60, 61, 62, 63, /* 56 - 63 */ 64, 65, 66, 67, 68, 69, 70, 71, /* 64 - 71 */ 72, 73, 74, 75, 76, 77, 78, 79, /* 72 - 79 */ 80, 81, 82, 83, 84, 85, 86, 87, /* 80 - 87 */ 88, 89, 90, 91, 92, 93, 94, 95, /* 88 - 95 */ 96, 97, 98, 99, 100, 101, 102, 103, /* 96 - 103 */ 104, 105, 106, 107, 108, 109, 110, 111, /* 104 - 111 */ 112, 113, 114, 115, 116, 117, 118, 119, /* 112 - 119 */ 120, 121, 122, 123, 124, 125, 126, 127, /* 120 - 127 */ 196, 197, 165, 201, 209, 247, 220, 183, /* 128 - 135 */ 224, 226, 228, 227, 198, 176, 170, 255, /* 136 - 143 */ 205, 206, 195, 207, 211, 212, 210, 223, /* 144 - 151 */ 218, 217, 246, 245, 250, 249, 251, 184, /* 152 - 159 */ 202, 193, 162, 163, 219, 180, 182, 164, /* 160 - 167 */ 172, 169, 187, 199, 194, 173, 168, 248, /* 168 - 175 */ 161, 177, 178, 179, 171, 181, 166, 225, /* 176 - 183 */ 252, 185, 188, 200, 186, 189, 160, 192, /* 184 - 191 */ 203, 231, 229, 204, 128, 129, 174, 130, /* 192 - 199 */ 233, 131, 230, 232, 237, 234, 235, 236, /* 200 - 207 */ 208, 132, 241, 238, 239, 213, 133, 215, /* 208 - 215 */ 175, 244, 242, 243, 134, 221, 222, 167, /* 216 - 223 */ 136, 135, 137, 139, 138, 140, 190, 141, /* 224 - 231 */ 143, 142, 144, 145, 147, 146, 148, 149, /* 232 - 239 */ 240, 150, 152, 151, 153, 155, 154, 214, /* 240 - 247 */ 191, 157, 156, 158, 159, 253, 254, 216, /* 248 - 255 */ }; /* From Fetch. */ unsigned char const mac_to_iso[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1, 0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8, 0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3, 0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC, 0xDD, 0xB0, 0xA2, 0xA3, 0xA7, 0x80, 0xB6, 0xDF, 0xAE, 0xA9, 0x81, 0xB4, 0xA8, 0x82, 0xC6, 0xD8, 0x83, 0xB1, 0xBE, 0x84, 0xA5, 0xB5, 0x8F, 0x85, 0xBD, 0xBC, 0x86, 0xAA, 0xBA, 0x87, 0xE6, 0xF8, 0xBF, 0xA1, 0xAC, 0x88, 0x9F, 0x89, 0x90, 0xAB, 0xBB, 0x8A, 0xA0, 0xC0, 0xC3, 0xD5, 0x91, 0xA6, 0xAD, 0x8B, 0xB3, 0xB2, 0x8C, 0xB9, 0xF7, 0xD7, 0xFF, 0x8D, 0x8E, 0xA4, 0xD0, 0xF0, 0xDE, 0xFE, 0xFD, 0xB7, 0x92, 0x93, 0x94, 0xC2, 0xCA, 0xC1, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4, 0x95, 0xD2, 0xDA, 0xDB, 0xD9, 0x9E, 0x96, 0x97, 0xAF, 0x98, 0x99, 0x9A, 0xB8, 0x9B, 0x9C, 0x9D, }; unsigned char const iso_to_mac[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xA5, 0xAA, 0xAD, 0xB0, 0xB3, 0xB7, 0xBA, 0xBD, 0xC3, 0xC5, 0xC9, 0xD1, 0xD4, 0xD9, 0xDA, 0xB6, 0xC6, 0xCE, 0xE2, 0xE3, 0xE4, 0xF0, 0xF6, 0xF7, 0xF9, 0xFA, 0xFB, 0xFD, 0xFE, 0xFF, 0xF5, 0xC4, 0xCA, 0xC1, 0xA2, 0xA3, 0xDB, 0xB4, 0xCF, 0xA4, 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, 0xD0, 0xA8, 0xF8, 0xA1, 0xB1, 0xD3, 0xD2, 0xAB, 0xB5, 0xA6, 0xE1, 0xFC, 0xD5, 0xBC, 0xC8, 0xB9, 0xB8, 0xB2, 0xC0, 0xCB, 0xE7, 0xE5, 0xCC, 0x80, 0x81, 0xAE, 0x82, 0xE9, 0x83, 0xE6, 0xE8, 0xED, 0xEA, 0xEB, 0xEC, 0xDC, 0x84, 0xF1, 0xEE, 0xEF, 0xCD, 0x85, 0xD7, 0xAF, 0xF4, 0xF2, 0xF3, 0x86, 0xA0, 0xDE, 0xA7, 0x88, 0x87, 0x89, 0x8B, 0x8A, 0x8C, 0xBE, 0x8D, 0x8F, 0x8E, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, 0xDD, 0x96, 0x98, 0x97, 0x99, 0x9B, 0x9A, 0xD6, 0xBF, 0x9D, 0x9C, 0x9E, 0x9F, 0xE0, 0xDF, 0xD8 }; static const unsigned char *convert_iso(int convert_from, int iso) { if(iso != 1 && iso != 2) // only Latin 1 available right now return NULL; if(iso == 1) { return convert_from ? iso_to_mac : mac_to_iso; } else return convert_from ? iso_to_mac_maccvspro : mac_to_iso_maccvspro; } void mac_convert_file (const char *infile, int encode, char *outfile, int binary) { FILE *infd, *outfd; char buf[8192]; int len; int decode; /* 1 : server to client format, 0: client to server format */ # define ISO8559_VALID(iso) ((iso) == 1 || (iso) == 2) static int set_text_signature = -1; static int convert_iso8559 = -1; static int convert_maclf = -1; decode = encode ? 0 : 1; if(convert_iso8559 == -1) { const char *iso = CProtocolLibrary::GetEnvironment("ISO8859"); if(iso == NULL || sscanf(iso, "%d", &convert_iso8559) != 1 || !ISO8559_VALID(convert_iso8559)) convert_iso8559 = 0; } if(set_text_signature == -1) { set_text_signature = CProtocolLibrary::GetEnvironment("IC_ON_TXT") != NULL ? 1 : 0; } // create text files with the Mac CR (0x0D) // the default is LF on OSX if(convert_maclf == -1) { convert_maclf = CProtocolLibrary::GetEnvironment("CVS_MACLF") != NULL ? 1 : 0; } /* "update" doesn't check if we can erase the dest file */ chmod(outfile, S_IRWXU); if(convert_hqx_file(infile, encode, outfile, &binary)) return; const unsigned char *isotab = NULL; if(convert_iso8559) isotab = convert_iso(decode, convert_iso8559); if ((infd = fopen (infile, (binary || convert_maclf) ? "rb" : "r")) == NULL) error (1, errno, "cannot read %s", infile); if ((outfd = fopen (outfile, (binary || convert_maclf) ? "wb" : "w")) == NULL) error (1, errno, "cannot write %s", outfile); while ((len = fread (buf, sizeof (char), sizeof (buf) / sizeof(char), infd)) > 0) { // for a text file, we have some post process depending // if we encode for the server or decode from the server if(binary == 0) { char * conv = buf; int convlen = len; while (convlen--) { if(isotab != NULL) { *conv = (char)isotab[(unsigned char)*conv]; } // on OSX, we don't have MSL-stdio switching the CR <-> LF, // we can go straigth to the point if(convert_maclf) { if(decode) { // for a text file, this will turn the line feed // to the mac one if(*conv == 0x0a) *conv = 0x0d; } else { if(*conv == 0x0d) *conv = 0x0a; } } conv++; } } if (fwrite (buf, sizeof(char), len, outfd) < 0) error (1, errno, "error writing %s", outfile); } if (len < 0) error (1, errno, "error reading %s", infile); if (fclose (outfd) != 0) error (0, errno, "warning: cannot close %s", outfile); if (fclose (infd) != 0) error (0, errno, "warning: cannot close %s", infile); if((binary || set_text_signature) && decode) set_file_type(outfile, !quiet); } #endif /* __MACH__ */