iccprofile: Decode 'dict' data type
[deark.git] / modules / ar.c
blob110dcb3c271169a9b5e092683db6b965034dc640
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;
12 } lctx;
14 static int do_ar_item(deark *c, lctx *d, i64 pos1, i64 *p_item_len)
16 char name_orig[17];
17 size_t name_orig_len;
18 de_ucstring *rawname_ucstring = NULL;
19 de_ucstring *filename_ucstring = NULL;
20 char timestamp_buf[64];
21 i64 mod_time;
22 i64 file_mode;
23 i64 file_offset;
24 i64 file_size = 0;
25 i64 name_offset;
26 de_finfo *fi = NULL;
27 i64 k;
28 int retval = 0;
29 int ret;
30 i64 foundpos;
31 i64 ext_name_len;
33 de_dbg(c, "archive member at %d", (int)pos1);
34 de_dbg_indent(c, 1);
36 fi = de_finfo_create(c);
38 de_read((u8*)name_orig, pos1, 16);
39 // Strip trailing spaces
40 name_orig[16] = '\0';
41 for(k=15; k>=0; k--) {
42 if(name_orig[k]!=' ') break;
43 name_orig[k]='\0';
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;
62 else {
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);
71 if(name_orig_len<1) {
72 de_warn(c, "Missing filename");
73 retval = 1;
74 goto done;
76 else if(!de_strcmp(name_orig, "/")) {
77 de_dbg(c, "symbol table (ignoring)");
78 retval = 1;
79 goto done;
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;
85 retval = 1;
86 goto done;
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");
91 goto done;
94 (void)dbuf_read_ascii_number(c->infile, pos1+1, 15, 10, &name_offset);
95 if(name_offset >= d->extended_name_table_size) {
96 goto done;
99 ret = dbuf_search_byte(c->infile, '\x0a', d->extended_name_table_pos+name_offset,
100 d->extended_name_table_size-name_offset, &foundpos);
101 if(!ret) goto done;
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.
107 ext_name_len--;
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));
121 retval = 1;
122 goto done;
124 else {
125 i64 adjusted_len;
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 '/'.
133 adjusted_len--;
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);
145 retval = 1;
146 done:
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);
153 return retval;
156 static void de_run_ar(deark *c, de_module_params *mparams)
158 lctx *d = NULL;
159 i64 pos;
160 i64 item_len;
161 int ret;
163 d = de_malloc(c, sizeof(lctx));
165 pos = 8;
166 while(1) {
167 if(pos >= c->infile->len) break;
168 ret = do_ar_item(c, d, pos, &item_len);
169 if(!ret || item_len<1) break;
170 pos += item_len;
173 de_free(c, d);
176 static int de_identify_ar(deark *c)
178 if(!dbuf_memcmp(c->infile, 0, "!<arch>\x0a", 8))
179 return 100;
180 return 0;
183 void de_module_ar(deark *c, struct deark_module_info *mi)
185 mi->id = "ar";
186 mi->desc = "ar archive";
187 mi->run_fn = de_run_ar;
188 mi->identify_fn = de_identify_ar;