// Copyright (C) 2003-2026, Foxit Software Inc..
// All Rights Reserved.
//
// http://www.foxitsoftware.com
//
// The following code is copyrighted and contains proprietary information and trade secrets of Foxit Software Inc..
// You cannot distribute any part of Foxit PDF Conversion SDK to any third party or general public,
// unless there is a separate license agreement with Foxit Software Inc. which explicitly grants you such rights.
//
// This file contains an example to demonstrate how to use Foxit PDF Conversion SDK to convert PDF files to Office(Word, Excel or PowerPoint) format files.

// Include Foxit PDF Conversion SDK header files.
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)

#if defined(_WIN32) || defined(_WIN64)
#include <direct.h>
#else
#include <sys/stat.h>
#include <wchar.h>
#endif
#include <stdio.h>
#include <stdlib.h>

#include "../../../include/fs_basictypes_c.h"
#include "../../../include/fs_common_c.h"
#include "../../../include/fx_stream_c.h"
#include "../../../include/fs_pdf2office_c.h"

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef NULL
#define NULL (void*)0
#endif

#define MAX_FILE_PATH 260

static const char* sn = "TrBnIl1hcu6pTpu0S3ERjXXXOfdLrtmMprkH+ti7GbntIvMVPDiVXg==";
static const char* key = "LTceEOppvT5kiwl+7kIrRDynk1Yf2ZEWx/dcW1TEpHM5SmNMKyRHROy4VmGriH57HWffaMfF6M6MJubxQ3iyAn+JlyGdsBvv7qO3R1pqeQ5QvxjKik23m1JVmreCRjSnw0pXYuivW0vArZCljSu0y/0upmsG/QrLi3b19f80xfIvI3zR2mgmTg7QB2ggHp457yAO81nO3Cr/+T/lSfRwlr/q7fBltxATtPViSA6vpr59ipesqvq2Dvb14mim7q2O1thkJqS11UpVtRJ+5kiDgfgVb/Dqj9mAyazuO5h9fFlWnASQnBIkxr9/i3E89QFAskCSN2L0nPmam4Vat3Sy2NzQqiEIQat0hY8aGr05WIlTcr81hTBCtUsnweXtCUyG+IYF7BFl8HXItlErz+AMsXwCc9mG6E3+nLM0b7mk80rpeG+XXxbdcHZKjfjZem8qcoCITEzZsQo4DRoqeO65adCFZ7TxCzyVPQKUbFfxwmZFGRMpanuh6WJ8EcRohguAvy2sWNTQptwAzky3iXWdJVl8th5hu9AIT84xIuaXRVP9mAyvwa0fjMZQJZ/KYSwH6BEgG2oCigAjp8+/NdPy5+XrPaIjZLQxhxnJO5jtMFm/IrQmEHsytBNyJPN3TLazQhFzzgREfJ3citV7IXYw/4CUusP6I7mnNv7CHQeR4AxIL2yHZaUO9FK/YzRpuurN+Va64LVZ4Yryrw12Z40P/nrEwiaeZre/KZNjF1DBGetodpkRE/KPY739VJGI9UDb/uOQ17viH0H0ZnMFRAYvd0uQ7vfWZvGlj6jU40TheWu1yCdIqYAXa1XxDGFWU2cboGhnIC64AKS1yjv8UEUY1nWpp1tNvmykq7ZiYs1Jl0KszVDsSHDlKeSyvo4MD/J1OrR+7cFj27sya2Pt1WPhKGQ48b/vwckLzE+QyaLAaHfWuF6Xa6MzSj+PlRJo9Oa/d11N86WQV9BRj2g4vggjAbfRMGg6yS/wHadCujk6+XlVtBtpNKYV6fPKnASpn5IHPtZjm+qoyDFsuh8BHZn5UbH0JF9szdWbiEf+oZ17fna49qSPGKkl14ojW2lkb2O5e/wy/0lWFOBoI/mtUw9SA+M+VCEr6ji4xWckKKYY2eC0I3SghjMcUQgj6QyShMfl3hH9KUJ9U/eKMw4ZpDv5cG7xQ9p/I9nGX0ZrGzdV8o1pR5byw6xcRNw8rdtZS3pkVCEAuRFsicq6WRP7ro0kHaKJWzfRlQKgdZO+AHz47BzX4F6aD6KCCwIz7g==";

