Added UnzipEngine, work in progress. This actually unzips, but the progress

reporting is incomplete and it is not yet used for anything, it's not even
part of the build. I am testing it in a selfcontained little test.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32905 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-09-02 14:55:03 +00:00
parent 8e3916f8ef
commit dce00bc179
2 changed files with 278 additions and 0 deletions
+224
View File
@@ -0,0 +1,224 @@
/*
* Copyright 2008-2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "UnzipEngine.h"
#include <new>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <Directory.h>
#include <fs_attr.h>
#include <NodeInfo.h>
#include <Path.h>
#include <String.h>
#include <SymLink.h>
#include "CommandPipe.h"
#include "SemaphoreLocker.h"
using std::nothrow;
UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message)
:
fPackage(""),
fBytesToUncompress(0),
fBytesUncompressed(0),
fItemsToUncompress(0),
fItemsUncompressed(0),
fCurrentTargetFolder(NULL),
fCurrentItem(NULL),
fMessenger(messenger),
fMessage(message)
{
}
UnzipEngine::~UnzipEngine()
{
delete fMessage;
}
status_t
UnzipEngine::SetTo(const char* pathToPackage)
{
fPackage = pathToPackage;
BPrivate::BCommandPipe commandPipe;
status_t ret = commandPipe.AddArg("unzip");
if (ret == B_OK)
ret = commandPipe.AddArg("-Z");
if (ret == B_OK)
ret = commandPipe.AddArg("-t");
if (ret == B_OK)
ret = commandPipe.AddArg(fPackage.String());
if (ret != B_OK)
return ret;
// Launch the unzip thread and start reading the stdout and stderr output.
FILE* stdOutAndErrPipe = NULL;
thread_id unzipThread = commandPipe.PipeInto(&stdOutAndErrPipe);
if (unzipThread < 0)
return (status_t)unzipThread;
BString result = commandPipe.ReadLines(stdOutAndErrPipe);
static const char* kListingFormat = "%llu files, %llu bytes uncompressed, "
"%llu bytes compressed: %f%%";
uint64 bytesCompressed;
float compresssionRatio;
if (sscanf(result.String(), kListingFormat, &fItemsToUncompress,
&fBytesToUncompress, &bytesCompressed, &compresssionRatio) != 4) {
fBytesToUncompress = 0;
fItemsToUncompress = 0;
fprintf(stderr, "error reading command output: %s\n", result.String());
return B_ERROR;
}
printf("%s: %llu items in %llu bytes\n", pathToPackage, fItemsToUncompress,
fBytesToUncompress);
return B_OK;
}
status_t
UnzipEngine::UnzipPackage(const char* destinationFolder,
sem_id cancelSemaphore)
{
if (fItemsToUncompress == 0)
return B_NO_INIT;
if (fMessage) {
BMessage message(*fMessage);
message.AddString("status", "Extracting package.");
fMessenger.SendMessage(&message);
}
BPrivate::BCommandPipe commandPipe;
status_t ret = commandPipe.AddArg("unzip");
if (ret == B_OK)
ret = commandPipe.AddArg("-o");
if (ret == B_OK)
ret = commandPipe.AddArg(fPackage.String());
if (ret == B_OK)
ret = commandPipe.AddArg("-d");
if (ret == B_OK)
ret = commandPipe.AddArg(destinationFolder);
if (ret == B_OK)
ret = commandPipe.AddArg("-x");
if (ret == B_OK)
ret = commandPipe.AddArg(".OptionalPackageDescription");
if (ret != B_OK)
return ret;
// Launch the unzip thread and start reading the stdout and stderr output.
FILE* stdOutAndErrPipe = NULL;
thread_id unzipThread = commandPipe.PipeInto(&stdOutAndErrPipe);
if (unzipThread < 0)
return (status_t)unzipThread;
return _ReadFromPipe(stdOutAndErrPipe, commandPipe, cancelSemaphore);
}
// #pragma mark -
status_t
UnzipEngine::_ReadFromPipe(FILE* stdOutAndErrPipe,
BPrivate::BCommandPipe& commandPipe, sem_id cancelSemaphore)
{
class LineReader : public BPrivate::BCommandPipe::LineReader {
public:
LineReader(sem_id cancelSemaphore, off_t bytesToUncompress,
uint64 itemsToUncompress, BMessenger& messenger,
const BMessage* message)
:
fCancelSemaphore(cancelSemaphore),
fBytesToUncompress(itemsToUncompress),
fBytesUncompressed(0),
fItemsToUncompress(itemsToUncompress),
fItemsUncompressed(0),
fMessenger(messenger),
fMessage(message)
{
}
virtual bool IsCanceled()
{
if (fCancelSemaphore < 0)
return false;
SemaphoreLocker locker(fCancelSemaphore);
return !locker.IsLocked();
}
virtual status_t ReadLine(const BString& line)
{
char item[1024];
char linkTarget[256];
const char* kInflatingFormat = " inflating: %s\n";
const char* kLinkingFormat = " linking: %s -> %s\n";
if (sscanf(line.String(), kInflatingFormat, &item) == 1
|| sscanf(line.String(), kLinkingFormat, &item,
&linkTarget) == 2) {
BString itemPath(item);
int pos = itemPath.FindLast('/');
BString itemName = itemPath.String() + pos + 1;
itemPath.Truncate(pos);
printf("extracted %s to %s\n", itemName.String(),
itemPath.String());
} else {
printf("ignored: %s", line.String());
}
return B_OK;
}
private:
sem_id fCancelSemaphore;
off_t fBytesToUncompress;
off_t fBytesUncompressed;
uint64 fItemsToUncompress;
uint64 fItemsUncompressed;
BMessenger& fMessenger;
const BMessage* fMessage;
};
LineReader lineReader(cancelSemaphore, fBytesToUncompress,
fItemsToUncompress, fMessenger, fMessage);
return commandPipe.ReadLines(stdOutAndErrPipe, &lineReader);
}
void
UnzipEngine::_UpdateProgress()
{
if (fMessage != NULL) {
BMessage message(*fMessage);
float progress = 100.0 * fBytesUncompressed / fBytesToUncompress;
message.AddFloat("progress", progress);
message.AddInt32("current", fItemsUncompressed);
message.AddInt32("maximum", fItemsToUncompress);
message.AddString("item", fCurrentItem);
message.AddString("folder", fCurrentTargetFolder);
fMessenger.SendMessage(&message);
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright 2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef UNZIP_ENGINE_H
#define UNZIP_ENGINE_H
#include <stdio.h>
#include <Messenger.h>
#include <String.h>
namespace BPrivate {
class BCommandPipe;
}
class BMessage;
class BMessenger;
class UnzipEngine {
public:
UnzipEngine(const BMessenger& messenger,
BMessage* message);
virtual ~UnzipEngine();
status_t SetTo(const char* pathToPackage);
status_t UnzipPackage(const char* destinationFolder,
sem_id cancelSemaphore = -1);
private:
status_t _ReadFromPipe(FILE* stdOutAndErrPipe,
BPrivate::BCommandPipe& commandPipe,
sem_id cancelSemaphore);
void _UpdateProgress();
private:
BString fPackage;
off_t fBytesToUncompress;
off_t fBytesUncompressed;
uint64 fItemsToUncompress;
uint64 fItemsUncompressed;
const char* fCurrentTargetFolder;
const char* fCurrentItem;
BMessenger fMessenger;
BMessage* fMessage;
};
#endif // UNZIP_ENGINE_H