2013-09-16 8 views
5

Для программы восстановления данных мне нужно иметь возможность извлекать значения + типы из файлов, написанных NSArchiver, без доступа к фреймворкам CF/NS от Apple.Проверка файлов типа «NeXT/Apple typedstream» версии 4 (NSArchiver)

Доклады команд OS X file такие файлы как:

NeXT/Apple typedstream data, little endian, version 4, system 1000 

Есть ли документация о том, как эти файлы кодируются, или кто-нибудь придумать код, который может разобрать их?

Вот пример таких данных (также: downloadable):

04 0B 73 74 72 65 61 6D 74 79 70 65 64 81 E8 03 ..streamtyped... 
84 01 40 84 84 84 12 4E 53 41 74 74 72 69 62 75 [email protected] 
74 65 64 53 74 72 69 6E 67 00 84 84 08 4E 53 4F tedString....NSO 
62 6A 65 63 74 00 85 92 84 84 84 08 4E 53 53 74 bject.......NSSt 
72 69 6E 67 01 94 84 01 2B 06 46 65 73 6B 65 72 ring....+.Fesker 
86 84 02 69 49 01 06 92 84 84 84 0C 4E 53 44 69 ...iI.......NSDi 
63 74 69 6F 6E 61 72 79 00 94 84 01 69 01 92 84 ctionary....i... 
96 96 1D 5F 5F 6B 49 4D 4D 65 73 73 61 67 65 50 ...__kIMMessageP 
61 72 74 41 74 74 72 69 62 75 74 65 4E 61 6D 65 artAttributeName 
86 92 84 84 84 08 4E 53 4E 75 6D 62 65 72 00 84 ......NSNumber.. 
84 07 4E 53 56 61 6C 75 65 00 94 84 01 2A 84 99 ..NSValue....*.. 
99 00 86 86 86         ..... 

Это содержит NSAttributedString. У меня есть аналогичные примеры, которые содержат NSMutableAttributedStrings и т. Д., Но все они в конечном итоге разрешают NSAttributedStrings, для которых мне нравится получать текст. Я не забочусь обо всем остальном, но мне нужно знать, действительно ли это.

Мое настоящее решение - использовать NSUnarchiver и, полагая, что я всегда должен найти NSAttributedString там, получить его первый элемент и прочитать его текст, а затем воссоздать из него архив и посмотреть, совпадает ли он с исходными данными , Если я получаю исключение или другой архив назад, я полагаю, что архив поврежден или недействителен:

NSData *data = [[NSData alloc] initWithBytesNoCopy:dataPtr length:dataLen freeWhenDone:false]; 
NSUnarchiver *a = NULL; 

// The algorithm simply assumes that the data contains a NSAttributedString, retrieves it, 
// and then recreates the NSArchived version from it in order to tell its size. 
@try { 
    a = [[NSUnarchiver alloc] initForReadingWithData:data]; 
    NSAttributedString *s = [a decodeObject]; 

    // re-encode the string item so we can tell its length 
    NSData *d = [NSArchiver archivedDataWithRootObject:s]; 
    if ([d isEqualTo:[data subdataWithRange:NSMakeRange(0,d.length)]]) { 
     lenOut = (int) d.length; 
     okay = true; // -> lenOut is valid, though textOut might still fail, see @catch below 
     textOut = [s.string cStringUsingEncoding:NSUTF8StringEncoding]; 
    } else { 
     // oops, we don't get back what we had as input, so let's better not consider this valid 
    } 
} @catch (NSException *e) { 
    // data is invalid 
} 

Однако есть несколько проблем с выше кодом:

  1. Это не х-платформа , Мне тоже нужно работать в Windows.
  2. Некоторые примеры поврежденных данных вызывают нежелательную ошибку msg, записанную в stderr или syslog (не уверены, какой), например: *** mmap(size=18446744071608111104) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug (я печатал отчет об ошибке, который был закрыт как «не исправить», к сожалению).
  3. Ничто не гарантирует, что код NSUnarchiver 100% защищен от кражи. Для этого примером является ошибка malloc. Я мог бы также получить ошибку шины в некоторых ситуациях, и это было бы фатальным. Если у меня есть пользовательский код для синтаксического анализа, я сам позабочусь об этом (и исправлю любые сбои, с которыми я сталкиваюсь). (Обновление: я только что нашел некоторые недопустимые данные, которые действительно приводят к сбою NSUnarchiver с помощью SIGSEGV.)

Поэтому мне нужен специальный код для декодирования этих типов архивов. Я посмотрел на несколько, но не могу понять коды, которые он использует. По-видимому, существуют поля длины и поля типа, причем типы находятся в диапазоне от 0x81 до 0x86. Кроме того, первый 16-байтовый заголовок, включая системный код (0x03E8 = 1000) со смещением 14-15.

Я также задаюсь вопросом, доступен ли исходный код в некоторых старых источниках NeXT или в версии Windows, которая когда-то существовала, но где бы я ее нашел? (Примечание. Я был направлен в источник GNUstep («core.20131003.tar.bz2»), в котором я нашел его источник NSUnarchiver, но этот код, по-видимому, с 1998 года, использует свою собственную кодировку, которая не понимает этого «потоковое» кодирование.)

ответ

0

Посмотрите на реализацию Cocotron по открытым исходным кодом NSArchiver и NSUnarchiver:

https://code.google.com/p/cocotron/source/browse/Foundation/NSArchiver.m https://code.google.com/p/cocotron/source/browse/Foundation/NSUnarchiver.m

+0

