Skip to content

Commit a244e95

Browse files
Added makeCFDictionaryFrom
1 parent d2e28d0 commit a244e95

3 files changed

Lines changed: 113 additions & 0 deletions

File tree

Security/cfutilities.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { assertEquals, assertInstanceOf } from '@std/assert';
2+
import { encodeBinary, encodeXml, PLArray, PLDictionary } from '@hqtsm/plist';
3+
import { assertThrowsCFError } from '../spec/assert.ts';
4+
import { makeCFDictionaryFrom } from './cfutilities.ts';
5+
6+
Deno.test('makeCFDictionaryFrom: view', () => {
7+
const data = encodeXml(new PLDictionary());
8+
const dict = makeCFDictionaryFrom(data);
9+
assertInstanceOf(dict, PLDictionary);
10+
});
11+
12+
Deno.test('makeCFDictionaryFrom: pointer', () => {
13+
const data = encodeBinary(new PLDictionary());
14+
const view = new Uint8Array(data.byteLength + 2);
15+
view.set(data, 1);
16+
const dict = makeCFDictionaryFrom(view.subarray(1), data.byteLength);
17+
assertInstanceOf(dict, PLDictionary);
18+
});
19+
20+
Deno.test('makeCFDictionaryFrom: null', () => {
21+
const dict = makeCFDictionaryFrom(null);
22+
assertEquals(dict, null);
23+
});
24+
25+
Deno.test('makeCFDictionaryFrom: array', () => {
26+
const data = encodeXml(new PLArray());
27+
assertThrowsCFError(() => makeCFDictionaryFrom(data));
28+
});
29+
30+
Deno.test('makeCFDictionaryFrom: bad', () => {
31+
const invalid = new TextEncoder().encode('<badplist>');
32+
assertEquals(makeCFDictionaryFrom(invalid), null);
33+
});

Security/cfutilities.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import type { ArrayBufferPointer } from '@hqtsm/struct';
2+
import { decode, type DecodeXmlDecoder, PLDictionary } from '@hqtsm/plist';
3+
import type { size_t } from '../libc/stddef.ts';
4+
import { pointerBytes, viewBytes } from '../util/memory.ts';
5+
import { CFError } from './errors.ts';
6+
7+
/**
8+
* Decode plist dictionary from buffer.
9+
*
10+
* @param data Data buffer.
11+
* @param decoder Optional XML decoder for obscure encoding.
12+
* @returns Dictionary or null.
13+
*/
14+
export function makeCFDictionaryFrom(
15+
data: ArrayBufferLike | ArrayBufferView | null,
16+
decoder?: DecodeXmlDecoder,
17+
): PLDictionary | null;
18+
19+
/**
20+
* Decode plist dictionary from pointer.
21+
*
22+
* @param data Data pointer.
23+
* @param length Data length in bytes.
24+
* @param decoder Optional XML decoder for obscure encoding.
25+
* @returns Dictionary or null.
26+
*/
27+
export function makeCFDictionaryFrom(
28+
data: ArrayBufferPointer | null,
29+
length: size_t,
30+
decoder?: DecodeXmlDecoder,
31+
): PLDictionary | null;
32+
33+
/**
34+
* Decode plist dictionary from buffer or pointer.
35+
*
36+
* @param data Data buffer or pointer.
37+
* @param length Data length in bytes, or optional XML decoder.
38+
* @param decoder Optional XML decoder for obscure encoding.
39+
* @returns Dictionary or null.
40+
*/
41+
export function makeCFDictionaryFrom(
42+
data: ArrayBufferLike | ArrayBufferView | ArrayBufferPointer | null,
43+
length?: size_t | DecodeXmlDecoder,
44+
decoder?: DecodeXmlDecoder,
45+
): PLDictionary | null {
46+
if (data) {
47+
let d;
48+
if (typeof length === 'number') {
49+
d = pointerBytes(data, length);
50+
} else {
51+
decoder = length;
52+
d = viewBytes(data as ArrayBufferLike | ArrayBufferView);
53+
}
54+
let plist = null;
55+
try {
56+
// Attempt decode using Mac CF constraints.
57+
({ plist } = decode(d, {
58+
binary: {
59+
int64: true,
60+
stringKeys: true,
61+
},
62+
xml: {
63+
int64: true,
64+
decoder,
65+
},
66+
openstep: {
67+
utf16le: true,
68+
},
69+
}));
70+
} catch {
71+
// Ignore.
72+
}
73+
if (plist && !PLDictionary.is(plist)) {
74+
CFError.throwMe();
75+
}
76+
return plist;
77+
}
78+
return null;
79+
}

Security/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './blob.ts';
2+
export * from './cfutilities.ts';
23
export * from './CSCommon.ts';
34
export * from './CSCommonPriv.ts';
45
export * from './endian.ts';

0 commit comments

Comments
 (0)