#if defined(_WIN32) || defined(_WIN64)
static const wchar_t* output_path = L"../output_files/";
static const wchar_t* input_path = L"../input_files/";
#else
static const wchar_t* output_path = L"./output_files/";
static const wchar_t* input_path = L"./input_files/";
#endif


static FS_BOOL gNeedToPause(void* user_data) {
  return TRUE;
}

static void gProgressNotify(void* user_data, int converted_count, int total_count) {
}

FS_BOOL is_large_file = FALSE;
FILE* file = NULL;
FILE* filestream = NULL;
int ref = 0;
FS_INT64 cur_pos = 0;



void gOpenFile(FILE** p_file, wchar_t* filename, const char *mode) {
  FS_WSTR wstr;
  FS_BSTR bstr;
  *p_file = NULL;
  if (!p_file || !filename || !mode) return;
  wstr.str = filename;
  wstr.len = wcslen(filename);
  FSDK_WStr_UTF8Encode(&wstr, &bstr);
#if defined(_WIN32) || defined(_WIN64)
  fopen_s(p_file, bstr.str, mode);
#elif defined(__linux__)
  *p_file = fopen(bstr.str, mode);
#endif
  FSDK_BStr_Clear(&bstr);
}

FS_INT64 gGetSize(void* user_data) {
  if (!user_data) return 0;
  if (is_large_file) {
    long long size_long;
#if defined(_WIN32) || defined(_WIN64)
    _fseeki64(file, 0, SEEK_END);
    size_long = _ftelli64(file);
#elif defined(__linux__)
    fseeko(file, 0, SEEK_END);
    size_long = ftello(file);
#endif
    return size_long;
  } else {
   fseek(file, 0, SEEK_END);
   return (FS_INT64)ftell(file);
  }
  return 0;
}

FS_BOOL gReadBlock(void* user_data, void* buffer, FS_INT64 offset, size_t size) {
  if (is_large_file) {
    long long read_size;
#if defined(_WIN32) || defined(_WIN64)
      _fseeki64(file, 0, SEEK_END);
#elif defined(__linux__) || defined(__APPLE__)
      fseeko(file, 0, SEEK_END);
#endif
    read_size = fread(buffer, 1, size, file);
    return read_size == size ? TRUE : FALSE;
  } else {
    if (!file)
      return FALSE;
    if (0 != fseek(file, (long)offset, 0))
      return FALSE;
    if (0 == fread(buffer, size, 1, file))
      return FALSE;
    return TRUE;
  }
  return FALSE;
}

static void gRelease(void* user_data) {
  if (file) {
    fclose(file);
    file = NULL;
  }  
  if (user_data)
   free(user_data);
}

FS_INT64 gGetSizeFileStream(void* user_data) {
  if (!user_data) return 0;
  fseek(filestream, 0, SEEK_END);
  return (FS_INT64)ftell(filestream);
}

FS_BOOL gFlushFileStream(void* user_data) {
  fflush(filestream);
  return TRUE;
}

FS_INT64 gGetPositionFileStream(void* user_data) {
  return cur_pos;
}

FS_BOOL gReadBlockFileStream(void* user_data, void* buffer, FS_INT64 offset, size_t size) {
  if (0 != fseek(filestream, (long)offset, 0))
    return FALSE;
  if (0 == fread(buffer, size, sizeof(char), filestream))
    return FALSE;

  cur_pos = offset + size;
  return TRUE;
}

size_t gReadBlock0FileStream(void* user_data, void* buffer, size_t size) {
  if (gReadBlock(user_data, buffer, gGetSize(user_data), size))
    return size;
  else
    return 0;
}

