1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
5 // X-Face, and "Compface intermediate format"
7 #include <deark-config.h>
8 #include <deark-private.h>
10 DE_DECLARE_MODULE(de_module_xface
);
11 DE_DECLARE_MODULE(de_module_compfacei
);
13 // **************************************************************************
15 // **************************************************************************
17 static int has_x_header(dbuf
*f
)
21 dbuf_read(f
, (u8
*)b
, 0, 8);
22 if((b
[0]=='X' || b
[0]=='x') &&
24 (b
[2]=='F' || b
[2]=='f') &&
25 (b
[3]=='A' || b
[3]=='a') &&
26 (b
[4]=='C' || b
[4]=='c') &&
27 (b
[5]=='E' || b
[5]=='e') &&
29 (b
[7]==' ' || b
[7]=='\t'))
36 #include "../foreign/uncompface.h"
38 static void de_run_xface(deark
*c
, de_module_params
*mparams
)
43 static int de_identify_xface(deark
*c
)
48 has_hdr
= has_x_header(c
->infile
);
49 has_ext
= de_input_file_has_ext(c
, "xface");
50 if(has_hdr
&& has_ext
) return 100;
51 if(has_hdr
) return 80;
56 void de_module_xface(deark
*c
, struct deark_module_info
*mi
)
59 mi
->desc
= "X-Face icon/avatar";
60 mi
->run_fn
= de_run_xface
;
61 mi
->identify_fn
= de_identify_xface
;
64 // **************************************************************************
65 // Compface intermediate format
66 // **************************************************************************
68 struct compfacei_ctx
{
70 i64 imgpos_x
, imgpos_y
;
73 size_t tokenbuf_strlen
;
75 unsigned int token_val
;
76 #define CFI_TOKENBUFLEN 32
77 u8 tokenbuf
[CFI_TOKENBUFLEN
];
80 static int cfi_is_whitespace(u8 ch
)
82 return (ch
==9 || ch
==10 || ch
==13 || ch
==' ');
84 static int cfi_is_alnum(u8 ch
)
86 return ((ch
>='0' && ch
<='9') ||
87 (ch
>='A' && ch
<='Z') ||
88 (ch
>='a' && ch
<='z'));
91 // On success, returns nonzero and
92 // - Writes a NUL-terminated string to cfictx->tokenbuf
93 // - Sets cfictx->tokenbuf_strlen
94 // - Updates cfictx->input_parse_pos
95 static int cfi_get_next_token_lowlevel(deark
*c
, struct compfacei_ctx
*cfictx
)
100 cfictx
->tokenbuf_strlen
= 0;
102 // Read [whitespace][1 or more alphanumerics][whitespace][comma].
103 // Save the alphanumerics in tokenbuf.
105 ch
= de_getbyte(cfictx
->input_parse_pos
++);
108 // (Note that de_getbyte returns NUL bytes after the end of file,
109 // and NUL doesn't count as whitespace, so this loop will definitely
111 while(cfi_is_whitespace(ch
)) {
112 ch
= de_getbyte(cfictx
->input_parse_pos
++);
115 // Copy alphanumerics to tokenbuf
116 while(cfi_is_alnum(ch
)) {
117 if(cfictx
->tokenbuf_strlen
>= CFI_TOKENBUFLEN
-1) {
120 cfictx
->tokenbuf
[cfictx
->tokenbuf_strlen
++] = ch
;
121 ch
= de_getbyte(cfictx
->input_parse_pos
++);
123 cfictx
->tokenbuf
[cfictx
->tokenbuf_strlen
] = '\0';
124 if(cfictx
->tokenbuf_strlen
<4) {
129 while(cfi_is_whitespace(ch
)) {
130 ch
= de_getbyte(cfictx
->input_parse_pos
++);
133 // Check for the terminating comma
141 de_err(c
, "Error parsing Compface format");
146 // On success, returns nonzero and
147 // - Sets cfictx->token_val, cfictx->token_numdigits
148 // - [Does whatever cfi_get_next_token_lowlevel() does]
149 static int cfi_get_next_token(deark
*c
, struct compfacei_ctx
*cfictx
)
153 ret
= cfi_get_next_token_lowlevel(c
, cfictx
);
156 // TODO: Make sure the format is correct.
157 // Should be "0[Xx][2 or 4 hex digits]".
159 // Most files have two bytes per token (0X????,0X????...), but some
160 // have just one (0X??,0X??,...)
161 if(cfictx
->tokenbuf_strlen
<=4)
162 cfictx
->token_numdigits
= 2;
164 cfictx
->token_numdigits
= 4;
166 cfictx
->token_val
= (unsigned int)de_strtoll((const char*)cfictx
->tokenbuf
, NULL
, 0);
170 static void cfi_set_image_byte(deark
*c
, struct compfacei_ctx
*cfictx
, u8 ch
)
172 de_unpack_pixels_bilevel_from_byte(cfictx
->img
, cfictx
->imgpos_x
, cfictx
->imgpos_y
,
173 ch
, 8, DE_CVTF_WHITEISZERO
);
174 cfictx
->imgpos_x
+= 8;
175 if(cfictx
->imgpos_x
>=XFACE_WIDTH
) {
181 static void de_run_compfacei(deark
*c
, de_module_params
*mparams
)
183 i64 image_bytes_processed
= 0;
184 struct compfacei_ctx
*cfictx
= NULL
;
186 cfictx
= de_malloc(c
, sizeof(struct compfacei_ctx
));
187 cfictx
->img
= de_bitmap_create(c
, XFACE_WIDTH
, XFACE_HEIGHT
, 1);
190 if(image_bytes_processed
>=(XFACE_WIDTH
*XFACE_HEIGHT
)/8) break;
191 if(!cfi_get_next_token(c
, cfictx
)) {
194 if(cfictx
->token_numdigits
==2) {
195 cfi_set_image_byte(c
, cfictx
, (u8
)cfictx
->token_val
);
197 else { // Assume numdigits==4
198 cfi_set_image_byte(c
, cfictx
, (u8
)(cfictx
->token_val
>>8));
199 cfi_set_image_byte(c
, cfictx
, (u8
)(cfictx
->token_val
&0xff));
201 image_bytes_processed
+= cfictx
->token_numdigits
/2;
204 de_bitmap_write_to_file_finfo(cfictx
->img
, NULL
, DE_CREATEFLAG_IS_BWIMG
);
206 de_bitmap_destroy(cfictx
->img
);
210 void de_module_compfacei(deark
*c
, struct deark_module_info
*mi
)
212 mi
->id
= "compfacei";
213 mi
->desc
= "Compface intermediate format";
214 mi
->run_fn
= de_run_compfacei
;