| 759 | | else |
| 760 | | result = new (manager) XMLMacCarbonFile; |
| 761 | | |
| 762 | | return result; |
| 763 | | } |
| 764 | | |
| 765 | | |
| 766 | | bool |
| 767 | | XMLParsePathToFSRef(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager) |
| 768 | | { |
| 769 | | bool result; |
| 770 | | |
| 771 | | // If FSPathMakeRef is available, we use it to parse the |
| 772 | | // path: this gives us "standard" path support under MacOS X. |
| 773 | | // Without this, our paths in that environment would always |
| 774 | | // have a volume name at their root...which would look |
| 775 | | // "normal" to Mac users, but not normal to unix users. Since |
| 776 | | // we're making "unix" paths, we'll stick with the unix |
| 777 | | // style paths. This also allows us to easilly take paths |
| 778 | | // off the command line. |
| 779 | | // |
| 780 | | // FSPathMakeRef is available on Mac OS X and in CarbonLib 1.1 |
| 781 | | // and greater. But on classic under CarbonLib, it expects paths |
| 782 | | // to contain ':' separators, for which we're not prepared. Since |
| 783 | | // this isn't a case where we need to use it, we drop back to the |
| 784 | | // classic case for this. |
| 785 | | |
| 786 | | if (TARGET_API_MAC_CARBON && gHasFSPathAPIs && gPathAPIsUsePosixPaths) |
| 787 | | result = XMLParsePathToFSRef_X(pathName, ref, manager); |
| 788 | | else |
| 789 | | result = XMLParsePathToFSRef_Classic(pathName, ref, manager); |
| 790 | | |
| 791 | | return result; |
| 792 | | } |
| 793 | | |
| 794 | | |
| 795 | | bool |
| 796 | | XMLParsePathToFSRef_X(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager) |
| 797 | | { |
| 798 | | // Parse Path to FSRef using FSPathMakeRef as available under |
| 799 | | // Mac OS X and CarbonLib 1.1 and greater. |
| 800 | | |
| 801 | | OSStatus err = noErr; |
| 802 | | std::size_t pathLen = XMLString::stringLen(pathName); |
| 803 | | |
| 804 | | // Transcode XMLCh into UniChar |
| 805 | | UniChar uniBuf[kMaxMacStaticPathChars]; |
| 806 | | CopyXMLChsToUniChars(pathName, uniBuf, pathLen, kMaxMacStaticPathChars); |
| 807 | | |
| 808 | | // Transcode Unicode to UTF-8 |
| 809 | | char utf8Buf[kMaxMacStaticPathChars]; |
| 810 | | pathLen = TranscodeUniCharsToUTF8(uniBuf, utf8Buf, pathLen, kMaxMacStaticPathChars-1); |
| 811 | | |
| 812 | | // Terminate the path |
| 813 | | char* p = utf8Buf; |
| 814 | | p[pathLen++] = '\0'; |
| 815 | | |
| 816 | | // If it's a relative path, pre-pend the current directory to the path. |
| 817 | | // FSPathMakeRef doesn't deal with relativity on the front of the path |
| 818 | | if (*p != '/' && kMaxMacStaticPathChars > pathLen) |
| 819 | | { |
| 820 | | // Right justify the user path to make room for the pre-pended path |
| 821 | | std::memmove(p + kMaxMacStaticPathChars - pathLen, p, pathLen); |
| 822 | | *p = '\0'; |
| 823 | | |
| 824 | | // Get the current directory |
| 825 | | if (gUseGETCWD) |
| 826 | | { |
| 827 | | // Get current directory path, leaving room for one '/' after |
| 828 | | if (err == noErr) |
| 829 | | getcwd(p, kMaxMacStaticPathChars - pathLen - 1); |
| 830 | | } |
| 831 | | else |
| 832 | | { |
| 833 | | // Get current directory path, leaving room for one '/' after |
| 834 | | |
| 835 | | // We quiz the carbon file manager for the current directory. |
| 836 | | // Note that carbon defaults its concept of the current directory |
| 837 | | // to the location of the executable. |
| 838 | | FSSpec spec; |
| 839 | | if (err == noErr) |
| 840 | | err = FSMakeFSSpec(0, 0, NULL, &spec); |
| 841 | | if (err == noErr) |
| 842 | | err = FSpMakeFSRef(&spec, &ref); |
| 843 | | |
| 844 | | // Get current directory path, leaving room for one '/' after |
| 845 | | if (err == noErr) |
| 846 | | err = FSRefMakePath(&ref, reinterpret_cast<UInt8*>(p), kMaxMacStaticPathChars - pathLen - 1); |
| 847 | | } |
| 848 | | |
| 849 | | // Now munge the two paths back together |
| 850 | | std::size_t prefixLen = std::strlen(p); |
| 851 | | p[prefixLen++] = '/'; |
| 852 | | std::memmove(p + prefixLen, p + kMaxMacStaticPathChars - pathLen, pathLen); |
| 853 | | |
| 854 | | // We now have a path from an absolute starting point |
| 855 | | } |
| 856 | | |
| 857 | | // Let the OS discover the location |
| 858 | | Boolean isDirectory = false; |
| 859 | | if (err == noErr) |
| 860 | | err = FSPathMakeRef(reinterpret_cast<UInt8*>(p), &ref, &isDirectory); |
| 861 | | |
| 862 | | // Return true on success |
| 863 | | return (err == noErr); |
| 864 | | } |
| 865 | | |
| 866 | | |
| 867 | | bool |
| 868 | | XMLParsePathToFSRef_Classic(const XMLCh* const pathName, FSRef& ref, MemoryManager* const manager) |
| 869 | | { |
| 870 | | // Parse Path to FSRef by stepping manually through path components. |
| 871 | | |
| 872 | | // Path's parsed in this way must always begin with a volume name. |
| 873 | | // This assumption would fail for standard unix paths under Mac OS X, |
| 874 | | // so for those cases we use the routine XMLParsePathToFSRef_Carbon |
| 875 | | // above. |
| 876 | | |
| 877 | | const XMLCh* p = pathName; |
| 878 | | const XMLCh* pEnd; |
| 879 | | std::size_t segLen; |
| 880 | | |
| 881 | | const std::size_t kXMLBufCount = 256; |
| 882 | | XMLCh xmlBuf[kXMLBufCount]; |
| 883 | | |
| 884 | | OSErr err = noErr; |
| 885 | | |
| 886 | | if (*p == L'/') |
| 887 | | { |
| 888 | | // Absolute name: grab the first component as volume name |
| 889 | | |
| 890 | | // Find the end of the path segment |
| 891 | | for (pEnd = ++p; *pEnd && *pEnd != L'/'; ++pEnd) ; |
| 892 | | segLen = pEnd - p; |
| 893 | | |
| 894 | | // Try to find a volume that matches this name |
| 895 | | for (ItemCount volIndex = 1; err == noErr; ++volIndex) |
| 896 | | { |
| 897 | | HFSUniStr255 hfsStr; |
| 898 | | hfsStr.length = 0; |
| 899 | | |
| 900 | | // Get the volume name |
| 901 | | err = FSGetVolumeInfo( |
| 902 | | 0, |
| 903 | | volIndex, |
| 904 | | static_cast<FSVolumeRefNum*>(NULL), |
| 905 | | 0, |
| 906 | | static_cast<FSVolumeInfo*>(NULL), |
| 907 | | &hfsStr, |
| 908 | | &ref |
| 909 | | ); |
| 910 | | |
| 911 | | // Compare against our path segment |
| 912 | | if (err == noErr && segLen == hfsStr.length) |
| 913 | | { |
| 914 | | // Case-insensitive compare |
| 915 | | if (XMLString::compareNIString( |
| 916 | | ConvertSlashToColon( |
| 917 | | CopyUniCharsToXMLChs(hfsStr.unicode, xmlBuf, segLen, kXMLBufCount), |
| 918 | | segLen), |
| 919 | | p, segLen) == 0) |
| 920 | | break; // we found our volume |
| 921 | | } |
| 922 | | } |
| 923 | | |
| 924 | | p = pEnd; |
| 925 | | } |
| 926 | | else |
| 927 | | { |
| 928 | | // Relative name, so get the default directory as parent ref |
| 929 | | FSSpec spec; |
| 930 | | err = FSMakeFSSpec(0, 0, NULL, &spec); |
| 931 | | if (err == noErr) |
| 932 | | err = FSpMakeFSRef(&spec, &ref); |
| 933 | | } |
| 934 | | |
| 935 | | // ref now refers to the parent directory: parse the rest of the path |
| 936 | | while (err == noErr && *p) |
| 937 | | { |
| 938 | | switch (*p) |
| 939 | | { |
| 940 | | case L'/': // Just skip any number of path separators |
| 941 | | ++p; |
| 942 | | break; |
| 943 | | |
| 944 | | case L'.': // Potentially "current directory" or "parent directory" |
| 945 | | if (p[1] == L'/' || p[1] == 0) // "current directory" |
| 946 | | { |
| 947 | | ++p; |
| 948 | | break; |
| 949 | | } |
| 950 | | else if (p[1] == L'.' && (p[2] == L'/' || p[2] == 0)) // "parent directory" |
| 951 | | { |
| 952 | | p += 2; // Get the parent of our parent |
| 953 | | |
| 954 | | FSCatalogInfo catalogInfo; |
| 955 | | err = FSGetCatalogInfo( |
| 956 | | &ref, |
| 957 | | kFSCatInfoParentDirID, |
| 958 | | &catalogInfo, |
| 959 | | static_cast<HFSUniStr255*>(NULL), |
| 960 | | static_cast<FSSpec*>(NULL), |
| 961 | | &ref |
| 962 | | ); |
| 963 | | |
| 964 | | // Check that we didn't go too far |
| 965 | | if (err != noErr || catalogInfo.parentDirID == fsRtParID) |
| 966 | | return false; |
| 967 | | |
| 968 | | break; |
| 969 | | } |
| 970 | | else // some other sequence of periods...fall through and treat as segment |
| 971 | | ; |
| 972 | | |
| 973 | | default: |
| 974 | | // Find the end of the path segment |
| 975 | | for (pEnd = p; *pEnd && *pEnd != L'/'; ++pEnd) ; |
| 976 | | segLen = pEnd - p; |
| 977 | | |
| 978 | | // pEnd now points either to '/' or NUL |
| 979 | | // Create a new ref using this path segment |
| 980 | | err = FSMakeFSRefUnicode( |
| 981 | | &ref, |
| 982 | | segLen, |
| 983 | | ConvertColonToSlash( |
| 984 | | CopyXMLChsToUniChars(p, reinterpret_cast<UniChar*>(xmlBuf), segLen, kXMLBufCount), |
| 985 | | segLen), |
| 986 | | kTextEncodingUnknown, |
| 987 | | &ref |
| 988 | | ); |
| 989 | | |
| 990 | | p = pEnd; |
| 991 | | break; |
| 992 | | } |
| 993 | | } |
| 994 | | |
| 995 | | return err == noErr; |
| 996 | | } |
| 997 | | |
| 998 | | |
| 999 | | bool |
| 1000 | | XMLParsePathToFSSpec(const XMLCh* const pathName, FSSpec& spec, |
| 1001 | | MemoryManager* const manager) |
| 1002 | | { |
| 1003 | | // Parse Path to an FSSpec |
| 1004 | | |
| 1005 | | // If we've got HFS+ APIs, do this in terms of refs so that |
| 1006 | | // we can grandfather in the use of FSPathMakeRef under Mac OS X |
| 1007 | | // and CarbonLib 1.1. Otherwise, do it the hard way. |
| 1008 | | |
| 1009 | | bool result = false; |
| 1010 | | |
| 1011 | | if (gHasHFSPlusAPIs) |
| 1012 | | { |
| 1013 | | // Parse to a ref |
| 1014 | | FSRef ref; |
| 1015 | | result = XMLParsePathToFSRef(pathName, ref, manager); |
| 1035 | | bool |
| 1036 | | XMLParsePathToFSSpec_Classic(const XMLCh* const pathName, FSSpec& spec, |
| 1037 | | MemoryManager* const manager) |
| 1038 | | { |
| 1039 | | // Manually parse the path using FSSpec APIs. |
| 1040 | | |
| 1041 | | // Transcode the path into ascii |
| 1042 | | const char* p = XMLString::transcode(pathName, manager); |
| 1043 | | ArrayJanitor<const char> janPath(p, manager); |
| 1044 | | const char* pEnd; |
| 1045 | | std::size_t segLen; |
| 1046 | | |
| 1047 | | OSStatus err = noErr; |
| 1048 | | Str255 name; // Must be long enough for a partial pathname consisting of two segments (64 bytes) |
| 1049 | | |
| 1050 | | if (*p == '/') |
| 1051 | | { |
| 1052 | | // Absolute name: grab the first component as volume name |
| 1053 | | |
| 1054 | | // Find the end of the path segment |
| 1055 | | for (pEnd = ++p; *pEnd && *pEnd != '/'; ++pEnd) ; |
| 1056 | | segLen = pEnd - p; |
| 1057 | | |
| 1058 | | // Try to find a volume that matches this name |
| 1059 | | for (ItemCount volIndex = 1; err == noErr; ++volIndex) |
| 1060 | | { |
| 1061 | | FSVolumeRefNum volRefNum; |
| 1062 | | |
| 1063 | | if (gHasFS2TBAPIs) |
| 1064 | | { |
| 1065 | | XVolumeParam xVolParam; |
| 1066 | | name[0] = 0; |
| 1067 | | xVolParam.ioNamePtr = name; |
| 1068 | | xVolParam.ioVRefNum = 0; |
| 1069 | | xVolParam.ioXVersion = 0; |
| 1070 | | xVolParam.ioVolIndex = volIndex; |
| 1071 | | err = PBXGetVolInfoSync(&xVolParam); |
| 1072 | | volRefNum = xVolParam.ioVRefNum; |
| 1073 | | } |
| 1074 | | else |
| 1075 | | { |
| 1076 | | #if !TARGET_API_MAC_CARBON |
| 1077 | | HParamBlockRec hfsParams; |
| 1078 | | name[0] = 0; |
| 1079 | | hfsParams.volumeParam.ioNamePtr = name; |
| 1080 | | hfsParams.volumeParam.ioVRefNum = 0; |
| 1081 | | hfsParams.volumeParam.ioVolIndex = volIndex; |
| 1082 | | err = PBHGetVInfoSync(&hfsParams); |
| 1083 | | volRefNum = hfsParams.volumeParam.ioVRefNum; |
| 1084 | | #else |
| 1085 | | err = nsvErr; |
| 1086 | | #endif |
| 1087 | | } |
| 1088 | | |
| 1089 | | // Compare against our path segment |
| 1090 | | if (err == noErr && segLen == StrLength(name)) |
| 1091 | | { |
| 1092 | | // Case-insensitive compare |
| 1093 | | if (XMLString::compareNIString( |
| 1094 | | ConvertSlashToColon(reinterpret_cast<char*>(&name[1]), segLen), |
| 1095 | | p, segLen) == 0) |
| 1096 | | { |
| 1097 | | // we found our volume: fill in the spec |
| 1098 | | err = FSMakeFSSpec(volRefNum, fsRtDirID, NULL, &spec); |
| 1099 | | break; |
| 1100 | | } |
| 1101 | | } |
| 1102 | | } |
| 1103 | | |
| 1104 | | p = pEnd; |
| 1105 | | } |
| 1106 | | else |
| 1107 | | { |
| 1108 | | // Relative name, so get the default directory as parent spec |
| 1109 | | err = FSMakeFSSpec(0, 0, NULL, &spec); |
| 1110 | | } |
| 1111 | | |
| 1112 | | // We now have a parent directory in the spec. |
| 1113 | | while (err == noErr && *p) |
| 1114 | | { |
| 1115 | | switch (*p) |
| 1116 | | { |
| 1117 | | case '/': // Just skip any number of path separators |
| 1118 | | ++p; |
| 1119 | | break; |
| 1120 | | |
| 1121 | | case L'.': // Potentially "current directory" or "parent directory" |
| 1122 | | if (p[1] == '/' || p[1] == 0) // "current directory" |
| 1123 | | { |
| 1124 | | ++p; |
| 1125 | | break; |
| 1126 | | } |
| 1127 | | else if (p[1] == '.' && (p[2] == '/' || p[2] == 0)) // "parent directory" |
| 1128 | | { |
| 1129 | | p += 2; // Get the parent of our parent |
| 1130 | | |
| 1131 | | CInfoPBRec catInfo; |
| 1132 | | catInfo.dirInfo.ioNamePtr = NULL; |
| 1133 | | catInfo.dirInfo.ioVRefNum = spec.vRefNum; |
| 1134 | | catInfo.dirInfo.ioFDirIndex = -1; |
| 1135 | | catInfo.dirInfo.ioDrDirID = spec.parID; |
| 1136 | | err = PBGetCatInfoSync(&catInfo); |
| 1137 | | |
| 1138 | | // Check that we didn't go too far |
| 1139 | | if (err != noErr || catInfo.dirInfo.ioDrParID == fsRtParID) |
| 1140 | | return false; |
| 1141 | | |
| 1142 | | // Update our spec |
| 1143 | | if (err == noErr) |
| 1144 | | err = FSMakeFSSpec(spec.vRefNum, catInfo.dirInfo.ioDrDirID, NULL, &spec); |
| 1145 | | |
| 1146 | | break; |
| 1147 | | } |
| 1148 | | else // some other sequence of periods...fall through and treat as segment |
| 1149 | | ; |
| 1150 | | |
| 1151 | | default: |
| 1152 | | { |
| 1153 | | // Find the end of the path segment |
| 1154 | | for (pEnd = p; *pEnd && *pEnd != '/'; ++pEnd) ; |
| 1155 | | segLen = pEnd - p; |
| 1156 | | |
| 1157 | | // Check for name length overflow |
| 1158 | | if (segLen > 31) |
| 1159 | | return false; |
| 1160 | | |
| 1161 | | // Make a partial pathname from our current spec to the new object |
| 1162 | | unsigned char* partial = &name[1]; |
| 1163 | | |
| 1164 | | *partial++ = ':'; // Partial leads with : |
| 1165 | | const unsigned char* specName = spec.name; // Copy in spec name |
| 1166 | | for (int specCnt = *specName++; specCnt > 0; --specCnt) |
| 1167 | | *partial++ = *specName++; |
| 1168 | | |
| 1169 | | *partial++ = ':'; // Separator |
| 1170 | | while (p != pEnd) // Copy in new element |
| 1171 | | { |
| 1172 | | if (*p == ':') // Convert : to / |
| 1173 | | { |
| 1174 | | *partial++ = '/'; |
| 1175 | | p++; |
| 1176 | | } |
| 1177 | | else |
| 1178 | | *partial++ = *p++; |
| 1179 | | } |
| 1180 | | |
| 1181 | | name[0] = partial - &name[1]; // Set the name length |
| 1182 | | |
| 1183 | | // Update the spec |
| 1184 | | err = FSMakeFSSpec(spec.vRefNum, spec.parID, name, &spec); |
| 1185 | | } |
| 1186 | | break; |
| 1187 | | } |
| 1188 | | } |
| 1189 | | |
| 1190 | | return err == noErr; |
| 1191 | | } |
| 1192 | | |
| 1193 | | |
| 1194 | | XMLCh* |
| 1195 | | XMLCreateFullPathFromFSRef(const FSRef& startingRef, |
| 1196 | | MemoryManager* const manager) |
| 1197 | | { |
| 1198 | | XMLCh* result = NULL; |
| 1199 | | |
| 1200 | | // If FSRefMakePath is available, we use it to create the |
| 1201 | | // path: this gives us "standard" path support under MacOS X. |
| 1202 | | // Without this, our paths in that environment would always |
| 1203 | | // have a volume name at their root...which would look |
| 1204 | | // "normal" to Mac users, but not normal to unix users. Since |
| 1205 | | // we're making "unix" paths, we'll stick with the unix |
| 1206 | | // style paths. This also allows us to easilly take paths |
| 1207 | | // off the command line. |
| 1208 | | // |
| 1209 | | // FSRefMakePath is available on Mac OS X and in CarbonLib 1.1 |
| 1210 | | // and greater. But we use it only on X since on Classic it |
| 1211 | | // makes paths with ':' separators, which really confuses us! |
| 1212 | | |
| 1213 | | if (TARGET_API_MAC_CARBON && gHasFSPathAPIs && gPathAPIsUsePosixPaths) |
| 1214 | | result = XMLCreateFullPathFromFSRef_X(startingRef, manager); |
| 1215 | | else |
| 1216 | | result = XMLCreateFullPathFromFSRef_Classic(startingRef, manager); |
| 1217 | | |
| 1218 | | return result; |
| 1219 | | } |
| 1220 | | |
| 1221 | | |
| 1222 | | XMLCh* |
| 1223 | | XMLCreateFullPathFromFSRef_X(const FSRef& startingRef, |
| 1224 | | MemoryManager* const manager) |
| 1225 | | { |
| 1226 | | // Create the path using FSRefMakePath as available on Mac OS X |
| 1227 | | // and under CarbonLib 1.1 and greater. |
| 1228 | | OSStatus err = noErr; |
| 1229 | | |
| 1230 | | // Make the path in utf8 form |
| 1231 | | char utf8Buf[kMaxMacStaticPathChars]; |
| 1232 | | utf8Buf[0] = '\0'; |
| 1233 | | |
| 1234 | | if (err == noErr) |
| 1235 | | err = FSRefMakePath(&startingRef, reinterpret_cast<UInt8*>(utf8Buf), kMaxMacStaticPathChars); |
| 1236 | | |
| 1237 | | // Bail if path conversion failed |
| 1238 | | if (err != noErr) |
| 1239 | | return NULL; |
| 1240 | | |
| 1241 | | // Transcode into UniChars |
| 1242 | | UniChar uniBuf[kMaxMacStaticPathChars]; |
| 1243 | | std::size_t pathLen = TranscodeUTF8ToUniChars(utf8Buf, uniBuf, kMaxMacStaticPathChars-1); |
| 1244 | | uniBuf[pathLen++] = 0; |
| 1245 | | |
| 1246 | | // Transcode into a dynamically allocated buffer of XMLChs |
| 1247 | | ArrayJanitor<XMLCh> result((XMLCh*) manager->allocate(pathLen * sizeof(XMLCh))/*new XMLCh[pathLen]*/, |
| 1248 | | manager); |
| 1249 | | if (result.get() != NULL) |
| 1250 | | CopyUniCharsToXMLChs(uniBuf, result.get(), pathLen, pathLen); |
| 1251 | | |
| 1252 | | return result.release(); |
| 1253 | | } |
| 1254 | | |
| 1255 | | |
| 1256 | | XMLCh* |
| 1257 | | XMLCreateFullPathFromFSRef_Classic(const FSRef& startingRef, |
| 1258 | | MemoryManager* const manager) |
| 1259 | | { |
| 1260 | | // Manually create the path using FSRef APIs. |
| 1261 | | OSStatus err = noErr; |
| 1262 | | FSCatalogInfo catalogInfo; |
| 1263 | | HFSUniStr255 name; |
| 1264 | | FSRef ref = startingRef; |
| 1265 | | |
| 1266 | | XMLCh buf[kMaxMacStaticPathChars]; |
| 1267 | | std::size_t bufPos = kMaxMacStaticPathChars; |
| 1268 | | std::size_t bufCnt = 0; |
| 1269 | | |
| 1270 | | ArrayJanitor<XMLCh> result(NULL); |
| 1271 | | std::size_t resultLen = 0; |
| 1272 | | |
| 1273 | | buf[--bufPos] = L'\0'; |
| 1274 | | ++bufCnt; |
| 1275 | | |
| 1276 | | do |
| 1277 | | { |
| 1278 | | err = FSGetCatalogInfo( |
| 1279 | | &ref, |
| 1280 | | kFSCatInfoParentDirID, |
| 1281 | | &catalogInfo, |
| 1282 | | &name, |
| 1283 | | static_cast<FSSpec*>(NULL), |
| 1284 | | &ref |
| 1285 | | ); |
| 1286 | | |
| 1287 | | if (err == noErr) |
| 1288 | | { |
| 1289 | | // If there's not room in our static buffer for the new |
| 1290 | | // name plus separator, dump it to the dynamic result buffer. |
| 1291 | | if (bufPos < (std::size_t)name.length + 1) |
| 1292 | | { |
| 1293 | | ArrayJanitor<XMLCh> temp |
| 1294 | | ( |
| 1295 | | (XMLCh*) manager->allocate((bufCnt + resultLen) * sizeof(XMLCh)) //new XMLCh[bufCnt + resultLen] |
| 1296 | | , manager |
| 1297 | | ); |
| 1298 | | |
| 1299 | | // Copy in the static buffer |
| 1300 | | std::memcpy(temp.get(), &buf[bufPos], bufCnt * sizeof(XMLCh)); |
| 1301 | | |
| 1302 | | // Copy in the old buffer |
| 1303 | | if (resultLen > 0) |
| 1304 | | std::memcpy(temp.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh)); |
| 1305 | | |
| 1306 | | result.reset(temp.release()); |
| 1307 | | resultLen += bufCnt; |
| 1308 | | |
| 1309 | | bufPos = kMaxMacStaticPathChars; |
| 1310 | | bufCnt = 0; |
| 1311 | | } |
| 1312 | | |
| 1313 | | // Prepend our new name and a '/' |
| 1314 | | bufPos -= name.length; |
| 1315 | | ConvertSlashToColon( |
| 1316 | | CopyUniCharsToXMLChs(name.unicode, &buf[bufPos], name.length, name.length), |
| 1317 | | name.length); |
| 1318 | | buf[--bufPos] = L'/'; |
| 1319 | | bufCnt += (name.length + 1); |
| 1320 | | } |
| 1321 | | } |
| 1322 | | while (err == noErr && catalogInfo.parentDirID != fsRtParID); |
| 1323 | | |
| 1324 | | // Composite existing buffer + any previous result buffer |
| 1325 | | ArrayJanitor<XMLCh> final |
| 1326 | | ( |
| 1327 | | (XMLCh*) manager->allocate((bufCnt + resultLen) * sizeof(XMLCh))//new XMLCh[bufCnt + resultLen] |
| 1328 | | , manager |
| 1329 | | ); |
| 1330 | | |
| 1331 | | // Copy in the static buffer |
| 1332 | | std::memcpy(final.get(), &buf[bufPos], bufCnt * sizeof(XMLCh)); |
| 1333 | | |
| 1334 | | // Copy in the old buffer |
| 1335 | | if (resultLen > 0) |
| 1336 | | std::memcpy(final.get() + bufCnt, result.get(), resultLen * sizeof(XMLCh)); |
| 1337 | | |
| 1338 | | return final.release(); |
| 1339 | | } |
| 1340 | | |
| 1341 | | |
| 1342 | | XMLCh* |
| 1343 | | XMLCreateFullPathFromFSSpec(const FSSpec& startingSpec, |
| 1344 | | MemoryManager* const manager) |
| 1345 | | { |
| 1346 | | XMLCh* result = NULL; |
| 1347 | | |
| 1348 | | // If FSRefs are available, do this operation in terms of refs...this |
| 1349 | | // allows us to grandfather in the use of FSPathMakeRef and FSRefMakePath |
| 1350 | | // if possible. |
| 1351 | | if (gHasHFSPlusAPIs) |
| 1352 | | { |
| 1353 | | OSStatus err = noErr; |
| 1354 | | FSRef ref; |
| 1355 | | |
| 1356 | | // Up convert to FSRef |
| 1357 | | if (err == noErr) |
| 1358 | | err = FSpMakeFSRef(&startingSpec, &ref); |
| 1359 | | |
| 1360 | | // Create the path |
| 1361 | | if (err == noErr) |
| 1362 | | result = XMLCreateFullPathFromFSRef(ref, manager); |
| 1363 | | } |
| 1364 | | else |
| 1365 | | { |
| 1366 | | // Create using FSSpecs only |
| 1367 | | result = XMLCreateFullPathFromFSSpec_Classic(startingSpec, manager); |
| 1368 | | } |
| 1369 | | |
| 1370 | | return result; |
| 1371 | | } |
| 1372 | | |
| 1373 | | |
| 1374 | | XMLCh* |
| 1375 | | XMLCreateFullPathFromFSSpec_Classic(const FSSpec& startingSpec, |
| 1376 | | MemoryManager* const manager) |
| 1377 | | { |
| 1378 | | // Manually create the path using FSSpec APIs. |
| 1379 | | OSStatus err = noErr; |
| 1380 | | FSSpec spec = startingSpec; |
| 1381 | | |
| 1382 | | char buf[kMaxMacStaticPathChars]; |
| 1383 | | std::size_t bufPos = kMaxMacStaticPathChars; |
| 1384 | | std::size_t bufCnt = 0; |
| 1385 | | |
| 1386 | | ArrayJanitor<char> result(NULL); |
| 1387 | | std::size_t resultLen = 0; |
| 1388 | | |
| 1389 | | buf[--bufPos] = '\0'; |
| 1390 | | ++bufCnt; |
| 1391 | | |
| 1392 | | short index = 0; |
| 1393 | | do |
| 1394 | | { |
| 1395 | | CInfoPBRec catInfo; |
| 1396 | | catInfo.dirInfo.ioNamePtr = spec.name; |
| 1397 | | catInfo.dirInfo.ioVRefNum = spec.vRefNum; |
| 1398 | | catInfo.dirInfo.ioFDirIndex = index; |
| 1399 | | catInfo.dirInfo.ioDrDirID = spec.parID; |
| 1400 | | err = PBGetCatInfoSync(&catInfo); |
| 1401 | | |
| 1402 | | if (err == noErr) |
| 1403 | | { |
| 1404 | | std::size_t nameLen = StrLength(spec.name); |
| 1405 | | |
| 1406 | | // If there's not room in our static buffer for the new |
| 1407 | | // name plus separator, dump it to the dynamic result buffer. |
| 1408 | | if (bufPos < nameLen + 1) |
| 1409 | | { |
| 1410 | | ArrayJanitor<char> temp |
| 1411 | | ( |
| 1412 | | (char*) manager->allocate((bufCnt + resultLen) * sizeof(char))//new char[bufCnt + resultLen] |
| 1413 | | , manager |
| 1414 | | ); |
| 1415 | | |
| 1416 | | // Copy in the static buffer |
| 1417 | | std::memcpy(temp.get(), &buf[bufPos], bufCnt); |
| 1418 | | |
| 1419 | | // Copy in the old buffer |
| 1420 | | if (resultLen > 0) |
| 1421 | | std::memcpy(temp.get() + bufCnt, result.get(), resultLen); |
| 1422 | | |
| 1423 | | result.reset(temp.release()); |
| 1424 | | resultLen += bufCnt; |
| 1425 | | |
| 1426 | | bufPos = kMaxMacStaticPathChars; |
| 1427 | | bufCnt = 0; |
| 1428 | | } |
| 1429 | | |
| 1430 | | // Prepend our new name and a '/' |
| 1431 | | bufPos -= nameLen; |
| 1432 | | ConvertSlashToColon((char*)std::memcpy(&buf[bufPos], &spec.name[1], nameLen), nameLen); |
| 1433 | | buf[--bufPos] = '/'; |
| 1434 | | bufCnt += (nameLen + 1); |
| 1435 | | |
| 1436 | | // From here on out, ignore the input file name |
| 1437 | | index = -1; |
| 1438 | | |
| 1439 | | // Move up to the parent |
| 1440 | | spec.parID = catInfo.dirInfo.ioDrParID; |
| 1441 | | } |
| 1442 | | } |
| 1443 | | while (err == noErr && spec.parID != fsRtParID); |
| 1444 | | |
| 1445 | | // Composite existing buffer with any previous result buffer |
| 1446 | | ArrayJanitor<char> final |
| 1447 | | ( |
| 1448 | | (char*) manager->allocate((bufCnt + resultLen) * sizeof(char))//new char[bufCnt + resultLen] |
| 1449 | | , manager |
| 1450 | | ); |
| 1451 | | |
| 1452 | | // Copy in the static buffer |
| 1453 | | std::memcpy(final.get(), &buf[bufPos], bufCnt); |
| 1454 | | |
| 1455 | | // Copy in the old buffer |
| 1456 | | if (resultLen > 0) |
| 1457 | | std::memcpy(final.get() + bufCnt, result.get(), resultLen); |
| 1458 | | |
| 1459 | | // Cleanup and transcode to unicode |
| 1460 | | return XMLString::transcode(final.get(), manager); |
| 1461 | | } |
| 1462 | | |