FS_BOOL gWriteBlockFileStream(void* user_data, const void* buffer, FS_INT64 offset, size_t size) {
  FS_INT64 write_size = 0;
  fseek(filestream, (long)offset, SEEK_SET);
  write_size = fwrite(buffer, sizeof(char), size, filestream);
  if (write_size == size) {
    cur_pos = offset + size;
    return TRUE;
  }
  return FALSE;
}

FSIFX_FileStream* gRetainFileStream(void* user_data) {
  ref++;
  return ((FSStreamCallback*)user_data);
}

FS_BOOL gIsEOFFileStream(void* user_data) {
  fseek(filestream, 0, SEEK_END);
  if (cur_pos < (FS_INT64)ftell(filestream))
    return FALSE;
  return TRUE;
}

void gReleaseFileStream(void* user_data) {
  ref--;
  if (ref > 0) return;
  
  fclose(filestream);
  free(user_data);
}


int main(int argc, char *argv[]) {
  int err_ret = 0;
  FSErrorCode error_code = e_FSErrSuccess;
  wchar_t output_directory[MAX_FILE_PATH];
  wchar_t src_pdf_path[MAX_FILE_PATH];
  wchar_t saved_word_file_path[MAX_FILE_PATH];
  wchar_t saved_excel_file_path[MAX_FILE_PATH];
  wchar_t saved_ppt_file_path[MAX_FILE_PATH];
  wchar_t saved_word_file_path_stream[MAX_FILE_PATH];
  wchar_t saved_excel_file_path_stream[MAX_FILE_PATH];
  wchar_t saved_ppt_file_path_stream[MAX_FILE_PATH];

  FSConvertCallback* callback = NULL;
  FS_PROGRESSIVE_HANDLE progressive_handle = NULL;
  int rate = 0;
  FSConvertCallback* callback_stream_word = NULL;
  FSReaderCallback* callback_filereader_word = NULL;
  FSStreamCallback* callback_filestream_word = NULL;
  FSConvertCallback* callback_stream_excel = NULL;
  FSReaderCallback* callback_filereader_excel = NULL;
  FSStreamCallback* callback_filestream_excel = NULL;
  FSConvertCallback* callback_stream_ppt = NULL;
  FSReaderCallback* callback_filereader_ppt = NULL;
  FSStreamCallback* callback_filestream_ppt = NULL;
  
  FSPDF2OfficeSettingData setting_data;
  FSPDF2WordSettingData word_setting_data;
  FSPDF2PowerPointSettingData power_point_setting_data;
  FSPDF2ExcelSettingData excel_setting_data;


#if defined(_WIN32) || defined(_WIN64)
    swprintf_s(output_directory, MAX_FILE_PATH, L"%lspdf2office/", output_path);
    _wmkdir(output_directory);
#else
    swprintf(output_directory, MAX_FILE_PATH-1, L"%lspdf2office/", output_path);
    FS_WSTR wstr;
    wstr.str = output_directory;
    wstr.len = wcslen(output_directory);
    FS_BSTR bstr;
    FSDK_WStr_UTF8Encode(&wstr, &bstr);
    mkdir(bstr.str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
    FSDK_BStr_Clear(&bstr);
#endif


  error_code = FSDK_Library_Initialize(sn, key);
  if (error_code != e_FSErrSuccess) {
    printf("Library Initialize Error: %d\n", error_code);
    return 1;
  }

  // Convert PDF file to Word format file.
  setting_data.metrics_data_folder_path.str = NULL;
  setting_data.metrics_data_folder_path.len = 0;
  setting_data.enable_trailing_space = TRUE;
  setting_data.include_images = TRUE;
  setting_data.enable_ml_recognition = FALSE;
  setting_data.include_pdf_comments = TRUE;
  setting_data.page_range = NULL;
  setting_data.enable_matching_system_fonts = FALSE;
  word_setting_data.enable_retain_page_layout = FALSE;
  word_setting_data.enable_generate_headers_and_footers = TRUE;
  word_setting_data.enable_generate_footnotes_and_endnotes = FALSE;
  word_setting_data.enable_generate_page_rendered_break = FALSE;
  setting_data.word_setting_data = word_setting_data;
  power_point_setting_data.enable_aggressively_split_sections = FALSE;
  power_point_setting_data.enable_aggressively_split_sections = FALSE;
  setting_data.power_point_setting_data = power_point_setting_data;  
  excel_setting_data.decimal_symbol.str = NULL;
  excel_setting_data.decimal_symbol.len = 0;
  excel_setting_data.thousands_separator.str = NULL;
  excel_setting_data.thousands_separator.len = 0;
  excel_setting_data.workbook_settings = e_FSWorkbookSettingsEachPage;
  excel_setting_data.enable_aggressive_table_repair = TRUE;
  excel_setting_data.include_watermarks = FALSE;
  setting_data.excel_setting_data = excel_setting_data;

  callback = (FSConvertCallback*)malloc(sizeof(FSConvertCallback));
  callback->user_data = callback;
  callback->NeedToPause = gNeedToPause;
  callback->ProgressNotify = gProgressNotify;

  swprintf(src_pdf_path, MAX_FILE_PATH - 1, L"%lsword.pdf", input_path);
  swprintf(saved_word_file_path, MAX_FILE_PATH - 1, L"%lspdf2word_result.docx", output_directory);
  swprintf(saved_word_file_path_stream, MAX_FILE_PATH - 1, L"%lspdf2word_stream_result.docx", output_directory);
  error_code = FSDK_PDF2Office_StartConvertToWord(src_pdf_path, NULL, saved_word_file_path, setting_data, callback, &progressive_handle);
  if (error_code != e_FSErrSuccess) {
    switch (error_code) {
    case e_FSErrNoPDF2OfficeModuleRight:
      printf("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.\n");
      break;
    default:
      printf("Exception: %d\n", error_code);
        break;
    }
    return 1;
  }    

  FSDK_Progressive_GetRateOfProgress(progressive_handle, &rate);
  if (rate != 100) {
    FSState state = e_FSToBeContinued;
    while (e_FSToBeContinued == state) {
      FSDK_Progressive_Continue(progressive_handle, &state);
    }
  }
  printf("Convert PDF file to Word format file with path.\n");

  callback_stream_word = (FSConvertCallback*)malloc(sizeof(FSConvertCallback));
  callback_stream_word->user_data = callback_stream_word;
  callback_stream_word->NeedToPause = gNeedToPause;
  callback_stream_word->ProgressNotify = gProgressNotify;

  callback_filereader_word = (FSReaderCallback*)malloc(sizeof(FSReaderCallback));
  gOpenFile(&file, src_pdf_path, "rb");

  callback_filereader_word->user_data = callback_filereader_word;
  callback_filereader_word->ReadBlock = gReadBlock;
  callback_filereader_word->Release = gRelease;
  callback_filereader_word->GetSize = gGetSize;

  callback_filestream_word = (FSStreamCallback*)malloc(sizeof(FSStreamCallback));
  gOpenFile(&filestream, saved_word_file_path_stream, "wb");
  callback_filestream_word->Flush = gFlushFileStream;
  callback_filestream_word->GetPosition = gGetPositionFileStream;
  callback_filestream_word->GetSize = gGetSizeFileStream;
  callback_filestream_word->IsEOF = gIsEOFFileStream;
  callback_filestream_word->WriteBlock = gWriteBlockFileStream;
  callback_filestream_word->ReadBlock = gReadBlockFileStream;
  callback_filestream_word->ReadBlock0 = gReadBlock0FileStream;
  callback_filestream_word->Release = gReleaseFileStream;
  callback_filestream_word->Retain = gRetainFileStream;
  callback_filestream_word->user_data = callback_filestream_word;
  ref = 0;
  cur_pos = 0;

  error_code = FSDK_PDF2Office_StartConvertToWord0(callback_filereader_word, NULL, callback_filestream_word, setting_data, callback_stream_word, &progressive_handle);
  if (error_code != e_FSErrSuccess) {
    switch (error_code) {
    case e_FSErrNoPDF2OfficeModuleRight:
      printf("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.\n");
      break;
    default:
      printf("Exception: %d\n", error_code);
      break;
    }
    return 1;
  }    
  FSDK_Progressive_GetRateOfProgress(progressive_handle, &rate);
  if (rate != 100) {
    FSState state = e_FSToBeContinued;
    while (e_FSToBeContinued == state) {
      FSDK_Progressive_Continue(progressive_handle, &state);
    }
  }
  printf("Convert PDF file to Word format file with stream.\n");

  swprintf(src_pdf_path, MAX_FILE_PATH - 1, L"%lsexcel.pdf", input_path);
  swprintf(saved_excel_file_path, MAX_FILE_PATH - 1, L"%lspdf2excel_result.xlsx", output_directory);
  swprintf(saved_excel_file_path_stream, MAX_FILE_PATH - 1, L"%lspdf2excel_stream_result.xlsx", output_directory);

  // Convert PDF file to Excel format file.
  error_code = FSDK_PDF2Office_StartConvertToExcel(src_pdf_path, NULL, saved_excel_file_path, setting_data, callback_stream_word, &progressive_handle);
  if (error_code != e_FSErrSuccess) {
    switch (error_code) {
    case e_FSErrNoPDF2OfficeModuleRight:
      printf("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.\n");
      break;
    default:
      printf("Exception: %d\n", error_code);
      break;
    }
    return 1;
  }    
  FSDK_Progressive_GetRateOfProgress(progressive_handle, &rate);
  if (rate != 100) {
    FSState state = e_FSToBeContinued;
    while (e_FSToBeContinued == state) {
      FSDK_Progressive_Continue(progressive_handle, &state);
    }
  }
  printf("Convert PDF file to Excel format file with path.\n");

  callback_stream_excel = (FSConvertCallback*)malloc(sizeof(FSConvertCallback));
  callback_stream_excel->user_data = callback_stream_word;
  callback_stream_excel->NeedToPause = gNeedToPause;
  callback_stream_excel->ProgressNotify = gProgressNotify;

  callback_filereader_excel = (FSReaderCallback*)malloc(sizeof(FSReaderCallback));
  gOpenFile(&file, src_pdf_path, "rb");
  callback_filereader_excel->user_data = callback_filereader_word;
  callback_filereader_excel->ReadBlock = gReadBlock;
  callback_filereader_excel->Release = gRelease;
  callback_filereader_excel->GetSize = gGetSize;

  callback_filestream_excel = (FSStreamCallback*)malloc(sizeof(FSStreamCallback));
  gOpenFile(&filestream, saved_excel_file_path_stream, "wb");
  callback_filestream_excel->Flush = gFlushFileStream;
  callback_filestream_excel->GetPosition = gGetPositionFileStream;
  callback_filestream_excel->GetSize = gGetSizeFileStream;
  callback_filestream_excel->IsEOF = gIsEOFFileStream;
  callback_filestream_excel->ReadBlock = gReadBlockFileStream;
  callback_filestream_excel->ReadBlock0 = gReadBlock0FileStream;
  callback_filestream_excel->WriteBlock = gWriteBlockFileStream;
  callback_filestream_excel->Release = gReleaseFileStream;
  callback_filestream_excel->Retain = gRetainFileStream;
  callback_filestream_excel->user_data = callback_filestream_excel;
  ref = 0;
  cur_pos = 0;

  error_code = FSDK_PDF2Office_StartConvertToExcel0(callback_filereader_excel, NULL, callback_filestream_excel, setting_data, callback_stream_excel, &progressive_handle);
  if (error_code != e_FSErrSuccess) {
    switch (error_code) {
      case e_FSErrNoPDF2OfficeModuleRight:
        printf("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.\n");
        break;
      default:
        printf("Exception: %d\n", error_code);
        break;
    }
    return 1;
  }    
  FSDK_Progressive_GetRateOfProgress(progressive_handle, &rate);
  if (rate != 100) {
    FSState state = e_FSToBeContinued;
    while (e_FSToBeContinued == state) {
      FSDK_Progressive_Continue(progressive_handle, &state);
    }
  }
  printf("Convert PDF file to Excel format file with stream.\n");

  // Convert PDF file to PowerPoint format file.
  swprintf(src_pdf_path, MAX_FILE_PATH - 1, L"%lspowerpoint.pdf", input_path);
  swprintf(saved_ppt_file_path, MAX_FILE_PATH - 1, L"%lspdf2powerpoint_result.pptx", output_directory);
  swprintf(saved_ppt_file_path_stream, MAX_FILE_PATH - 1, L"%lspdf2powerpoint_stream_result.pptx", output_directory);

  error_code = FSDK_PDF2Office_StartConvertToPowerPoint(src_pdf_path, NULL, saved_ppt_file_path, setting_data, callback, &progressive_handle);
  if (error_code != e_FSErrSuccess) {
    switch (error_code) {
    case e_FSErrNoPDF2OfficeModuleRight:
      printf("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.\n");
      break;
    default:
      printf("Exception: %d\n", error_code);
      break;
    }
    return 1;
  }    
  FSDK_Progressive_GetRateOfProgress(progressive_handle, &rate);
  if (rate != 100) {
    FSState state = e_FSToBeContinued;
    while (e_FSToBeContinued == state) {
      FSDK_Progressive_Continue(progressive_handle, &state);
    }
  }
  printf("Convert PDF file to PowerPoint format file with path.\n");

  callback_stream_ppt = (FSConvertCallback*)malloc(sizeof(FSConvertCallback));
  callback_stream_ppt->user_data = callback_stream_word;
  callback_stream_ppt->NeedToPause = gNeedToPause;
  callback_stream_ppt->ProgressNotify = gProgressNotify;

  callback_filereader_ppt = (FSReaderCallback*)malloc(sizeof(FSReaderCallback));
  gOpenFile(&file, src_pdf_path, "rb");
  callback_filereader_ppt->user_data = callback_filereader_word;
  callback_filereader_ppt->ReadBlock = gReadBlock;
  callback_filereader_ppt->Release = gRelease;
  callback_filereader_ppt->GetSize = gGetSize;

  callback_filestream_ppt = (FSStreamCallback*)malloc(sizeof(FSStreamCallback));
  gOpenFile(&filestream, saved_ppt_file_path_stream, "wb");
  callback_filestream_ppt->Flush = gFlushFileStream;
  callback_filestream_ppt->GetPosition = gGetPositionFileStream;
  callback_filestream_ppt->GetSize = gGetSizeFileStream;
  callback_filestream_ppt->IsEOF = gIsEOFFileStream;
  callback_filestream_ppt->ReadBlock = gReadBlockFileStream;
  callback_filestream_ppt->ReadBlock0 = gReadBlock0FileStream;
  callback_filestream_ppt->WriteBlock = gWriteBlockFileStream;
  callback_filestream_ppt->Release = gReleaseFileStream;
  callback_filestream_ppt->Retain = gRetainFileStream;
  callback_filestream_ppt->user_data = callback_filestream_ppt;

  error_code = FSDK_PDF2Office_StartConvertToPowerPoint0(callback_filereader_ppt, NULL, callback_filestream_ppt, setting_data, callback_stream_ppt, &progressive_handle);
  if (error_code != e_FSErrSuccess) {
    switch (error_code) {
    case e_FSErrNoPDF2OfficeModuleRight:
      printf("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.\n");
      break;
    default:
      printf("Exception: %d\n", error_code);
      break;
    }
    return 1;
  }    
  FSDK_Progressive_GetRateOfProgress(progressive_handle, &rate);
  if (rate != 100) {
    FSState state = e_FSToBeContinued;
    while (e_FSToBeContinued == state) {
      FSDK_Progressive_Continue(progressive_handle, &state);
    }
  }
  printf("Convert PDF file to PowerPoint format file with stream.\n");

  FSDK_Library_Release();
  return err_ret;
}
#endif  // #if defined(_WIN32) || defined(_WIN64) || defined(__linux__)

