Skip to content

Instantly share code, notes, and snippets.

@alberthdev
Last active October 4, 2021 04:15
Show Gist options
  • Save alberthdev/ae013060a5d51b754e43d46fb16cba8f to your computer and use it in GitHub Desktop.
Save alberthdev/ae013060a5d51b754e43d46fb16cba8f to your computer and use it in GitHub Desktop.
010 editor template - AR .a, .lib, .ar, .deb with Microsoft / Visual Studio (MSVC) specific parsing
//------------------------------------------------
//--- 010 Editor v11.0 Binary Template
//
// File: AR.bt
// Authors: SweetScape Software + Albert Huang (GitHub @alberthdev)
// Version: 1.1
// Purpose: Parse ar archives used for .a, .lib,
// .ar and .deb files.
// Category: Archive
// File Mask: *.a,*.lib,*.ar,*.deb
// ID Bytes: 21 3C 61 72 63 68 3E 0A //!<arch>\n
// History:
// 1.1 2021-10-05 Albert Huang: Support for MSVC specific structures + LUTs.
// 1.0 2020-10-23 SweetScape Software: Initial version.
//------------------------------------------------
// MSFT shenanigans
local int isMsft = 0;
typedef struct {
char name[];
} nullTermString <read=ReadNullTermString>;
string ReadNullTermString( struct nullTermString &f )
{
return f.name;
}
typedef struct {
BigEndian();
ulong numSymbols;
ulong symOffsets[numSymbols];
LittleEndian();
nullTermString symbols[numSymbols] <optimize=false>;
} ar_msft_first_archive_linker_member;
typedef struct {
ulong numMembers;
ulong memberOffsets[numMembers];
ulong numSymbols;
short symOffsets[numSymbols];
nullTermString publicSymbols[numSymbols] <optimize=false>;
} ar_msft_second_archive_linker_member;
local int readingSecond = 0;
local int64 longNamesOffset = 0;
local int64 longNamesSize = 0;
local int64 longNameReqIdx = 0;
string getLongNameByIdx(int64 idx) {
local int64 curIdx = 0;
local int64 parsedSize = longNamesSize;
local string longName = ReadString(longNamesOffset + (longNamesSize - parsedSize));
while ((parsedSize > 0) && (curIdx <= idx)) {
longName = ReadString(longNamesOffset + (longNamesSize - parsedSize));
parsedSize -= (Strlen(longName) + 1);
curIdx++;
}
return longName;
}
// File record
typedef struct {
// Define header
SetBackColor( cLtYellow );
char fileName[16];
char modification_timestamp[12];
char ownerID[6];
char groupID[6];
char fileMode[8];
char fileSize[10];
char endMarker[2];
SetBackColor( cNone );
// Define file data
if( endMarker == "\x60\x0a" )
{
local int64 size;
SScanf( fileSize, "%Ld", size );
if ((fileName == "/ ") && (size > 0)) {
isMsft = 1;
if (readingSecond == 0) {
ar_msft_first_archive_linker_member member;
readingSecond = 1;
} else {
ar_msft_second_archive_linker_member member;
}
} else if ((fileName == "// ") && (size > 0)) {
local int64 parsedSize = size;
local int64 numLongNames = 0;
local string longName = "";
longNamesSize = size;
longNamesOffset = FTell();
while (parsedSize > 0) {
longName = ReadString(longNamesOffset + (size - parsedSize));
parsedSize -= (Strlen(longName) + 1);
numLongNames++;
}
if( size & 1 ) numLongNames--;
nullTermString longNames[numLongNames] <optimize=false>;
} else {
local int matchLongNameReqd = RegExMatch(fileName, "/\\d+\\s+");
if ((matchLongNameReqd == 1) && (size > 0)) {
local int64 usinglongNameIdx = longNameReqIdx;
longNameReqIdx++;
local string realFilename = getLongNameByIdx(usinglongNameIdx);
}
if( size > 0 )
uchar data[size];
}
// Add padding byte
if( size & 1 )
uchar padding <bgcolor=cLtGray>;
}
} ar_file <read=ReadArFile>;
// Display filename beside ar_file struct
string ReadArFile( struct ar_file &f )
{
if (isMsft) {
if (f.fileName == "/ ") {
return "MSFT Archive Linker Member";
} else if (f.fileName == "// ") {
return "MSFT Long Names";
} else if (exists(f.matchLongNameReqd) && (f.matchLongNameReqd == 1)) {
return f.realFilename + " size=" + f.fileSize + " (using long name; real name: " + f.fileName + ")";
} else {
// trim trailing slash
local string fileNameWithoutSlash = "";
Strcpy(fileNameWithoutSlash, f.fileName);
fileNameWithoutSlash = StrDel(fileNameWithoutSlash, Strchr(fileNameWithoutSlash, '/'), 1);
return fileNameWithoutSlash + " ns size=" + f.fileSize;
}
}
return f.fileName + " size=" + f.fileSize;
}
// Read the file signature
char signature[8] <bgcolor=cLtPurple>;
if( signature != "!<arch>\n" )
{
Warning( "File is not a valid archive. Template stopped." );
return -1;
}
// Read file records
while( !FEof() )
{
ar_file file;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment