# `pytypedstream`
A pure Python, cross-platform library/tool for reading Mac OS X and NeXTSTEP typedstream files.
The typedstream format is a serialization format for C and Objective-C data structures.
It is used by Apple's implementation of the Foundation classes [`NSArchiver`](https://developer.apple.com/documentation/foundation/nsarchiver?language=objc) and [`NSUnarchiver`](https://developer.apple.com/documentation/foundation/nsunarchiver?language=objc),
and is based on the data format originally used by NeXTSTEP's `NXTypedStream` APIs.
The `NSArchiver` and `NSUnarchiver` classes and the typedstream format are superseded by [`NSKeyedArchiver`](https://developer.apple.com/documentation/foundation/nskeyedarchiver?language=objc) and [`NSKeyedUnarchiver`](https://developer.apple.com/documentation/foundation/nskeyedunarchiver?language=objc),
which use binary property lists for serialization.
`NSArchiver` and `NSUnarchiver` are deprecated since macOS 10.13 (but still available as of macOS 10.15)
and have never been available for application developers on other Apple platforms (iOS, watchOS, tvOS).
Despite this,
the typedstream data format is still used by some macOS components and applications,
such as the Stickies and Grapher applications.
**Note:**
The typedstream data format is undocumented and specific to the Mac OS X implementation of `NSArchiver`/`NSUnarchiver`.
Other Objective-C/Foundation implementations may also provide `NSArchiver`/`NSUnarchiver`,
but might not use the same data format.
For example,
GNUstep's `NSArchiver`/`NSUnarchiver` implementations use a completely different format,
with a `GNUstep archive` signature string.
## Features
* Pure Python, cross-platform - no native Mac APIs are used.
* Provides both a Python API (for use in programs and in the REPL)
and a command-line tool (for quick inspection of files from the command line).
* Typedstream data is automatically parsed and translated to appropriate Python data types.
* Standard Foundation objects and structures are recognized and translated to dedicated Python objects with properly named attributes.
* Users of the library can create custom Python classes
to decode and represent classes and structure types that aren't supported by default.
* Unrecognized objects and structures are still parsed,
but are represented as generic objects whose contents can only be accessed by index
(because typedstream data doesn't include field names).
* Unlike with the Objective-C [`NSCoder`](https://developer.apple.com/documentation/foundation/nscoder?language=objc) API,
values can be read without knowing their exact type beforehand.
However, when the expected types in a certain context are known,
the types in the typedstream are checked to make sure that they match.
* In addition to the high-level NSUnarchiver-style decoder,
an iterative stream/event-based reader is provided,
which can be used (to some extent)
to read large typedstreams without storing them fully in memory.
## Requirements
Python 3.6 or later.
No other libraries are required,
except on older Python versions:
* [`contextvars`](https://pypi.org/project/contextvars/) is needed before Python 3.7
* [`typing_extensions`](https://pypi.org/project/typing-extensions/) is needed before Python 3.8
These libraries are declared as [platform-specific dependencies](https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#platform-specific-dependencies)
and will be installed automatically as needed.
## Installation
`pytypedstream` is available [on PyPI](https://pypi.org/project/pytypedstream/) and can be installed using `pip`:
```sh
$ python3 -m pip install pytypedstream
```
Alternatively you can download the source code manually,
and run this command in the source code directory to install it:
```sh
python3 -m pip install .
```
## Examples
### Simple example
```python-repl
>>> import typedstream
>>> data = b"\x04\x0bstreamtyped\x81\xe8\x03\x84\x01@\x84\x84\x84\x08NSString\x01\x84\x84\x08NSObject\x00\x85\x84\x01+\x0cstring value\x86"
>>> typedstream.unarchive_from_data(data)
NSString('string value')
>>> _.value
'string value'
```
### Low-level stream reading
```python-repl
>>> from typedstream.stream import TypedStreamReader
>>> ts = TypedStreamReader.from_data(data)
>>> for event in ts:
... print(event)
typedstream.stream.BeginTypedValues([b"@"])
typedstream.stream.BeginObject()
typedstream.stream.SingleClass(name=b'NSString', version=1)
...
```
### Command-line interface
Full high-level decoding:
```sh
$ pytypedstream decode StickiesDatabase
NSMutableArray, 2 elements:
object of class Document v1, extends NSObject v0, contents:
NSMutableData(b"rtfd\x00\x00\x00\x00[...]")
0
struct ?:
struct ?:
8.0
224.0
struct ?:
442.0
251.0
0
<NSDate: 2003-03-05 02:13:27.454397+00:00>
<NSDate: 2007-09-26 14:51:07.340778+00:00>
[...]
```
Low-level stream-based reading/dumping:
```sh
$ pytypedstream read StickiesDatabase
streamer version 4, byte order little, system version 1000
begin typed values (types [b'@'])
begin literal object (#0)
class NSMutableArray v0 (#1)
class NSArray v0 (#2)
class NSObject v0 (#3)
None
begin typed values (types [b'i'])
2
end typed values
begin typed values (types [b'@'])
begin literal object (#4)
class Document v1 (#5)
<reference to class #3>
[...]
end literal object
end typed values
[...]
end literal object
end typed values
```
## Limitations
Many common classes and structure types from Foundation, AppKit, and other standard frameworks are not supported yet.
How each class encodes its data in a typedstream is almost never documented,
and the relevant Objective-C implementation source code is normally not available,
so usually the only way to find out the meaning of the values in a typedstream is through experimentation and educated guessing.
Writing typedstream data is not supported at all.
## License
Copyright (C) 2020 dgelessus
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
## Changelog
### Version 0.1.0
* Initial version.
Raw data
{
"_id": null,
"home_page": "https://github.com/dgelessus/python-typedstream",
"name": "pytypedstream",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "typedstream,streamtyped,nsarchiver,nsunarchiver,nxtypedstream,mac,macosx,osx,macos,nextstep",
"author": "dgelessus",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/47/d2/4632904c21890b1f397e6e9ef823b216f6f0a3a767897b092f592f16b90e/pytypedstream-0.1.0.tar.gz",
"platform": null,
"description": "# `pytypedstream`\n\nA pure Python, cross-platform library/tool for reading Mac OS X and NeXTSTEP typedstream files.\n\nThe typedstream format is a serialization format for C and Objective-C data structures.\nIt is used by Apple's implementation of the Foundation classes [`NSArchiver`](https://developer.apple.com/documentation/foundation/nsarchiver?language=objc) and [`NSUnarchiver`](https://developer.apple.com/documentation/foundation/nsunarchiver?language=objc),\nand is based on the data format originally used by NeXTSTEP's `NXTypedStream` APIs.\n\nThe `NSArchiver` and `NSUnarchiver` classes and the typedstream format are superseded by [`NSKeyedArchiver`](https://developer.apple.com/documentation/foundation/nskeyedarchiver?language=objc) and [`NSKeyedUnarchiver`](https://developer.apple.com/documentation/foundation/nskeyedunarchiver?language=objc),\nwhich use binary property lists for serialization.\n`NSArchiver` and `NSUnarchiver` are deprecated since macOS 10.13 (but still available as of macOS 10.15)\nand have never been available for application developers on other Apple platforms (iOS, watchOS, tvOS).\nDespite this,\nthe typedstream data format is still used by some macOS components and applications,\nsuch as the Stickies and Grapher applications.\n\n**Note:**\nThe typedstream data format is undocumented and specific to the Mac OS X implementation of `NSArchiver`/`NSUnarchiver`.\nOther Objective-C/Foundation implementations may also provide `NSArchiver`/`NSUnarchiver`,\nbut might not use the same data format.\nFor example,\nGNUstep's `NSArchiver`/`NSUnarchiver` implementations use a completely different format,\nwith a `GNUstep archive` signature string.\n\n## Features\n\n* Pure Python, cross-platform - no native Mac APIs are used.\n* Provides both a Python API (for use in programs and in the REPL)\n and a command-line tool (for quick inspection of files from the command line).\n* Typedstream data is automatically parsed and translated to appropriate Python data types.\n\n * Standard Foundation objects and structures are recognized and translated to dedicated Python objects with properly named attributes.\n * Users of the library can create custom Python classes\n to decode and represent classes and structure types that aren't supported by default.\n * Unrecognized objects and structures are still parsed,\n but are represented as generic objects whose contents can only be accessed by index\n (because typedstream data doesn't include field names).\n\n* Unlike with the Objective-C [`NSCoder`](https://developer.apple.com/documentation/foundation/nscoder?language=objc) API,\n values can be read without knowing their exact type beforehand.\n However, when the expected types in a certain context are known,\n the types in the typedstream are checked to make sure that they match.\n* In addition to the high-level NSUnarchiver-style decoder,\n an iterative stream/event-based reader is provided,\n which can be used (to some extent)\n to read large typedstreams without storing them fully in memory.\n\n## Requirements\n\nPython 3.6 or later.\nNo other libraries are required,\nexcept on older Python versions:\n\n* [`contextvars`](https://pypi.org/project/contextvars/) is needed before Python 3.7\n* [`typing_extensions`](https://pypi.org/project/typing-extensions/) is needed before Python 3.8\n\nThese libraries are declared as [platform-specific dependencies](https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#platform-specific-dependencies)\nand will be installed automatically as needed.\n\n## Installation\n\n`pytypedstream` is available [on PyPI](https://pypi.org/project/pytypedstream/) and can be installed using `pip`:\n\n```sh\n$ python3 -m pip install pytypedstream\n```\n\nAlternatively you can download the source code manually,\nand run this command in the source code directory to install it:\n\n```sh\npython3 -m pip install .\n```\n\n## Examples\n\n### Simple example\n\n```python-repl\n>>> import typedstream\n>>> data = b\"\\x04\\x0bstreamtyped\\x81\\xe8\\x03\\x84\\x01@\\x84\\x84\\x84\\x08NSString\\x01\\x84\\x84\\x08NSObject\\x00\\x85\\x84\\x01+\\x0cstring value\\x86\"\n>>> typedstream.unarchive_from_data(data)\nNSString('string value')\n>>> _.value\n'string value'\n```\n\n### Low-level stream reading\n\n```python-repl\n>>> from typedstream.stream import TypedStreamReader\n>>> ts = TypedStreamReader.from_data(data)\n>>> for event in ts:\n... print(event)\ntypedstream.stream.BeginTypedValues([b\"@\"])\ntypedstream.stream.BeginObject()\ntypedstream.stream.SingleClass(name=b'NSString', version=1)\n...\n```\n\n### Command-line interface\n\nFull high-level decoding:\n\n```sh\n$ pytypedstream decode StickiesDatabase\nNSMutableArray, 2 elements:\n object of class Document v1, extends NSObject v0, contents:\n NSMutableData(b\"rtfd\\x00\\x00\\x00\\x00[...]\")\n 0\n struct ?:\n struct ?:\n 8.0\n 224.0\n struct ?:\n 442.0\n 251.0\n 0\n <NSDate: 2003-03-05 02:13:27.454397+00:00>\n <NSDate: 2007-09-26 14:51:07.340778+00:00>\n [...]\n```\n\nLow-level stream-based reading/dumping:\n\n```sh\n$ pytypedstream read StickiesDatabase\nstreamer version 4, byte order little, system version 1000\n\nbegin typed values (types [b'@'])\n begin literal object (#0)\n class NSMutableArray v0 (#1)\n class NSArray v0 (#2)\n class NSObject v0 (#3)\n None\n begin typed values (types [b'i'])\n 2\n end typed values\n begin typed values (types [b'@'])\n begin literal object (#4)\n class Document v1 (#5)\n <reference to class #3>\n [...]\n end literal object\n end typed values\n [...]\n end literal object\nend typed values\n```\n\n## Limitations\n\nMany common classes and structure types from Foundation, AppKit, and other standard frameworks are not supported yet.\nHow each class encodes its data in a typedstream is almost never documented,\nand the relevant Objective-C implementation source code is normally not available,\nso usually the only way to find out the meaning of the values in a typedstream is through experimentation and educated guessing.\n\nWriting typedstream data is not supported at all.\n\n## License\n\nCopyright (C) 2020 dgelessus\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU Lesser General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU Lesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License\nalong with this program. If not, see <https://www.gnu.org/licenses/>.\n\n## Changelog\n\n### Version 0.1.0\n\n* Initial version.\n",
"bugtrack_url": null,
"license": "LGPL-3.0-or-later",
"summary": "A pure Python, cross-platform library/tool for reading Mac OS X and NeXTSTEP typedstream files",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/dgelessus/python-typedstream"
},
"split_keywords": [
"typedstream",
"streamtyped",
"nsarchiver",
"nsunarchiver",
"nxtypedstream",
"mac",
"macosx",
"osx",
"macos",
"nextstep"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0d1adbbbad9690c24506aec4571bc6613a5625b163b1607777109c9dabdbec07",
"md5": "1d9ec719a081c86e0437acad97a74e3b",
"sha256": "499920d4cb8bec8fd9d9cdd4c6312765eb418c398c10371ab1c9c0051104d278"
},
"downloads": -1,
"filename": "pytypedstream-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1d9ec719a081c86e0437acad97a74e3b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 65857,
"upload_time": "2023-06-26T23:43:32",
"upload_time_iso_8601": "2023-06-26T23:43:32.197621Z",
"url": "https://files.pythonhosted.org/packages/0d/1a/dbbbad9690c24506aec4571bc6613a5625b163b1607777109c9dabdbec07/pytypedstream-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "47d24632904c21890b1f397e6e9ef823b216f6f0a3a767897b092f592f16b90e",
"md5": "636c87eb8c3d65bfc58413c4bd133b7c",
"sha256": "c3b01790e667189966e98fcfeb638cc0541358ea7348745619fe58e3e8c9fd51"
},
"downloads": -1,
"filename": "pytypedstream-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "636c87eb8c3d65bfc58413c4bd133b7c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 84192,
"upload_time": "2023-06-26T23:43:35",
"upload_time_iso_8601": "2023-06-26T23:43:35.555474Z",
"url": "https://files.pythonhosted.org/packages/47/d2/4632904c21890b1f397e6e9ef823b216f6f0a3a767897b092f592f16b90e/pytypedstream-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-06-26 23:43:35",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "dgelessus",
"github_project": "python-typedstream",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "pytypedstream"
}