Skip to content

Commit

Permalink
Universal typeOf
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderOMara committed Jan 19, 2025
1 parent af31749 commit d67f698
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
7 changes: 7 additions & 0 deletions macho/universal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { assertEquals } from '@std/assert';
import { fixtureMacho, fixtureMachos } from '../spec/fixture.ts';
import type { Architecture } from './architecture.ts';
import { Universal } from './universal.ts';
import { MH_DYLIB, MH_EXECUTE } from '../const.ts';

const fixtures = fixtureMachos();

Expand Down Expand Up @@ -30,5 +31,11 @@ for (const { kind, arch, file, archs } of fixtures) {
assertEquals(architectures.size, archs.size);
uni.architectures(architectures);
assertEquals(architectures.size, archs.size);

if (/\.dylib$|\.framework\//i.test(file)) {
assertEquals(await Universal.typeOf(blob), MH_DYLIB);
} else {
assertEquals(await Universal.typeOf(blob), MH_EXECUTE);
}
});
}
51 changes: 51 additions & 0 deletions macho/universal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,55 @@ export class Universal {
public isSuspicious(): boolean {
return this.mSuspicious;
}

/**
* Guess type of file.
*
* @param reader Reader object.
* @returns Zero if not a valid Mach-O or Universal.
*/
public static async typeOf(reader: Reader): Promise<number> {
let data = await reader.slice(0, MachHeader.BYTE_LENGTH).arrayBuffer();
if (data.byteLength !== MachHeader.BYTE_LENGTH) {
return 0;
}
let header = new MachHeader(data);
let arch1;
for (let tries = 3; tries--;) {
switch (header.magic) {
case MH_CIGAM:
case MH_CIGAM_64:
header = new MachHeader(data, 0, !header.littleEndian);
// Falls through.
case MH_MAGIC:
case MH_MAGIC_64: {
return header.filetype;
}
case FAT_CIGAM:
arch1 = new FatArch(
data,
FatHeader.BYTE_LENGTH,
!header.littleEndian,
);
// Falls through.
case FAT_MAGIC: {
arch1 ??= new FatArch(data, FatHeader.BYTE_LENGTH);
const { offset } = arch1;
// deno-lint-ignore no-await-in-loop
data = await reader
.slice(offset, offset + header.byteLength)
.arrayBuffer();
if (data.byteLength !== header.byteLength) {
return 0;
}
header = new MachHeader(data, 0, arch1.littleEndian);
continue;
}
default: {
return 0;
}
}
}
return 0;
}
}

0 comments on commit d67f698

Please sign in to comment.