Added support for cp932 (Shift-JIS) conversion
[deark.git] / modules / xface.c
blobd46bd29c4368f71379f0c29c106cfb467bfbfc9d
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 // **************************************************************************
14 // X-Face format
15 // **************************************************************************
17 static int has_x_header(dbuf *f)
19 char b[8];
21 dbuf_read(f, (u8*)b, 0, 8);
22 if((b[0]=='X' || b[0]=='x') &&
23 (b[1]=='-') &&
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') &&
28 (b[6]==':') &&
29 (b[7]==' ' || b[7]=='\t'))
31 return 1;
33 return 0;
36 #include "../foreign/uncompface.h"
38 static void de_run_xface(deark *c, de_module_params *mparams)
40 uncompface_main(c);
43 static int de_identify_xface(deark *c)
45 int has_ext;
46 int has_hdr;
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;
52 if(has_ext) return 5;
53 return 0;
56 void de_module_xface(deark *c, struct deark_module_info *mi)
58 mi->id = "xface";
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 {
69 de_bitmap *img;
70 i64 imgpos_x, imgpos_y;
72 i64 input_parse_pos;
73 size_t tokenbuf_strlen;
74 int token_numdigits;
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)
97 int retval = 0;
98 u8 ch;
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++);
107 // Skip whitespace
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
110 // end eventually.)
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) {
118 goto done;
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) {
125 goto done;
128 // Skip whitespace
129 while(cfi_is_whitespace(ch)) {
130 ch = de_getbyte(cfictx->input_parse_pos++);
133 // Check for the terminating comma
134 if(ch != ',') {
135 goto done;
138 retval = 1;
139 done:
140 if(!retval) {
141 de_err(c, "Error parsing Compface format");
143 return retval;
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)
151 int ret;
153 ret = cfi_get_next_token_lowlevel(c, cfictx);
154 if(!ret) return 0;
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;
163 else
164 cfictx->token_numdigits = 4;
166 cfictx->token_val = (unsigned int)de_strtoll((const char*)cfictx->tokenbuf, NULL, 0);
167 return 1;
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) {
176 cfictx->imgpos_x=0;
177 cfictx->imgpos_y++;
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);
189 while(1) {
190 if(image_bytes_processed>=(XFACE_WIDTH*XFACE_HEIGHT)/8) break;
191 if(!cfi_get_next_token(c, cfictx)) {
192 goto done;
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);
205 done:
206 de_bitmap_destroy(cfictx->img);
207 de_free(c, cfictx);
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;