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 | | |