Ios 检查类型为“的文件”;NeXT/Apple typedstream“;第4版(NSArchiver)
对于数据恢复程序,我需要能够从NSArchiver编写的文件中提取值+类型,而无需访问苹果的CF/NS框架 OS XIos 检查类型为“的文件”;NeXT/Apple typedstream“;第4版(NSArchiver),ios,objective-c,macos,nscoding,nsarchiving,Ios,Objective C,Macos,Nscoding,Nsarchiving,对于数据恢复程序,我需要能够从NSArchiver编写的文件中提取值+类型,而无需访问苹果的CF/NS框架 OS Xfile命令报告以下文件: NeXT/Apple typedstream data, little endian, version 4, system 1000 有没有关于这些文件是如何编码的文档,或者有没有人想出可以解析它们的代码 以下是此类数据的一个示例(也是:): 这包含一个NSAttributed字符串。我有一些类似的例子,其中包含NSMutableAttributedS
file
命令报告以下文件:
NeXT/Apple typedstream data, little endian, version 4, system 1000
有没有关于这些文件是如何编码的文档,或者有没有人想出可以解析它们的代码
以下是此类数据的一个示例(也是:):
这包含一个NSAttributed字符串。我有一些类似的例子,其中包含NSMutableAttributedString等,但最终都解析为NSAttributedString,我希望得到文本。其余的我不在乎,但我需要知道它是否有效
我目前的解决方案是使用nsunachiver,并且假设我总是应该在其中找到一个nsattributed字符串,获取它的第一个元素并读取它的文本,然后从中重新创建一个存档,看看它是否与原始数据相同。如果我得到一个异常或另一个归档文件,我假设该归档文件已损坏或无效:
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
}
但是,上述代码存在几个问题:
***mmap(size=1844674407160811104)失败(error code=12)***错误:无法分配区域***在malloc\u error\u break中设置一个断点以进行调试
(我提交了一份错误报告,报告以“无法修复”的形式关闭)我还想知道这些源代码是否存在于一些旧的下一个源代码中,或者在曾经存在的Windows版本中,但是我在哪里可以找到它们呢?(注意:我被引导到GNUstep源代码(“core.20131003.tar.bz2”),在其中我找到了它的nsunachiver源代码,但该代码显然是从1998年开始使用的,它使用自己的编码,不理解这种“流式”编码。)看一下Cocodron对
NSArchiver
和nsunachiver
的开源实现:
它似乎是GNU Objective-C运行时的一部分,尽管它并不完全是运行时的东西(请参阅: ) 此文件可以实现这些功能:
虽然我不知道该格式的任何文档,但您可以通过检查旧达尔文(或OpenStep)版本的公共源代码来找到您要查找的信息 例如,在
objc-1.tar.gz
中的typedstream.m
文件中查看typedstream
的实现
此源代码应该能够读/写typedstream
。请确保在使用苹果的许可证时确认它。首先,请查看一些有趣的信息
很可能,可以使用plutil
工具将格式转换为更可读的格式。此工具也可用于windows(它随iTunes for windows提供)。但不确定它的许可证
问题在于文件包含转换为二进制的对象实例。仅仅了解文件格式是不够的,还需要了解每种类型是如何存储的。这里的部分问题是Cocoa/NeXTSTEP/OPENSTEP中的每个类都知道如何存档自己。在每个类中都有一个initWithCoder:/encodeWithCoder:方法,其中有一个用于typedstream的部分和另一个用于键控归档的部分。键控归档更为现代,通常表示为XML plists。这些可以以二进制形式编码,但是,毫无疑问,这种二进制形式与typedstream归档不同。此外,还对它们进行了键控,这样就可以轻松地提取单个数据片段,而无需读取之前的所有数据。Typedstream归档文件不是这样工作的。它们是基于顺序的,这意味着每个对象中的每个元素都是一个接一个地写入的。首先是类名,然后是版本,然后是每个数据段。GNUstep从未实现这一点的原因是编码顺序几乎不可能被发现 当您归档对象图的根对象时,它会对该对象调用encodeWithCoder:方法,该方法反过来对它包含的每个对象调用encodeWithCoder:方法,依此类推,直到归档整个对象图。当使用键控存档(NSKeyedArchiver)完成此操作时,将适当地构建存档并设置键控。当使用类型化流存档(NSArchiver)完成时,同样的递归也会发生,但每次对对象进行编码时,它只是将每个元素以开发人员当时认为合适的顺序转储到存档中
我希望这个解释能澄清一点。你前面的路很难走。在GNUstep中避免这样做是有原因的。如果我们有,我们仍在努力解决这个问题。弗兰克·伊伦伯格根据1999年的typedstream.m源代码编写了一个名为
MEUnarchiver
的NSunachiver替代品:
它已被扩展以支持原始源代码未知的新类型。它仍然依赖于ObjC运行时为所有s提供NSCoding解码器实现
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
}