4 * Copyright 2012-2013 Samsung Electronics Co., Ltd
6 * Licensed under the Flora License, Version 1.1 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://floralicense.org/license/
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <libgen.h> //basename and dirname
26 #include <sys/types.h>
29 #include "pgen_debug.h"
30 #include "previewgen.h"
32 #define PDF_CONV_UTIL "/usr/bin/pdftoppm"
33 #define PDF_INFO_UTIL "/usr/bin/pdfinfo"
34 #define MAX_PATH_LEN 4096
35 #define IMG_MAX_SIZE (1024 * 1024 * 2) /* 2MB */
36 #define PDF_INFO_STR_MAX_SIZE 511
38 #define PDF_INFO_TEMP_FNAME "/tmp/mobileprint/pdfinfo.txt"
40 #define PDF_PX_MAX_VAL 999999
41 #define PDF_PX_VAL_MAX_STR_LEN (sizeof("999999") - 1)
44 /* Just simple stub for further development
45 TODO: use pipe output, current implementation have high security risk
47 int call_pdftoppm(const char *path, const struct pdf_preview_settings *settings)
49 char conv_cmd[] = PDF_CONV_UTIL " "; //" -f 1 -l 1 ";
50 char output_cmd[] = " > " IMG_TEMP_FILE_NAME;
52 char x_val_str[PDF_PX_VAL_MAX_STR_LEN + 1];
53 char y_val_str[PDF_PX_VAL_MAX_STR_LEN + 1];
54 char page_str[PDF_PAGE_MAX_VAL + 1];
58 PGEN_RETV_IF(path == NULL || settings == NULL, -1, "Invalid argument");
59 path_len = strnlen(path, MAX_PATH_LEN);
60 PGEN_RETV_IF(path_len <= 0 || path_len >= MAX_PATH_LEN, -1, "path_len is out of scope");
62 /* check for correct picture size */
63 if (settings->w >= PDF_PX_MAX_VAL
65 || settings->h >= PDF_PX_MAX_VAL
68 || settings->page >= PDF_PAGE_MAX_VAL) {
69 PGEN_DEBUG("call_pdftoppm(): ERROR in settings;"
70 " w = %d, h = %d, page = %d",
71 settings->w, settings->h, settings->page);
76 sprintf(x_val_str, "%d", settings->w);
78 sprintf(y_val_str, "%d", settings->h);
80 sprintf(page_str, "%d", settings->page);
83 cmd_len = (sizeof(conv_cmd) - 1)
84 + strlen("-f ") + strlen(page_str) + 1
85 + strlen("-l ") + strlen(page_str) + 1
86 + strlen("-scale-to-x ") + strlen(x_val_str) + 1
87 + strlen("-scale-to-y ") + strlen(y_val_str) + 1
88 + path_len + sizeof(output_cmd);
89 cmd_str = malloc(sizeof(char) * (cmd_len + 1));
91 PGEN_RETV_IF(cmd_str == NULL, -1, "cmd_str malloc failed");
92 memset(cmd_str, 0, sizeof(char) * (cmd_len + 1));
95 strcat(cmd_str, conv_cmd);
96 strcat(cmd_str, "-f ");
97 strcat(cmd_str, page_str);
99 strcat(cmd_str, "-l ");
100 strcat(cmd_str, page_str);
101 strcat(cmd_str, " ");
102 strcat(cmd_str, "-scale-to-x ");
103 strcat(cmd_str, x_val_str);
104 strcat(cmd_str, " ");
105 strcat(cmd_str, "-scale-to-y ");
106 strcat(cmd_str, y_val_str);
107 strcat(cmd_str, " ");
108 strcat(cmd_str, path);
109 strcat(cmd_str, output_cmd);
111 cmd_str[cmd_len] = '\0';
113 PGEN_DEBUG("call_pdftoppm(): cmd_str = %s", cmd_str);
115 if (system(cmd_str) < 0) {
116 PGEN_DEBUG("Failed to call system");
119 PGEN_IF_FREE_MEM(cmd_str);
125 int call_pdfinfo(const char *path, const char *field)
131 PGEN_RETV_IF(path == NULL || field == NULL, -1, "Invalid argument");
132 path_len = strnlen(path, MAX_PATH_LEN);
133 PGEN_RETV_IF(path_len <= 0 || path_len >= MAX_PATH_LEN, -1, "path_len is out of scope");
135 cmd_len = sizeof(PDF_INFO_UTIL) + sizeof(" '") + path_len
136 + sizeof("' | grep '") + strlen(field)
137 + strlen("' > " PDF_INFO_TEMP_FNAME); // strlen(output_cmd);
138 cmd_str = malloc(sizeof(char) * (cmd_len + 1));
140 PGEN_RETV_IF(cmd_str == NULL, -1, "cmd_str malloc failed");
141 memset(cmd_str, 0, sizeof(char) * (cmd_len + 1));
144 strcat(cmd_str, PDF_INFO_UTIL);
145 strcat(cmd_str, " '");
146 strcat(cmd_str, path);
147 strcat(cmd_str, "' | grep '");
148 strcat(cmd_str, field);
149 strcat(cmd_str, "' > " PDF_INFO_TEMP_FNAME);
150 //strcat(cmd_str, output_cmd);
151 cmd_str[cmd_len] = '\0';
153 PGEN_DEBUG("call_pdfinfo(): cmd_str = %s", cmd_str);
155 if (system(cmd_str) < 0) {
156 PGEN_DEBUG("Failed to call system");
159 PGEN_IF_FREE_MEM(cmd_str);
167 * @param[in] path path to PDF file
169 int call_pdfinfo_pagesize(const char *path)
171 /* TODO: page number */
172 return call_pdfinfo(path, "Page size:");
176 int call_pdfinfo_pages(const char *path)
178 return call_pdfinfo(path, "Pages:");
182 int is_page_landscape(struct size_pts *s)
184 PGEN_RETV_IF(s == NULL, -1, "Invalid argument");
195 * @brief get PDF file page size in pts
196 * @param[in] path PDF file path
197 * @param[out] ow width in pts
198 * @param[out] oh height in pts
200 int get_pdf_page_size(const char *path, struct size_pts *s)
203 char cmd_str[MAX_PATH_LEN] = {0,};
205 PGEN_RETV_IF(path == NULL || s == NULL, -1, "Invalid argument");
207 //NOTICE : Usage : pdfinfo [options] <PDF-file>, we use "pdfinfo <PDF-file>" to get page size
208 snprintf(cmd_str, MAX_PATH_LEN, "%s %s", PDF_INFO_UTIL, path);
209 PGEN_DEBUG("call_pdfinfo(): cmd_str = %s", cmd_str);
212 if ((fp=popen(cmd_str, "r"))==NULL) {
213 PGEN_DEBUG("popen error(%s)",cmd_str);
217 char *str_buf = NULL;
219 ssize_t read_len = 0;
220 char temp[MAX_PATH_LEN] = {0,};
223 read_len = getline(&str_buf, &len, fp);
224 if (strstr(str_buf, "Page size:") != NULL) {
225 res = sscanf(str_buf, "Page size:\t%lf x %lf%s", &(s->x), &(s->y), temp);
227 PGEN_DEBUG("ERROR: get_pdf_page_size(): incorrect output\n");
234 } while (read_len != -1);
235 PGEN_IF_FREE_MEM(str_buf);
237 PGEN_DEBUG("Page size : [%f %f]",s->x, s->y);
239 int ret = pclose(fp);
240 if (!WIFEXITED(ret) || (WEXITSTATUS(ret) != 0)) {
241 PGEN_DEBUG("pclose error!");
252 int get_pdf_pages_count(const char *path)
254 PGEN_RETV_IF(path == NULL, -1, "Invalid argument");
259 char cmd_str[MAX_PATH_LEN] = {0,};
261 path_len = strnlen(path, MAX_PATH_LEN);
262 PGEN_RETV_IF(path_len <= 0 || path_len >= MAX_PATH_LEN, -1, "path_len is out of scope");
264 //NOTICE : Usage : pdfinfo [options] <PDF-file>, we use "pdfinfo <PDF-file>" to get pages
265 snprintf(cmd_str, MAX_PATH_LEN, "%s %s", PDF_INFO_UTIL, path);
266 PGEN_DEBUG("call_pdfinfo(): cmd_str = %s", cmd_str);
269 if ((fp=popen(cmd_str, "r"))==NULL) {
270 PGEN_DEBUG("popen error(%s)",cmd_str);
274 char *str_buf = NULL;
276 ssize_t read_len = 0;
279 read_len = getline(&str_buf, &len, fp);
280 if (strstr(str_buf, "Pages:") != NULL) {
281 res = sscanf(str_buf, "Pages:\t%d", &val);
283 PGEN_DEBUG("ERROR: get_pdf_pages_count(): incorrect output\n");
290 } while (read_len != -1);
291 PGEN_IF_FREE_MEM(str_buf);
293 PGEN_DEBUG("Pages : %d", val);
295 int ret = pclose(fp);
296 if (!WIFEXITED(ret) || (WEXITSTATUS(ret) != 0)) {
297 PGEN_DEBUG("pclose error!");
303 * @brief get PDF preview
304 * @param[in] path path to PDF to generate preview
305 * @param[in] settings currently just ignored
306 * @param[out] out_img pointer to return allocated buffer, user is
307 * responsible for it's memory deallocation
309 * @param[out] size image data size
313 int get_pdf_preview(const char *path,
314 const struct pdf_preview_settings *settings,
315 void **out_img, int *size)
318 unsigned char *imgbuf;
319 PGEN_RETV_IF(size == NULL || settings == NULL || out_img == NULL , -1, "Invalid argument");
321 if (call_pdftoppm(path, settings) < 0) {
322 PGEN_DEBUG("ERROR: get_pdf_preview(): call_pdftoppm() error");
326 /* just stub, insecure in case of multiple printing requests */
327 img_fd = open(IMG_TEMP_FILE_NAME, O_RDONLY);
328 PGEN_RETV_IF(img_fd == -1, -1, "Failed to open temporary file");
330 /* STUB: currently just with enough big memory area, no check for
331 higher memory requirements */
332 imgbuf = malloc(sizeof(char) * IMG_MAX_SIZE);
333 if (imgbuf == NULL) {
335 PGEN_DEBUG("malloc failed");
338 memset(imgbuf, 0, sizeof(char) * IMG_MAX_SIZE);
339 *size = read(img_fd, imgbuf, IMG_MAX_SIZE);
343 PGEN_IF_FREE_MEM(imgbuf);
344 PGEN_DEBUG("ERROR: get_pdf_preview(): read error");
354 /* Check for file extension
357 int is_file_ext(const char *fname, int fname_len, const char *ext)
359 const char *ptr, *ext_ptr;
362 PGEN_RETV_IF(fname == NULL || ext == NULL, 0, "Invalid argument");
364 ext_len = strlen(ext);
365 if (fname_len < ext_len + 1) {
369 ptr = fname + fname_len - ext_len - 1;
372 if (*ptr == '.' && strcasecmp(ext_ptr, ext) == 0) {
380 * @brief get file type from its name (extension-based)
381 * @param[in] fname file name (may be with path)
384 enum file_type get_file_type(const char *fname)
387 const char *img_file_types[] = IMG_FILE_EXTS;
388 const char *pdf_ftype = PDF_FILE_EXT;
391 /* check for corectness */
392 PGEN_RETV_IF(fname == NULL, FILE_TYPE_INCORRECT, "Incorrect file type");
394 fname_len = strnlen(fname, MAX_PATH_LEN);
395 PGEN_RETV_IF(fname_len >= MAX_PATH_LEN, FILE_TYPE_INCORRECT, "Too long file name");
397 /* check for pdf extension */
398 if (is_file_ext(fname, fname_len, pdf_ftype)) {
399 return FILE_TYPE_PDF;
402 /* check for image extensions */
403 for (i = 0; img_file_types[i] != NULL; i++) {
404 if (is_file_ext(fname, fname_len, img_file_types[i])) {
405 return FILE_TYPE_IMAGE;
409 return FILE_TYPE_INCORRECT;
414 * @brief get file type from its name (extension-based)
415 * @param[in] fname file name (may be with path)
418 enum file_type get_file_type(const char *fname)
420 PGEN_RETV_IF(fname == NULL, FILE_TYPE_INCORRECT, "fname is NULL");
421 char *fname_copy = strdup(fname);
422 PGEN_RETV_IF(fname_copy == NULL, FILE_TYPE_INCORRECT, "fname_copy is NULL");
424 char *bname = basename(fname_copy);
425 char *ext = strrchr(bname, '.');
426 PGEN_RETV_IF(ext == NULL, FILE_TYPE_INCORRECT, "ext is NULL");
428 const char *img_file_types[] = IMG_FILE_EXTS;
429 const char *pdf_ftype = PDF_FILE_EXT;
430 int ret = FILE_TYPE_INCORRECT;
433 if (strcasestr(ext, pdf_ftype) != NULL) {
436 for (i = 0; img_file_types[i] != NULL; i++) {
437 if (strcasestr(ext, img_file_types[i]) != NULL) {
438 ret = FILE_TYPE_IMAGE;
444 PGEN_IF_FREE_MEM(fname_copy);