К сожалению, этот формат использует другой формат, как и GNUstep :( –

+0

Поскольку эти два класса устарели, возможно, вы смотрите на 'NSKeyed * rchiver'? –

+0

Нет, это старая неблокированная версия. Фактически, когда я передаю данные NSKeyedUnarchiver, он прерывается с ошибкой. –

0

Вроде бы часть GNU Objective-C среды выполнения, даже если это не совсем выполнения вещи (см обсуждение на: http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00495.html)

Этот файл может реализовать этот материал: https://github.com/gnustep/gnustep-libobjc/blob/master/archive.c

+0

Спасибо, нужно проверить это завтра. Мне просто интересно, почему кто-то отказал в ответе - если люди это делают, они должны оставить комментарий о –

5

Хотя я не знаю какой-либо документации по формату, вы можете найти информацию, которую ищете, проверив общедоступный исходный код из старых версий Darwin (или, возможно, OpenStep).

Например, взгляните на реализацию typedstream в файле typedstream.m в objc-1.tar.gz доступны на this mirror of an old darwin distribution.

Этот исходный код должен быть способен читать/писать typedstream. Просто не забудьте подтвердить лицензию Apple при ее использовании.

+0

Да, это первый источник, который я видел, который действительно знает о «typedstream». Это должно сделать это. –

+0

Оказывается, этот код слишком стар и не может обрабатывать современные архивы, подобные тому, который задан в вопросе. –

+1

Ссылка, содержащаяся наверху, мертва. Можно найти одну версию здесь: http://next.68k.org/n extstuff/otto/html/pub/apple.com/PublicSource/Darwin/objc-1.tar.gz – yageek

0

Во-первых, пожалуйста, см. Is there a way to read in files in TypedStream format для получения некоторой интересной информации.

Возможно, формат может быть преобразован в нечто более читаемое, используя инструмент plutil. Этот инструмент также доступен для Windows (он поставляется с iTunes для Windows). Однако не уверен в своей лицензии.

Проблемная часть состоит в том, что файлы содержат экземпляры объектов, преобразованные в двоичные. Недостаточно понять формат файла, необходимо понять, как хранится каждый тип.

+0

Я уже прочитал этот другой вопрос SO и следил за его ссылками. Казалось, ничего, что могло бы помочь мне, в частности. Кроме того, plutil не может читать эти файлы с типом. Теперь я сделал загружаемую версию файла. –

3

Часть вопроса здесь состоит в том, что каждый класс в Cocoa/NeXTSTEP/OPENSTEP знает, как архивировать себя. В каждом классе есть метод initWithCoder:/encodeWithCoder: и внутри есть раздел для typedstream и другого раздела для ключей-архивов. Ключевые архивы более современны и обычно выражаются как XML-массивы. Они могут быть закодированы в двоичной форме, но, не ошибитесь, эта двоичная форма НЕ такая же, как типовой архив. Кроме того, они вводятся так, что легко вытащить отдельные фрагменты данных без необходимости считывать все данные, которые были до этого. Архивы Typedstream не работают таким образом. Они основаны на порядке, что означает, что каждый элемент в каждом объекте записывается один за другим. Сначала введите имя класса, затем версию, затем каждую из частей данных. Причина, по которой GNUstep никогда не выполнялась, заключается в том, что порядок кодирования почти невозможно обнаружить.

При архивации корневого объекта графа объектов он вызывает метод encodeWithCoder: на этом объекте, который в свою очередь вызывает методы encodeWithCoder: по каждому из объектов, которые он содержит, и так далее рекурсивно, пока весь архив объекта не будет архивирован. Когда это делается с использованием архивов с ключами (NSKeyedArchiver), архив создается и управляется соответствующим образом. Когда это делается с помощью типизированного архива потока (NSArchiver), происходит одна и та же рекурсия, но каждый раз, когда объект кодируется, он просто выгружает каждый элемент в архив в любом порядке, который разработчик считал подходящим в то время.

Надеюсь, это объяснение немного облегчит ситуацию. У вас впереди трудный путь. Были причины, по которым это было сделано в GNUstep. Если бы мы это сделали, мы бы все еще пытались понять это.

+0

Спасибо, Грег, это хорошее резюме (лучше, чем у Apple). Но, несмотря на то, что порядок и значение хранимых значений класса неизвестны, каждый элемент по-прежнему индивидуально упакован внутри, каждый с явным типом. И это все, что я хотел выбраться из этого: Дерево типов + значений. Я понимаю, что этого недостаточно для общего поиска сложных типов NS, но он достаточно хорош для моих потребностей, когда я хочу только восстановить текст из таких данных. –

+0

NB. Возможно, вы могли бы выяснить некоторые типы, просто создав свои собственные подклассы NSArchiver и NSKeyedArchiver и используя их для архивирования некоторых общих объектов (возможно, это хороший старт для NSString), чтобы увидеть, какие данные вообще написаны, с какими именами. Я предполагаю, что все архивирование в конце концов сводится к примитивным вызовам типа -encodeInt: and -encodeBytes :. – uliwitness

0

Франк Illenberger написал замену NSUnarchiver под названием MEUnarchiver на основе исходного кода typedstream.m 1999 году: https://github.com/depth42/MEUnarchiver

Она была расширена поддержка новых типов, которые не известны оригинального исходного кода. Он по-прежнему полагается на среду выполнения ObjC для предоставления реализаций декодирования NSCoding для всех стандартных типов, таких как NSString и т. Д., Но в остальном он довольно автономный и позволяет мне предотвращать сбои, возникающие с кодом NSUnarchiver от Apple при передаче поврежденных данных.