Библиотека кодирования / декодирования TAR для iPhone (в идеале - какао)
Кто-нибудь знает какую-либо библиотеку / код, который позволит мне кодировать и декодировать данные в формате.tar - которые я могу использовать в своем проекте iPhone (предпочтительно какао)
заранее спасибо
Craig
ОБНОВЛЕНИЕ: Я взглянул на предложенные библиотеки и пришел к выводу, что они решают большую часть проблемы - поэтому я сам разрабатываю кодек - это всего лишь 512-байтовый заголовок ASCII в конце концов - насколько это сложно быть:-)
7 ответов
Лучшая библиотека, которую я нашел, libarchive
, Он хорошо продуман, хорошо документирован и быстр.
Я только что создал репозиторий на GitHub, в котором есть инструменты для сборки libarchive
а также libbz2
в качестве статических библиотек для iOS 4.2+. (Должно быть возможно использовать его и для цели 3.x).
http://github.com/davepeck/iOS-libarchive/
Другие отметили, что libarchive
включен в SDK. Это не совсем так. Бинарный libarchive.2.dylib
включен, но заголовки нет. То же самое относится и к libbz2
(но, как ни странно, не libz
.) Это означает, что libarchive
считается частным API - иными словами, вы не можете использовать его, если собираетесь отправлять в App Store. Отсюда и мой репозиторий.
Фактически, libarchive.dylib включен в iPhone SDK. Вы просто должны добавить это. Проблема в том, что как-то Apple не включила заголовочный файл archive.h. Однако, во-первых, вам не нужны файлы заголовков, если вы точно знаете, что функции, которые вы собираетесь вызывать, существуют (хотя компилятор будет скулить), во-вторых, если вы не хотите, чтобы компилятор жаловался, вы можете скачать файл заголовка для libarchive 2.6 и включите его в свою программу...
Если вы хотите знать, как использовать libarchive, загрузите его источник из Интернета и изучите приведенный пример (особенно мини-гитары). Это действительно очень просто.
Еще лучше ссылка: http://code.google.com/p/libarchive/downloads/detail?name=libarchive-2.6.2.tar.gz&can=2&q=
Версия 2.6.2 включена в iOS 4.0 и 4.1 SDK. Это не присутствует в 3.2 (или ранее я предполагаю).
Если вы загрузите это, запустите ./configure --prefix=$HOME && make && make install
и вы найдете два заголовочных файла, помещенных в $HOME/include
Для libarchive он работает из коробки, просто добавив libarchive в список фреймворков, но заголовок отсутствует. Вы можете скопировать заголовки из исходного архива. Или, если вы хотите сохранить простоту, попробуйте это:
////////////////////////////////////////////////////////////////////////////////////////////////////
// LibArchive "Header" - ios is missing this header. go figure.
////////////////////////////////////////////////////////////////////////////////////////////////////
// from ftp://ftp8.freebsd.org/pub/FreeBSD/FreeBSD-current/src/lib/libarchive/archive.h.in
#define ARCHIVE_EOF 1 /* Found end of archive. */
#define ARCHIVE_OK 0 /* Operation was successful. */
#define ARCHIVE_RETRY (-10) /* Retry might succeed. */
#define ARCHIVE_WARN (-20) /* Partial success. */
#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */
#define ARCHIVE_FATAL (-30) /* No more operations are possible. */
struct archive;
struct archive_entry;
int archive_version_number(void);
const char * archive_version_string(void);
int archive_version_stamp(void);
const char * archive_version(void);
int archive_api_version(void);
int archive_api_feature(void);
typedef ssize_t archive_read_callback(struct archive *, void *_client_data, const void **_buffer);
//typedef ssize_t archive_skip_callback(struct archive *, void *_client_data, size_t request);
typedef off_t archive_skip_callback(struct archive *, void *_client_data, off_t request);
typedef ssize_t archive_write_callback(struct archive *, void *_client_data, const void *_buffer, size_t _length);
typedef int archive_open_callback(struct archive *, void *_client_data);
typedef int archive_close_callback(struct archive *, void *_client_data);
struct archive *archive_read_new(void);
int archive_read_support_compression_all(struct archive *);
int archive_read_support_compression_bzip2(struct archive *);
int archive_read_support_compression_compress(struct archive *);
int archive_read_support_compression_gzip(struct archive *);
int archive_read_support_compression_none(struct archive *);
int archive_read_support_compression_program(struct archive *, const char *command);
int archive_read_support_format_all(struct archive *);
int archive_read_support_format_ar(struct archive *);
int archive_read_support_format_cpio(struct archive *);
int archive_read_support_format_empty(struct archive *);
int archive_read_support_format_gnutar(struct archive *);
int archive_read_support_format_iso9660(struct archive *);
int archive_read_support_format_mtree(struct archive *);
int archive_read_support_format_tar(struct archive *);
int archive_read_support_format_zip(struct archive *);
int archive_read_open(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_close_callback *);
int archive_read_open2(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_skip_callback *, archive_close_callback *);
int archive_read_open_filename(struct archive *, const char *_filename, size_t _block_size);
int archive_read_open_file(struct archive *, const char *_filename, size_t _block_size);
int archive_read_open_memory(struct archive *, void * buff, size_t size);
int archive_read_open_memory2(struct archive *a, void *buff, size_t size, size_t read_size);
int archive_read_open_fd(struct archive *, int _fd, size_t _block_size);
int archive_read_open_FILE(struct archive *, FILE *_file);
int archive_read_next_header(struct archive *, struct archive_entry **);
int64_t archive_read_header_position(struct archive *);
ssize_t archive_read_data(struct archive *, void *, size_t);
int archive_read_data_block(struct archive *a, const void **buff, size_t *size, off_t *offset);
int archive_read_data_skip(struct archive *);
int archive_read_data_into_buffer(struct archive *, void *buffer, ssize_t len);
int archive_read_data_into_fd(struct archive *, int fd);
int archive_read_extract(struct archive *, struct archive_entry *, int flags);
void archive_read_extract_set_progress_callback(struct archive *, void (*_progress_func)(void *), void *_user_data);
void archive_read_extract_set_skip_file(struct archive *, dev_t, ino_t);
int archive_read_close(struct archive *);
int archive_read_finish(struct archive *);
//void archive_read_finish(struct archive *);
struct archive *archive_write_new(void);
int archive_write_set_bytes_per_block(struct archive *, int bytes_per_block);
int archive_write_get_bytes_per_block(struct archive *);
int archive_write_set_bytes_in_last_block(struct archive *, int bytes_in_last_block);
int archive_write_get_bytes_in_last_block(struct archive *);
int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
int archive_write_set_compression_bzip2(struct archive *);
int archive_write_set_compression_compress(struct archive *);
int archive_write_set_compression_gzip(struct archive *);
int archive_write_set_compression_none(struct archive *);
int archive_write_set_compression_program(struct archive *, const char *cmd);
int archive_write_set_format(struct archive *, int format_code);
int archive_write_set_format_by_name(struct archive *, const char *name);
int archive_write_set_format_ar_bsd(struct archive *);
int archive_write_set_format_ar_svr4(struct archive *);
int archive_write_set_format_cpio(struct archive *);
int archive_write_set_format_cpio_newc(struct archive *);
int archive_write_set_format_pax(struct archive *);
int archive_write_set_format_pax_restricted(struct archive *);
int archive_write_set_format_shar(struct archive *);
int archive_write_set_format_shar_dump(struct archive *);
int archive_write_set_format_ustar(struct archive *);
int archive_write_open(struct archive *, void *, archive_open_callback *, archive_write_callback *, archive_close_callback *);
int archive_write_open_fd(struct archive *, int _fd);
int archive_write_open_filename(struct archive *, const char *_file);
int archive_write_open_file(struct archive *, const char *_file);
int archive_write_open_FILE(struct archive *, FILE *);
int archive_write_open_memory(struct archive *, void *_buffer, size_t _buffSize, size_t *_used);
int archive_write_header(struct archive *, struct archive_entry *);
ssize_t archive_write_data(struct archive *, const void *, size_t);
//int archive_write_data(struct archive *, const void *, size_t);
ssize_t archive_write_data_block(struct archive *, const void *, size_t, off_t);
int archive_write_finish_entry(struct archive *);
int archive_write_close(struct archive *);
int archive_write_finish(struct archive *);
//void archive_write_finish(struct archive *);
struct archive *archive_write_disk_new(void);
int archive_write_disk_set_skip_file(struct archive *, dev_t, ino_t);
int archive_write_disk_set_options(struct archive *, int flags);
int archive_write_disk_set_standard_lookup(struct archive *);
int archive_write_disk_set_group_lookup(struct archive *, void *private_data, gid_t (*loookup)(void *, const char *gname, gid_t gid), void (*cleanup)(void *));
int archive_write_disk_set_user_lookup(struct archive *, void *private_data, uid_t (*)(void *, const char *uname, uid_t uid), void (*cleanup)(void *));
int64_t archive_position_compressed(struct archive *);
int64_t archive_position_uncompressed(struct archive *);
const char * archive_compression_name(struct archive *);
int archive_compression(struct archive *);
int archive_errno(struct archive *);
const char * archive_error_string(struct archive *);
const char * archive_format_name(struct archive *);
int archive_format(struct archive *);
void archive_clear_error(struct archive *);
void archive_set_error(struct archive *, int _err, const char *fmt, ...);
void archive_copy_error(struct archive *dest, struct archive *src);
// From ftp://ftp8.freebsd.org/pub/FreeBSD/FreeBSD-current/src/lib/libarchive/archive_entry.h
time_t archive_entry_atime(struct archive_entry *);
long archive_entry_atime_nsec(struct archive_entry *);
time_t archive_entry_ctime(struct archive_entry *);
long archive_entry_ctime_nsec(struct archive_entry *);
dev_t archive_entry_dev(struct archive_entry *);
dev_t archive_entry_devmajor(struct archive_entry *);
dev_t archive_entry_devminor(struct archive_entry *);
mode_t archive_entry_filetype(struct archive_entry *);
void archive_entry_fflags(struct archive_entry *, unsigned long *set, unsigned long *clear);
const char* archive_entry_fflags_text(struct archive_entry *);
gid_t archive_entry_gid(struct archive_entry *);
const char* archive_entry_gname(struct archive_entry *);
const wchar_t* archive_entry_gname_w(struct archive_entry *);
const char* archive_entry_hardlink(struct archive_entry *);
const wchar_t* archive_entry_hardlink_w(struct archive_entry *);
ino_t archive_entry_ino(struct archive_entry *);
mode_t archive_entry_mode(struct archive_entry *);
time_t archive_entry_mtime(struct archive_entry *);
long archive_entry_mtime_nsec(struct archive_entry *);
unsigned int archive_entry_nlink(struct archive_entry *);
const char* archive_entry_pathname(struct archive_entry *);
const wchar_t* archive_entry_pathname_w(struct archive_entry *);
dev_t archive_entry_rdev(struct archive_entry *);
dev_t archive_entry_rdevmajor(struct archive_entry *);
dev_t archive_entry_rdevminor(struct archive_entry *);
int64_t archive_entry_size(struct archive_entry *);
const char* archive_entry_strmode(struct archive_entry *);
const char* archive_entry_symlink(struct archive_entry *);
const wchar_t* archive_entry_symlink_w(struct archive_entry *);
uid_t archive_entry_uid(struct archive_entry *);
const char* archive_entry_uname(struct archive_entry *);
const wchar_t* archive_entry_uname_w(struct archive_entry *);
Я заботился только о чтении, поэтому я не стал беспокоиться о некоторых функциях мутации archive_entry.h. Кроме того, некоторые из методов закомментированы. Это альтернативы для разных версий, которые выдают #ifdef'd. Удачи и удачной охоты на насекомых!
Вот пример его использования для распаковки архива в каталог на ios:
+ (void)unpackArchive: (NSData*) archiveData
{
int r;
struct archive* a;
struct archive_entry *entry;
const char *entry_path;
NSString *baseDir = [self baseDir];
NSFileHandle* file;
NSError* error;
NSDictionary* result = @{};
NSLog(@"Unpacking %d byte static assets tarball into %@", [archiveData length], baseDir);
if (![[NSFileManager defaultManager] createDirectoryAtPath:baseDir
withIntermediateDirectories:YES
attributes:nil
error:&error])
{
NSLog(@"Create directory error: %@", error);
}
a = archive_read_new();
archive_read_support_format_gnutar(a);
archive_read_support_format_tar(a);
archive_read_support_compression_gzip(a);
r = archive_read_open_memory(a, (void*)[archiveData bytes], [archiveData length]);
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_open_file(): %s", r, archive_error_string(a));
return;
}
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF) {
break;
}
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_next_header(): %s", r, archive_error_string(a));
return;
}
entry_path = archive_entry_pathname(entry);
NSString* path = [baseDir stringByAppendingPathComponent: [NSString stringWithUTF8String: entry_path]];
NSLog(@"Tarball Entry: %s", entry_path);
// Create the file and blank it out
[[NSFileManager defaultManager] createFileAtPath: path contents:[[NSMutableData alloc] init] attributes:nil];
// Actually write the file
file = [NSFileHandle fileHandleForWritingAtPath:path];
r = archive_read_data_into_fd(a, [file fileDescriptor]);
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_data_into_fd(): %s", r, archive_error_string(a));
return;
}
[file closeFile];
}
r = archive_read_close(a);
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_close(): %s", r, archive_error_string(a));
return;
}
}
--- Дэйв
Вы можете попробовать libxad. Это библиотека, которую использует приложение Unarchiver для Mac.
Кажется, есть еще две современные библиотеки, обе из которых доступны как Cocoapods:
- NVHTarGzip: Поддерживает отчеты о прогрессе, и имеет как синхронизирующие, так и асинхронные методы. Не поддерживает запись в tar.
- tarkit: поддерживает запись в tar, но не имеет других приятных функций.
Оба они очень похожи, так как оба они основаны на Light-Untar-for-iOS.