1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 #include <deark-config.h>
6 #include <deark-private.h>
7 DE_DECLARE_MODULE(de_module_ar
);
9 typedef struct localctx_struct
{
10 i64 extended_name_table_pos
; // 0=none
11 i64 extended_name_table_size
;
14 static int do_ar_item(deark
*c
, lctx
*d
, i64 pos1
, i64
*p_item_len
)
18 de_ucstring
*rawname_ucstring
= NULL
;
19 de_ucstring
*filename_ucstring
= NULL
;
20 char timestamp_buf
[64];
33 de_dbg(c
, "archive member at %d", (int)pos1
);
36 fi
= de_finfo_create(c
);
38 de_read((u8
*)name_orig
, pos1
, 16);
39 // Strip trailing spaces
41 for(k
=15; k
>=0; k
--) {
42 if(name_orig
[k
]!=' ') break;
45 name_orig_len
= de_strlen(name_orig
);
47 rawname_ucstring
= ucstring_create(c
);
48 ucstring_append_bytes(rawname_ucstring
, (const u8
*)name_orig
, name_orig_len
, 0, DE_ENCODING_UTF8
);
50 de_dbg(c
, "member raw name: \"%s\"", ucstring_getpsz(rawname_ucstring
));
52 (void)dbuf_read_ascii_number(c
->infile
, pos1
+16, 12, 10, &mod_time
);
53 de_unix_time_to_timestamp(mod_time
, &fi
->timestamp
[DE_TIMESTAMPIDX_MODIFY
], 0x1);
54 de_timestamp_to_string(&fi
->timestamp
[DE_TIMESTAMPIDX_MODIFY
], timestamp_buf
, sizeof(timestamp_buf
), 0);
55 de_dbg(c
, "mod time: %" I64_FMT
" (%s)", mod_time
, timestamp_buf
);
57 (void)dbuf_read_ascii_number(c
->infile
, pos1
+40, 8, 8, &file_mode
);
58 de_dbg(c
, "file mode: octal(%06o)", (int)file_mode
);
59 if((file_mode
& 0111)!=0) {
60 fi
->mode_flags
|= DE_MODEFLAG_EXE
;
63 fi
->mode_flags
|= DE_MODEFLAG_NONEXE
;
66 file_offset
= pos1
+ 60;
67 (void)dbuf_read_ascii_number(c
->infile
, pos1
+48, 10, 10, &file_size
);
68 de_dbg(c
, "member data at %d, size: %d",
69 (int)file_offset
, (int)file_size
);
72 de_warn(c
, "Missing filename");
76 else if(!de_strcmp(name_orig
, "/")) {
77 de_dbg(c
, "symbol table (ignoring)");
81 else if(!de_strcmp(name_orig
, "//")) {
82 de_dbg(c
, "extended name table");
83 d
->extended_name_table_pos
= file_offset
;
84 d
->extended_name_table_size
= file_size
;
88 else if(name_orig
[0]=='/' && name_orig
[1]>='0' && name_orig
[1]<='9') {
89 if(d
->extended_name_table_pos
==0) {
90 de_err(c
, "Missing extended name table");
94 (void)dbuf_read_ascii_number(c
->infile
, pos1
+1, 15, 10, &name_offset
);
95 if(name_offset
>= d
->extended_name_table_size
) {
99 ret
= dbuf_search_byte(c
->infile
, '\x0a', d
->extended_name_table_pos
+name_offset
,
100 d
->extended_name_table_size
-name_offset
, &foundpos
);
102 ext_name_len
= foundpos
- (d
->extended_name_table_pos
+name_offset
);
104 // TODO: Consolidate the filename extraction code.
105 if(ext_name_len
>0 && de_getbyte(d
->extended_name_table_pos
+name_offset
+ext_name_len
-1)=='/') {
106 // Strip trailing slash.
110 filename_ucstring
= ucstring_create(c
);
111 dbuf_read_to_ucstring(c
->infile
, d
->extended_name_table_pos
+name_offset
,
112 ext_name_len
, filename_ucstring
, 0, DE_ENCODING_UTF8
);
114 de_dbg(c
, "extended filename: \"%s\"", ucstring_getpsz(filename_ucstring
));
116 de_finfo_set_name_from_ucstring(c
, fi
, filename_ucstring
, 0);
117 fi
->original_filename_flag
= 1;
119 else if(name_orig
[0]=='/') {
120 de_warn(c
, "Unsupported extension: \"%s\"", ucstring_getpsz(rawname_ucstring
));
127 filename_ucstring
= ucstring_create(c
);
129 adjusted_len
= name_orig_len
;
130 if(name_orig
[name_orig_len
-1]=='/') {
131 // Filenames are often terminated with a '/', to allow for
132 // trailing spaces. Strip off the '/'.
135 ucstring_append_bytes(filename_ucstring
, (u8
*)name_orig
, adjusted_len
,
136 0, DE_ENCODING_UTF8
);
138 de_dbg(c
, "filename: \"%s\"", ucstring_getpsz(filename_ucstring
));
139 de_finfo_set_name_from_ucstring(c
, fi
, filename_ucstring
, 0);
140 fi
->original_filename_flag
= 1;
143 dbuf_create_file_from_slice(c
->infile
, file_offset
, file_size
, NULL
, fi
, 0);
147 *p_item_len
= 60 + file_size
;
148 if(*p_item_len
% 2) (*p_item_len
)++; // padding byte
149 de_dbg_indent(c
, -1);
150 de_finfo_destroy(c
, fi
);
151 ucstring_destroy(rawname_ucstring
);
152 ucstring_destroy(filename_ucstring
);
156 static void de_run_ar(deark
*c
, de_module_params
*mparams
)
163 d
= de_malloc(c
, sizeof(lctx
));
167 if(pos
>= c
->infile
->len
) break;
168 ret
= do_ar_item(c
, d
, pos
, &item_len
);
169 if(!ret
|| item_len
<1) break;
176 static int de_identify_ar(deark
*c
)
178 if(!dbuf_memcmp(c
->infile
, 0, "!<arch>\x0a", 8))
183 void de_module_ar(deark
*c
, struct deark_module_info
*mi
)
186 mi
->desc
= "ar archive";
187 mi
->run_fn
= de_run_ar
;
188 mi
->identify_fn
= de_identify_ar
;