this repo has no description
at fixPythonPipStalling 586 lines 19 kB view raw
1#include "ResourceFile.h" 2#include "BinaryIO.h" 3 4#include <boost/filesystem.hpp> 5#include "boost/filesystem/fstream.hpp" 6#include <sstream> 7#include <iostream> 8 9#ifdef __APPLE__ 10#include <sys/xattr.h> 11#endif 12extern "C" { 13#include "hfs.h" 14} 15 16namespace fs = boost::filesystem; 17 18// CRC 16 table lookup array 19static unsigned short CRC16Table[256] = 20 {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 21 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 22 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 23 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 24 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 25 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 26 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 27 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 28 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 29 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 30 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 31 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 32 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 33 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 34 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 35 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 36 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 37 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 38 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 39 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 40 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 41 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 42 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 43 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 44 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 45 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 46 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 47 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 48 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 49 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 50 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 51 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; 52 53// CalculateCRC 54static unsigned short CalculateCRC(unsigned short CRC, const char* dataBlock, int dataSize) 55{ 56 while (dataSize) 57 { 58 CRC = (CRC << 8) ^ CRC16Table[((*dataBlock) ^ (CRC >> 8)) & 0x00FF]; 59 dataBlock++; 60 dataSize--; 61 } 62 63 return CRC; 64} 65 66static void writeMacBinary(std::ostream& out, std::string filename, 67 ResType type, ResType creator, 68 const Resources& rsrc, const std::string& data) 69{ 70 71 std::ostringstream resstream; 72 rsrc.writeFork(resstream); 73 74 const std::string& rsrcBytes = resstream.str(); 75 76 77 std::ostringstream header; 78 byte(header, 0); 79 byte(header, filename.size()); 80 header << filename; 81 while((int)header.tellp() < 65) 82 byte(header,0); 83 ostype(header, type); 84 ostype(header, creator); 85 byte(header, 0); // flags 86 byte(header, 0); 87 word(header, 0); // position.v 88 word(header, 0); // position.h 89 word(header, 0); // folder id 90 byte(header, 0); // protected flag 91 byte(header, 0); 92 longword(header, (int)data.size()); 93 longword(header, (int)rsrcBytes.size()); 94 longword(header, 0); // creation date 95 longword(header, 0); // modification date 96 while((int)header.tellp() < 124) 97 byte(header,0); 98 std::string headerData = header.str(); 99 out << headerData; 100 word(out, CalculateCRC(0, &headerData[0], headerData.size())); 101 word(out, 0); 102 out << data; 103 while((int)out.tellp() % 128) 104 byte(out,0); 105 rsrc.writeFork(out); 106 while((int)out.tellp() % 128) 107 byte(out,0); 108} 109 110bool ResourceFile::read(std::string path, Format f) 111{ 112 if(!assign(path, f)) 113 return false; 114 return read(); 115} 116 117bool ResourceFile::write(std::string path, Format f) 118{ 119 if(!assign(path, f)) 120 return false; 121 return write(); 122} 123 124static bool CheckAppleDouble(fs::path path, std::string prefix) 125{ 126 fs::path adPath = path.parent_path() / (prefix + path.filename().string()); 127 fs::ifstream in(adPath); 128 if(in) 129 { 130 int magic1 = longword(in); 131 132 if(in && magic1 == 0x00051607) 133 { 134 int magic2 = longword(in); 135 if(in && magic2 == 0x00020000) 136 return true; 137 } 138 } 139 return false; 140} 141 142bool ResourceFile::assign(std::string pathstring, ResourceFile::Format f) 143{ 144 this->pathstring = pathstring; 145 fs::path path(pathstring); 146 147 this->filename = path.stem().string(); 148 fs::path rsrcPath = path.parent_path() / ".rsrc" / path.filename(); 149 fs::path finfPath = path.parent_path() / ".finf" / path.filename(); 150 151 format = f; 152 if(format == Format::autodetect) 153 { 154 if(path.extension() == ".bin") 155 format = Format::macbin; 156 else if(path.extension() == ".as") 157 format = Format::applesingle; 158 else if(path.extension() == ".dsk") 159 format = Format::diskimage; 160 else if(path.filename().string().substr(0,2) == "._") 161 { 162 path = path.parent_path() / path.filename().string().substr(2); 163 format = Format::underscore_appledouble; 164 this->pathstring = path.string(); 165 } 166 else if(path.filename().string()[0] == '%') 167 { 168 path = path.parent_path() / path.filename().string().substr(1); 169 format = Format::percent_appledouble; 170 this->pathstring = path.string(); 171 } 172 //else if(fs::exists(rsrcPath)) 173 // format = Format::basilisk; 174 } 175 if(format == Format::autodetect) 176 { 177 if(CheckAppleDouble(path, "._")) 178 format = Format::underscore_appledouble; 179 if(CheckAppleDouble(path, "%")) 180 format = Format::percent_appledouble; 181 } 182 if(format == Format::autodetect) 183 { 184 fs::ifstream in(path); 185 if(in) 186 { 187 int magic1 = longword(in); 188 if(in && magic1 == 0x00051600) 189 { 190 int magic2 = longword(in); 191 if(in && magic2 == 0x00020000) 192 format = Format::applesingle; 193 } 194 } 195 } 196 if(format == Format::autodetect) 197 { 198#ifdef __APPLE__ 199 format = Format::real; 200#else 201 format = Format::basilisk; 202#endif 203 } 204// std::cout << "assigned: " << pathstring << " format " << (int)format << "\n"; 205 return true; 206} 207 208bool ResourceFile::read(std::istream& in, Format f) 209{ 210 switch(f) 211 { 212 case Format::applesingle: 213 { 214 if(longword(in) != 0x00051600) 215 return false; 216 if(longword(in) != 0x00020000) 217 return false; 218 in.seekg(24); 219 int n = word(in); 220 for(int i = 0; i < n; i++) 221 { 222 in.seekg(26 + i * 12); 223 int what = longword(in); 224 int off = longword(in); 225 int len = longword(in); 226 in.seekg(off); 227 switch(what) 228 { 229 case 1: 230 { 231 std::vector<char> buf(len); 232 in.read(buf.data(), len); 233 data = std::string(buf.begin(), buf.end()); 234 } 235 break; 236 case 2: 237 resources = Resources(in); 238 break; 239 case 9: 240 type = ostype(in); 241 creator = ostype(in); 242 break; 243 } 244 } 245 } 246 break; 247 case Format::macbin: 248 { 249 if(byte(in) != 0) 250 return false; 251 if(byte(in) > 63) 252 return false; 253 in.seekg(65); 254 type = ostype(in); 255 creator = ostype(in); 256 in.seekg(83); 257 int datasize = longword(in); 258 //int rsrcsize = longword(in); 259 260 in.seekg(0); 261 char header[124]; 262 in.read(header, 124); 263 unsigned short crc = CalculateCRC(0,header,124); 264 if(word(in) != crc) 265 return false; 266 in.seekg(128); 267 std::vector<char> buf(datasize); 268 in.read(buf.data(), datasize); 269 data = std::string(buf.begin(), buf.end()); 270 datasize = ((int)datasize + 0x7F) & ~0x7F; 271 in.seekg(128 + datasize); 272 resources = Resources(in); 273 } 274 break; 275 default: 276 return false; 277 } 278 return true; 279} 280 281bool ResourceFile::read() 282{ 283 fs::path path(pathstring); 284 285 type = creator = 0x3F3F3F3F; 286 287 if(isSingleFork(format)) 288 { 289 fs::ifstream in(path); 290 return read(in, format); 291 } 292 293 switch(format) 294 { 295 case Format::basilisk: 296 { 297 fs::ifstream dataIn(path); 298 if(!dataIn) 299 return false; 300 data = std::string(std::istreambuf_iterator<char>(dataIn), 301 std::istreambuf_iterator<char>()); 302 303 fs::ifstream rsrcIn(path.parent_path() / ".rsrc" / path.filename()); 304 if(rsrcIn) 305 resources = Resources(rsrcIn); 306 fs::ifstream finfIn(path.parent_path() / ".finf" / path.filename()); 307 if(finfIn) 308 { 309 type = ostype(finfIn); 310 creator = ostype(finfIn); 311 } 312 } 313 break; 314#ifdef __APPLE__ 315 case Format::real: 316 { 317 fs::ifstream dataIn(path); 318 if(!dataIn) 319 return false; 320 data = std::string(std::istreambuf_iterator<char>(dataIn), 321 std::istreambuf_iterator<char>()); 322 fs::ifstream rsrcIn(path / "..namedfork" / "rsrc"); 323 if(rsrcIn) 324 resources = Resources(rsrcIn); 325 326 char finf[32]; 327 int n = getxattr(path.c_str(), XATTR_FINDERINFO_NAME, 328 finf, 32, 0, 0); 329 if(n > 0) 330 { 331 std::istringstream finfIn(std::string(finf, finf+n)); 332 type = ostype(finfIn); 333 creator = ostype(finfIn); 334 } 335 } 336 break; 337#endif 338 339 case Format::underscore_appledouble: 340 case Format::percent_appledouble: 341 { 342 fs::ifstream dataIn(path); 343 data = std::string(std::istreambuf_iterator<char>(dataIn), 344 std::istreambuf_iterator<char>()); 345 346 std::string prefix = format == Format::underscore_appledouble ? 347 "._" : "%"; 348 349 fs::path adPath = path.parent_path() / (prefix + path.filename().string()); 350 fs::ifstream in(adPath); 351 if(longword(in) != 0x00051607) 352 return false; 353 if(longword(in) != 0x00020000) 354 return false; 355 in.seekg(24); 356 int n = word(in); 357 for(int i = 0; i < n; i++) 358 { 359 in.seekg(26 + i * 12); 360 int what = longword(in); 361 int off = longword(in); 362 //int len = longword(in); 363 in.seekg(off); 364 switch(what) 365 { 366 case 2: 367 resources = Resources(in); 368 break; 369 case 9: 370 type = ostype(in); 371 creator = ostype(in); 372 break; 373 } 374 } 375 } 376 break; 377 default: 378 return false; 379 } 380 return true; 381} 382 383bool ResourceFile::write(std::ostream& out, Format f) 384{ 385 switch(f) 386 { 387 case Format::macbin: 388 { 389 writeMacBinary(out, filename, type, creator, resources, data); 390 } 391 break; 392 case Format::applesingle: 393 { 394 longword(out, 0x00051600); 395 longword(out, 0x00020000); 396 for(int i = 0; i < 16; i++) 397 byte(out, 0); 398 word(out, 3); 399 std::streampos entries = out.tellp(); 400 for(int i = 0; i < 3*3; i++) 401 longword(out, 0); 402 std::streampos dataStart = out.tellp(); 403 out << data; 404 std::streampos rsrcStart = out.tellp(); 405 resources.writeFork(out); 406 std::streampos finfStart = out.tellp(); 407 ostype(out, type); 408 ostype(out, creator); 409 for(int i = 8; i < 32; i++) 410 byte(out, 0); 411 out.seekp(entries); 412 longword(out, 1); 413 longword(out, dataStart); 414 longword(out, rsrcStart - dataStart); 415 longword(out, 2); 416 longword(out, rsrcStart); 417 longword(out, finfStart - rsrcStart); 418 longword(out, 9); 419 longword(out, finfStart); 420 longword(out, 32); 421 } 422 break; 423 default: 424 return false; 425 } 426 return true; 427} 428 429bool ResourceFile::write() 430{ 431 fs::path path(pathstring); 432 433 if(isSingleFork(format)) 434 { 435 fs::ofstream out(path); 436 return write(out, format); 437 } 438 439 switch(format) 440 { 441 case Format::basilisk: 442 { 443 fs::create_directory(path.parent_path() / ".rsrc"); 444 fs::create_directory(path.parent_path() / ".finf"); 445 446 fs::ofstream dataOut(path); 447 fs::ofstream rsrcOut(path.parent_path() / ".rsrc" / path.filename()); 448 fs::ofstream finfOut(path.parent_path() / ".finf" / path.filename()); 449 450 dataOut << data; 451 resources.writeFork(rsrcOut); 452 453 ostype(finfOut, type); 454 ostype(finfOut, creator); 455 for(int i = 8; i < 32; i++) 456 byte(finfOut, 0); 457 } 458 break; 459#ifdef __APPLE__ 460 case Format::real: 461 { 462 fs::ofstream dataOut(path); 463 fs::ofstream rsrcOut(path / "..namedfork" / "rsrc"); 464 std::ostringstream finfOut; 465 466 dataOut << data; 467 resources.writeFork(rsrcOut); 468 469 ostype(finfOut, type); 470 ostype(finfOut, creator); 471 for(int i = 8; i < 32; i++) 472 byte(finfOut, 0); 473 setxattr(path.c_str(), XATTR_FINDERINFO_NAME, 474 finfOut.str().data(), 32, 0, 0); 475 } 476 break; 477#endif 478 479 case Format::underscore_appledouble: 480 case Format::percent_appledouble: 481 { 482 fs::ofstream dataOut(path); 483 484 dataOut << data; 485 486 std::string prefix = format == Format::underscore_appledouble ? 487 "._" : "%"; 488 489 fs::path adPath = path.parent_path() / (prefix + path.filename().string()); 490 491 fs::ofstream out(adPath); 492 493 longword(out, 0x00051607); 494 longword(out, 0x00020000); 495 496 for(int i = 0; i < 16; i++) 497 byte(out, 0); 498 word(out, 2); 499 std::streampos entries = out.tellp(); 500 for(int i = 0; i < 2*3; i++) 501 longword(out, 0); 502 std::streampos rsrcStart = out.tellp(); 503 resources.writeFork(out); 504 std::streampos finfStart = out.tellp(); 505 ostype(out, type); 506 ostype(out, creator); 507 for(int i = 8; i < 32; i++) 508 byte(out, 0); 509 out.seekp(entries); 510 longword(out, 2); 511 longword(out, rsrcStart); 512 longword(out, finfStart - rsrcStart); 513 longword(out, 9); 514 longword(out, finfStart); 515 longword(out, 32); 516 } 517 break; 518#ifndef DARLING 519 case Format::diskimage: 520 { 521 std::ostringstream rsrcOut; 522 resources.writeFork(rsrcOut); 523 std::string rsrc = rsrcOut.str(); 524 int size = rsrc.size(); 525 526 size += 20 * 1024; 527 size += 800*1024 - size % (800*1024); 528 529 fs::ofstream(path, std::ios::binary | std::ios::trunc).seekp(size-1).put(0); 530 531 hfs_format(pathstring.c_str(), 0, 0, path.stem().string().substr(0,27).c_str(), 0, NULL); 532 hfsvol *vol = hfs_mount(pathstring.c_str(), 0, HFS_MODE_RDWR); 533 if(!vol) 534 return false; 535 //hfs_setvol(vol, ) 536 hfsfile *file = hfs_create(vol, (path.stem().string().substr(0,31)).c_str(), 537 ((std::string)type).c_str(), ((std::string)creator).c_str()); 538 hfs_setfork(file, 0); 539 hfs_write(file, data.data(), data.size()); 540 hfs_setfork(file, 1); 541 hfs_write(file, rsrc.data(), rsrc.size()); 542 543 hfs_close(file); 544 hfs_umount(vol); 545 546 } 547 break; 548#endif 549 default: 550 return false; 551 } 552 return true; 553} 554 555bool ResourceFile::hasPlainDataFork(ResourceFile::Format f) 556{ 557 switch(f) 558 { 559#ifdef __APPLE__ 560 case Format::real: 561#endif 562 case Format::basilisk: 563 case Format::underscore_appledouble: 564 case Format::percent_appledouble: 565 return true; 566 default: 567 return false; 568 } 569} 570 571bool ResourceFile::hasPlainDataFork() 572{ 573 return hasPlainDataFork(format); 574} 575 576bool ResourceFile::isSingleFork(Format f) 577{ 578 switch(f) 579 { 580 case Format::macbin: 581 case Format::applesingle: 582 return true; 583 default: 584 return false; 585 } 586}