#ifdef __APPLE__ #define __unix__ #endif #if defined(__unix__) #define uint _uint #include #undef uint #endif import "ecere" static void ShowSyntax() { Log("ECERE Archiver v0.1\n"); Log("Copyright (c) 2003 Jerome Jacovella-St-Louis\n\n"); Log("General Syntax:\n"); Log(" eAR \n"); Log("Extraction Commands:\n"); Log(" v (View) [files...]\n"); Log(" x (Extract All) [where]\n"); Log(" e (Extract) \n"); Log("Modification Commands:\n"); Log(" a (Add) \n"); Log(" r (Refresh) \n"); Log(" u (Update) \n"); Log(" m (Move) \n"); Log(" n (Rename) \n"); Log(" d (Delete) \n"); Log(" c (Clear) \n"); Log(" s (Self Extract) (With a: overwrite)\n"); Log("Options:\n"); Log("(aru) f Treat as folders to pack at the root of the archive\n"); Log("(aru) 0 No Compression\n"); Log("(aru) 1 ... 9 (Fastest Compression ... Best Compression (default = 9))\n"); Log("(earu) w Specify an output directory after \n"); Log("(xearu) q Quiet mode\n"); } #define ARCHIVE_ACTION_VIEW 1 #define ARCHIVE_ACTION_XTRACTALL 2 #define ARCHIVE_ACTION_EXTRACT 4 #define ARCHIVE_ACTION_ADD 5 #define ARCHIVE_ACTION_MOVE 6 #define ARCHIVE_ACTION_RENAME 7 #define ARCHIVE_ACTION_DELETE 8 #define ARCHIVE_ACTION_CLEAR 9 #define ARCHIVE_ACTION_SELFEXT 10 static void ViewArchive(char * path) { FileListing listing { path }; char string[MAX_LOCATION], * directory; SplitArchivePath(path, string, &directory); if(directory[0]) { strcpy(string, directory); if(!strcmp(directory, "/") || !strcmp(directory, "\\")) strcpy(string, DIR_SEPS); else strcat(string, DIR_SEPS); strcat(string, "\n"); Log(string); } while(listing.Find()) { char timeString[28]; strcpy(string, directory); if(string[0]) { if(!strcmp(directory, "/") || !strcmp(directory, "\\")) strcpy(string, DIR_SEPS); else strcat(string, DIR_SEPS); } PathCat(string, listing.name); ((DateTime)listing.stats.modified).local.OnGetString(timeString, null, null); strcat(string, "\n Modified: "); strcat(string, timeString); strcat(string, "\n"); if(listing.stats.attribs.isDirectory) ViewArchive(listing.path); else Log(string); } } #define BUFFERSIZE 0x10000 static void ExtractFileFromArchive(char * path, char * outputFile) { char fileName[MAX_LOCATION]; FileAttribs exists = FileExists(path); bool setTime = false; FileStats stats; if(exists.isDirectory) { FileListing listing { path }; if(outputFile[0]) { if(MakeDir(outputFile)) { setTime = true; FileGetStats(path, &stats); } } while(listing.Find()) { strcpy(fileName, outputFile); // Tweak file name if out if(outputFile[0]) { if(!strcmp(fileName, ".")) fileName[0] = '\0'; if(listing.name[0] == '/' || listing.name[0] == '\\') { char * afterSlash, rest[MAX_LOCATION]; for(afterSlash = fileName; *afterSlash == '/' || *afterSlash == '\\'; afterSlash++); strcpy(rest, afterSlash); PathCat(fileName, "_root"); PathCat(fileName, rest); } else if(listing.name[1] == ':') { char letter[10]; sprintf(letter, "_%cdrive", toupper(listing.name[0])); PathCat(fileName, letter); PathCat(fileName, listing.name[2] ? (listing.name + 3) : (listing.name + 2)); } else PathCat(fileName, listing.name); } else PathCat(fileName, listing.name); if(!strcmp(fileName, "/") || !strcmp(fileName, "\\")) strcpy(fileName, DIR_SEPS); ExtractFileFromArchive(listing.path, fileName); } } else if(exists) { File input = FileOpen(path, read); if(input) { File output = FileOpen(outputFile, write); if(output) { FileSize dataSize, c; static byte buffer[BUFFERSIZE]; FileGetSize(path, &dataSize); if(!quiet) Logf("Extracting %s...\n", outputFile); for(c = 0; c c + BUFFERSIZE) ? BUFFERSIZE : (dataSize - c); input.Read(buffer, 1, size); output.Write(buffer, 1, size); } delete output; setTime = true; FileGetStats(path, &stats); } delete input; } } if(setTime) FileSetTime(outputFile, stats.created, 0, stats.modified); } static bool AddToArchive(Archive archive, ArchiveDir parentDir, char * name, char * path, ArchiveAddMode addMode, int compression) { bool result = true; FileAttribs exists = FileExists(path); if(exists.isDirectory) { ArchiveDir directory; if(name[0] || !parentDir) { FileStats stats; FileGetStats(path, &stats); if(parentDir) directory = parentDir.OpenDirectory(name, &stats, addMode); else directory = archive.OpenDirectory(name, &stats, addMode); } else directory = parentDir; if(directory) { FileListing listing { path }; while(listing.Find()) { if(!AddToArchive(archive, directory, listing.name, listing.path, addMode, compression)) { result = false; break; } } if(directory != parentDir) delete directory; } } else if(exists) { int ratio; uint newPosition; if(!quiet) Logf("Adding %s...", name); if(parentDir.Add(name, path, addMode, compression, &ratio, &newPosition)) { if(newPosition) { if(ratio && !quiet) Logf("(%2d.%1d%%)", ratio / 10, ratio % 10); if(!quiet) Log("\n"); } else Logf("Skipped%s%s.\n", quiet ? " " : "", quiet ? name : ""); } else { Logf("Out of disk space.\nError: Ran out of disk space while archiving%s%s.\n", quiet ? " " : "", quiet ? name : ""); ((GuiApplication)__thisModule).exitCode = 1; result = false; } } return result; } static void MoveFileInArchive(Archive* archive, char * sourcePath, char * outputDirectory) { // Verify if source file/directory exists and figure its kind FileAttribs exists = FileExists(sourcePath); if(exists) { char sourceFileName[MAX_FILENAME], sourceDirectory[MAX_LOCATION]; char archiveName[MAX_LOCATION], * source; char existingFilePath[MAX_LOCATION], * existingFile; bool rootMoving = false; FileAttribs outputExists; bool doMove = false; SplitArchivePath(sourcePath, archiveName, &source); GetLastDirectory(source, sourceFileName); StripLastDirectory(source, sourceDirectory); sprintf(existingFilePath, "<%s>", archiveName); existingFile = existingFilePath + strlen(existingFilePath); PathCat(existingFile, outputDirectory); if(!sourceDirectory[0] && ((sourceFileName[0] && sourceFileName[1] == ':') || sourceFileName[0] == '\\' || sourceFileName[0] == '/')) rootMoving = true; else PathCat(existingFile, sourceFileName); if(rootMoving || fstrcmp(outputDirectory, sourceDirectory)) { // If directory exists in destination directory, move files and then delete outputExists = FileExists(existingFilePath); // If source is a directory if(exists.isDirectory) { // Check if destination directory is within the source directory bool within = true; char outputPart[MAX_FILENAME], outputRest[MAX_LOCATION]; char sourcePart[MAX_FILENAME], sourceRest[MAX_LOCATION]; strcpy(outputRest, outputDirectory); strcpy(sourceRest, source); for(;sourceRest[0];) { SplitDirectory(outputRest, outputPart, outputRest); SplitDirectory(sourceRest, sourcePart, sourceRest); if(fstrcmp(sourcePart, outputPart) || !outputPart[0]) { within = false; break; } } // Proceed with the move if(!within || !source[0]) { // If directory exists in destination directory, move files and then delete if(outputExists.isDirectory || rootMoving || !source[0]) { ArchiveDir input; FileListing listing { sourcePath }; if(!source[0]) { ArchiveDir dir; Logf("Moving files in root to %s.\n", outputDirectory[0] ? outputDirectory : "root"); dir = archive->OpenDirectory(outputDirectory, null, 0); if(dir) { char archiveName[MAX_LOCATION], * archiveFile; delete dir; delete *archive; SplitArchivePath(sourcePath, archiveName, &archiveFile); *archive = ArchiveOpen(archiveName, { true }); } } else if(!rootMoving) Logf("Merging directory %s in %s with %s in %s.\n", sourceFileName, sourceDirectory[0] ? sourceDirectory : "root", sourceFileName, outputDirectory[0] ? outputDirectory : "root"); while(listing.Find()) { if(strcmp(listing.path, existingFilePath)) MoveFileInArchive(archive, listing.path, existingFile); } if(source[0]) { input = archive->OpenDirectory(sourceDirectory, null, 0); if(input) { input.Delete(sourceFileName); delete input; } } } else if(outputExists) Logf("A file with the same name already exists (%s).\n", existingFile); else // Perform operation doMove = true; } else Logf("Can't move directory %s inside itself.\n", source); } // If source is a file else if(outputExists.isDirectory) Logf("A folder with the same name already exists (%s).\n", existingFile); else doMove = true; if(doMove) { // It is important for the output directory to be opened first, as it might // interfere with the input directory while its path is created. ArchiveDir output = archive->OpenDirectory(outputDirectory, null, 0); if(output) { ArchiveDir input = archive->OpenDirectory(sourceDirectory, null, 0); if(input) { // If a file by the same name exists already, replace it if(outputExists.isFile) output.Delete(sourceFileName); Logf("Moving file %s in directory %s to %s.\n", sourceFileName, sourceDirectory[0] ? sourceDirectory : "root", outputDirectory[0] ? outputDirectory : "root"); // Perform operation input.Move(sourceFileName, output); delete input; } delete output; } } } else Logf("File is already in directory \"%s\".\n", sourceDirectory[0] ? sourceDirectory : "root"); } } static bool quiet; class EARApp : GuiApplication { void Main() { bool valid = false; int numFiles = 0; int firstFileArg = 0; int action = 0; bool extractWhere = false; bool addFolders = false; bool selfExtract = false; int compression = 9; ArchiveAddMode addMode = 0; int c; quiet = false; DumpErrors(false); SetLoggingMode(stdOut, null); if(argc > 2) { // First validate command / options char ch; valid = true; for(c = 0; (ch = (char)tolower(argv[1][c])) && valid; c++) { int command = 0; switch(ch) { case 'v': command = ARCHIVE_ACTION_VIEW; break; case 'x': command = ARCHIVE_ACTION_XTRACTALL; break; case 'e': command = ARCHIVE_ACTION_EXTRACT; break; case 'a': command = ARCHIVE_ACTION_ADD; addMode = replace; break; case 'r': command = ARCHIVE_ACTION_ADD; addMode = refresh; break; case 'u': command = ARCHIVE_ACTION_ADD; addMode = update; break; case 'm': command = ARCHIVE_ACTION_MOVE; break; case 'n': command = ARCHIVE_ACTION_RENAME; break; case 'd': command = ARCHIVE_ACTION_DELETE; break; case 'c': command = ARCHIVE_ACTION_CLEAR; break; case 's': if(action == ARCHIVE_ACTION_ADD && addMode == replace) selfExtract = true; else if(!action) command = ARCHIVE_ACTION_SELFEXT; else valid = true; break; case 'f': if(action == ARCHIVE_ACTION_ADD) addFolders = true; else valid = false; break; case 'w': if(action == ARCHIVE_ACTION_EXTRACT || action == ARCHIVE_ACTION_ADD) extractWhere = true; else valid = false; break; case 'q': quiet = true; break; default: if(action == ARCHIVE_ACTION_ADD && ch >= '0' && ch <= '9' && compression == 9) compression = ch - '0'; else valid = false; } if(command) { if(action) valid = false; else action = command; } } if(valid) { // Validate commands needing parameters switch(action) { case ARCHIVE_ACTION_VIEW: numFiles = argc - 3; firstFileArg = 3; break; case ARCHIVE_ACTION_EXTRACT: firstFileArg = 3; if(extractWhere) numFiles = argc - 4; else numFiles = argc - 3; valid = numFiles > 0; break; case ARCHIVE_ACTION_ADD: firstFileArg = 3; if(extractWhere) numFiles = argc - 4; else numFiles = argc - 3; valid = numFiles > 0; break; case ARCHIVE_ACTION_MOVE: firstFileArg = 3; numFiles = argc - 4; valid = numFiles > 0; break; case ARCHIVE_ACTION_RENAME: valid = argc > 4; break; case ARCHIVE_ACTION_DELETE: firstFileArg = 3; numFiles = argc - 3; valid = numFiles > 0; break; case ARCHIVE_ACTION_SELFEXT: valid = argc > 3; break; } } } if(valid) { char archivePath[MAX_LOCATION]; int archivePathLen; sprintf(archivePath, "<%s>", argv[2]); archivePathLen = strlen(archivePath); if(action != ARCHIVE_ACTION_ADD) { FileSize size; if(!FileExists(argv[2])) { Logf("Archive file not found: %s\n", argv[2]); action = 0; } else if(FileGetSize(argv[2], &size) && !size) { Logf("Archive file is empty: %s\n", argv[2]); action = 0; } else { Archive archive = ArchiveOpen(argv[2], { false }); if(archive) delete archive; else { Logf("File is not a valid ECERE archive: %s\n", argv[2]); action = 0; } } } else if(selfExtract) { #ifdef __WIN32__ ExtractFileFromArchive(":extract.exe", argv[2]); #else ExtractFileFromArchive(":extract", argv[2]); chmod(argv[2], 0755); #endif } switch(action) { case ARCHIVE_ACTION_VIEW: { if(!numFiles) ViewArchive(archivePath); else { for(c = firstFileArg; c 3) ? argv[3] : ""); break; case ARCHIVE_ACTION_EXTRACT: { for(c = firstFileArg; c