Inspeção de arquivos do tipo “NeXT / Apple typedstream” versão 4 (NSArchiver)

Para um programa de recuperação de dados, preciso extrair os valores + tipos dos arquivos gravados pelo NSArchiver, sem ter acesso aos frameworks CF / NS da Apple.

O OS Xfile comando relata tais arquivos como:

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

Existe alguma documentação sobre como esses arquivos são codificados ou alguém criou um código que possa analisá-los?

Aqui está um exemplo de tais dados (também:descarregável):

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                                   .....

Isto contém um NSAttributedString. Eu tenho exemplos semelhantes que contêm NSMutableAttributedStrings, etc, mas todos, eventualmente, resolver para NSAttributedStrings, para o qual eu gostaria de obter o texto. Eu não ligo para o resto, mas preciso saber se é válido.

Minha solução atual é usar o NSUnarchiver e, assumindo que eu sempre deveria encontrar um NSAttributedString lá, obter seu primeiro elemento e ler seu texto, em seguida, recriar um arquivo dele e ver se é o mesmo que os dados originais. Se eu receber uma exceção ou um arquivo diferente, presumo que o arquivo está danificado ou é inválido:

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
}

No entanto, existem vários problemas com o código acima:

Não é x-platform. Eu preciso disso para trabalhar no Windows também.Alguns exemplos de dados danificados causam uma mensagem de erro indesejada gravada em stderr ou syslog (não sei qual), como:*** mmap(size=18446744071608111104) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug (Eu arquivei um relatório de bug sobre isso que foi fechado como "não vai consertar", infelizmente).Nada garante que o código NSUnarchiver seja 100% à prova de falhas. O erro malloc é um exemplo disso. Eu poderia muito bem ter um erro de ônibus em algumas situações, e isso seria fatal. Se eu tivesse um código personalizado para analisar, eu poderia cuidar disso sozinho (e consertar qualquer falha que eu encontrasse). (Atualização: Acabei de encontrar alguns dados inválidos que realmente travam o NSUnarchiver com um SIGSEGV.)

Portanto, eu preciso de código personalizado para decodificar esses tipos de arquivos. Eu olhei alguns, mas não consigo entender os códigos que ele usa. Aparentemente, há campos de comprimento e campos de tipo, com os tipos que estão no intervalo em torno de 0x81 a 0x86, aparentemente. Além disso, os primeiros 16 bytes são o cabeçalho, incluindo o código do sistema (0x03E8 = 1000) no deslocamento 14-15.

Eu também me pergunto se o código-fonte está disponível em algumas fontes antigas do NeXT ou na versão do Windows que existia, mas onde eu encontraria isso? (Nota: Eu fui direcionado para a fonte GNUstep ("core.20131003.tar.bz2"), na qual encontrei sua fonte NSUnarchiver, mas esse código, aparentemente de 1998, usa sua própria codificação, o que não está entendendo este "streamtyped" "codificação.)

questionAnswers(6)

yourAnswerToTheQuestion