xlsxio_write.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. #include "xlsxio_write.h"
  2. #include "xlsxio_version.h"
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include <inttypes.h>
  8. #ifndef _WIN32
  9. #include <unistd.h>
  10. #endif
  11. #include <fcntl.h>
  12. #include <stdarg.h>
  13. #ifdef USE_MINIZIP
  14. # include <minizip/zip.h>
  15. # if !defined(Z_DEFLATED) && defined(MZ_COMPRESS_METHOD_DEFLATE) /* support minizip2 which defines MZ_COMPRESS_METHOD_DEFLATE instead of Z_DEFLATED */
  16. # define Z_DEFLATED MZ_COMPRESS_METHOD_DEFLATE
  17. # endif
  18. # define ZIPFILETYPE zipFile
  19. #else
  20. # if (defined(STATIC) || defined(BUILD_XLSXIO_STATIC) || defined(BUILD_XLSXIO_STATIC_DLL) || (defined(BUILD_XLSXIO) && !defined(BUILD_XLSXIO_DLL) && !defined(BUILD_XLSXIO_SHARED))) && !defined(ZIP_STATIC)
  21. # define ZIP_STATIC
  22. # endif
  23. # include <zip.h>
  24. # ifndef ZIP_RDONLY
  25. typedef struct zip zip_t;
  26. typedef struct zip_source zip_source_t;
  27. # endif
  28. # define ZIPFILETYPE zip_t
  29. # ifndef USE_LIBZIP
  30. # define USE_LIBZIP
  31. # endif
  32. #endif
  33. #if defined(_WIN32) && !defined(USE_PTHREADS)
  34. # define USE_WINTHREADS
  35. # include <windows.h>
  36. #else
  37. # define USE_PTHREADS
  38. # include <pthread.h>
  39. #endif
  40. #if defined(_MSC_VER)
  41. # undef DLL_EXPORT_XLSXIO
  42. # define DLL_EXPORT_XLSXIO
  43. # define va_copy(dst,src) ((dst) = (src))
  44. #endif
  45. #ifdef _WIN32
  46. # define pipe(fds) _pipe(fds, 4096, _O_BINARY)
  47. # define read _read
  48. # define write _write
  49. # define write _write
  50. # define close _close
  51. # define fdopen _fdopen
  52. #else
  53. # define _fdopen(f) f
  54. #endif
  55. //#undef WITHOUT_XLSX_STYLES
  56. #define DEFAULT_BUFFERED_ROWS 5
  57. #define FONT_CHAR_WIDTH 7
  58. //#define CALCULATE_COLUMN_WIDTH(characters) ((double)characters + .75)
  59. #define CALCULATE_COLUMN_WIDTH(characters) ((double)(long)(((long)characters * FONT_CHAR_WIDTH + 5) * 256 / FONT_CHAR_WIDTH) / 256.0)
  60. #define CALCULATE_COLUMN_HEIGHT(characters) ((double)characters * 12.75)
  61. DLL_EXPORT_XLSXIO void xlsxiowrite_get_version (int* pmajor, int* pminor, int* pmicro)
  62. {
  63. if (pmajor)
  64. *pmajor = XLSXIO_VERSION_MAJOR;
  65. if (pminor)
  66. *pminor = XLSXIO_VERSION_MINOR;
  67. if (pmicro)
  68. *pmicro = XLSXIO_VERSION_MICRO;
  69. }
  70. DLL_EXPORT_XLSXIO const char* xlsxiowrite_get_version_string ()
  71. {
  72. return XLSXIO_VERSION_STRING;
  73. }
  74. ////////////////////////////////////////////////////////////////////////
  75. //#define WITHOUT_XLSX_SHAREDSTRINGS
  76. #define WITHOUT_XLSX_THEMES
  77. //#define WITHOUT_XLSX_FOLDERS
  78. //#define OPTIONAL_LINE_BREAK "\r\n"
  79. #define OPTIONAL_LINE_BREAK ""
  80. #define XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n"
  81. #define XML_FOLDER_RELS "_rels/"
  82. #ifndef WITHOUT_XLSX_FOLDERS
  83. #define XML_FOLDER_DOCPROPS "docProps/"
  84. #define XML_FOLDER_XL "xl/"
  85. #define XML_FOLDER_THEMES "theme/"
  86. #define XML_FOLDER_WORKSHEETS "worksheets/"
  87. #else
  88. #define XML_FOLDER_DOCPROPS ""
  89. #define XML_FOLDER_XL ""
  90. #define XML_FOLDER_WORKSHEETS ""
  91. #endif
  92. #define XML_FILENAME_CONTENTTYPES "[Content_Types].xml"
  93. #define XML_FILENAME_RELS ".rels"
  94. #define XML_FILENAME_DOCPROPS_CORE "core.xml"
  95. #define XML_FILENAME_DOCPROPS_APP "app.xml"
  96. #define XML_FILENAME_XL_WORKBOOK_RELS "workbook.xml.rels"
  97. #define XML_FILENAME_XL_WORKBOOK "workbook.xml"
  98. #define XML_FILENAME_XL_STYLES "styles.xml"
  99. #define XML_FILENAME_XL_THEME1 "theme1.xml"
  100. #define XML_FILENAME_XL_SHAREDSTRINGS "sharedStrings.xml"
  101. #define XML_FILENAME_XL_WORKSHEET1 "sheet1.xml"
  102. #define XML_SHEETNAME_MAXLEN 31
  103. #define XML_RELID_DOCPROPS_CORE "rId2"
  104. #define XML_RELID_DOCPROPS_APP "rId3"
  105. #define XML_RELID_XL_WORKBOOK "rId1"
  106. #define XML_WORKBOOK_RELID_XL_STYLES "rId1"
  107. #define XML_WORKBOOK_RELID_XL_WORKSHEET1 "rId2"
  108. #define XML_WORKBOOK_RELID_XL_SHAREDSTRINGS "rId3"
  109. #define XML_WORKBOOK_RELID_XL_THEME1 "rId4"
  110. const char* content_types_xml =
  111. XML_HEADER
  112. "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">" OPTIONAL_LINE_BREAK
  113. "<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>" OPTIONAL_LINE_BREAK
  114. "<Default Extension=\"xml\" ContentType=\"application/xml\"/>" OPTIONAL_LINE_BREAK
  115. "<Override PartName=\"/" XML_FOLDER_RELS XML_FILENAME_RELS "\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>" OPTIONAL_LINE_BREAK
  116. "<Override PartName=\"/" XML_FOLDER_XL XML_FILENAME_XL_WORKBOOK "\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>" OPTIONAL_LINE_BREAK
  117. "<Override PartName=\"/" XML_FOLDER_DOCPROPS XML_FILENAME_DOCPROPS_CORE "\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/>" OPTIONAL_LINE_BREAK
  118. "<Override PartName=\"/" XML_FOLDER_DOCPROPS XML_FILENAME_DOCPROPS_APP "\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/>" OPTIONAL_LINE_BREAK
  119. #ifndef WITHOUT_XLSX_STYLES
  120. "<Override PartName=\"/" XML_FOLDER_XL XML_FILENAME_XL_STYLES "\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/>" OPTIONAL_LINE_BREAK
  121. #endif
  122. #ifndef WITHOUT_XLSX_THEMES
  123. "<Override PartName=\"/" XML_FOLDER_XL XML_FOLDER_THEMES XML_FILENAME_XL_THEME1 "\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\"/>" OPTIONAL_LINE_BREAK
  124. #endif
  125. "<Override PartName=\"/" XML_FOLDER_XL XML_FOLDER_RELS XML_FILENAME_XL_WORKBOOK_RELS "\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>" OPTIONAL_LINE_BREAK
  126. "<Override PartName=\"/" XML_FOLDER_XL XML_FOLDER_WORKSHEETS XML_FILENAME_XL_WORKSHEET1 "\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/>" OPTIONAL_LINE_BREAK
  127. #ifndef WITHOUT_XLSX_SHAREDSTRINGS
  128. "<Override PartName=\"/" XML_FOLDER_XL XML_FILENAME_XL_SHAREDSTRINGS "\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml\"/>" OPTIONAL_LINE_BREAK
  129. #endif
  130. "</Types>" OPTIONAL_LINE_BREAK;
  131. const char* docprops_core_xml =
  132. XML_HEADER
  133. "<coreProperties xmlns=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\">" OPTIONAL_LINE_BREAK
  134. //"<creator>" XLSXIOWRITE_FULLNAME "</creator>" OPTIONAL_LINE_BREAK
  135. "<lastModifiedBy>" XLSXIOWRITE_FULLNAME "</lastModifiedBy>" OPTIONAL_LINE_BREAK
  136. //"<modified>2016-04-24T17:50:35Z</modified>" OPTIONAL_LINE_BREAK
  137. "</coreProperties>" OPTIONAL_LINE_BREAK;
  138. const char* docprops_app_xml =
  139. XML_HEADER
  140. "<Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" xmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\">" OPTIONAL_LINE_BREAK
  141. "<Application>" XLSXIOWRITE_NAME "</Application>" OPTIONAL_LINE_BREAK
  142. "<AppVersion>" XLSXIO_VERSION_STRING "</AppVersion>" OPTIONAL_LINE_BREAK
  143. "</Properties>" OPTIONAL_LINE_BREAK;
  144. const char* rels_xml =
  145. XML_HEADER
  146. "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">" OPTIONAL_LINE_BREAK
  147. "<Relationship Id=\"" XML_RELID_DOCPROPS_CORE "\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\" Target=\"" XML_FOLDER_DOCPROPS XML_FILENAME_DOCPROPS_CORE "\"/>" OPTIONAL_LINE_BREAK
  148. "<Relationship Id=\"" XML_RELID_DOCPROPS_APP "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\" Target=\"" XML_FOLDER_DOCPROPS XML_FILENAME_DOCPROPS_APP "\"/>" OPTIONAL_LINE_BREAK
  149. "<Relationship Id=\"" XML_RELID_XL_WORKBOOK "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"" XML_FOLDER_XL XML_FILENAME_XL_WORKBOOK "\"/>" OPTIONAL_LINE_BREAK
  150. "</Relationships>" OPTIONAL_LINE_BREAK;
  151. #ifndef WITHOUT_XLSX_STYLES
  152. const char* styles_xml =
  153. XML_HEADER
  154. "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" OPTIONAL_LINE_BREAK
  155. "<fonts count=\"2\">" OPTIONAL_LINE_BREAK
  156. "<font>" OPTIONAL_LINE_BREAK
  157. "<sz val=\"10\"/>" OPTIONAL_LINE_BREAK
  158. //"<color theme=\"1\"/>" OPTIONAL_LINE_BREAK
  159. "<name val=\"Consolas\"/>" OPTIONAL_LINE_BREAK
  160. "<family val=\"2\"/>" OPTIONAL_LINE_BREAK
  161. //"<scheme val=\"minor\"/>" OPTIONAL_LINE_BREAK
  162. "</font>" OPTIONAL_LINE_BREAK
  163. "<font>" OPTIONAL_LINE_BREAK
  164. "<b/><u/>"
  165. "<sz val=\"10\"/>" OPTIONAL_LINE_BREAK
  166. //"<color theme=\"1\"/>" OPTIONAL_LINE_BREAK
  167. "<name val=\"Consolas\"/>" OPTIONAL_LINE_BREAK
  168. "<family val=\"2\"/>" OPTIONAL_LINE_BREAK
  169. //"<scheme val=\"minor\"/>" OPTIONAL_LINE_BREAK
  170. "</font>" OPTIONAL_LINE_BREAK
  171. "</fonts>" OPTIONAL_LINE_BREAK
  172. "<fills count=\"1\">" OPTIONAL_LINE_BREAK
  173. "<fill/>" OPTIONAL_LINE_BREAK
  174. //"<fill><patternFill patternType=\"none\"/></fill>" OPTIONAL_LINE_BREAK
  175. "</fills>" OPTIONAL_LINE_BREAK
  176. "<borders count=\"2\">" OPTIONAL_LINE_BREAK
  177. "<border>" OPTIONAL_LINE_BREAK
  178. //"<left/>" OPTIONAL_LINE_BREAK
  179. //"<right/>" OPTIONAL_LINE_BREAK
  180. //"<top/>" OPTIONAL_LINE_BREAK
  181. //"<bottom/>" OPTIONAL_LINE_BREAK
  182. //"<diagonal/>" OPTIONAL_LINE_BREAK
  183. "</border>" OPTIONAL_LINE_BREAK
  184. "<border><bottom style=\"thin\"><color indexed=\"64\"/></bottom></border>" OPTIONAL_LINE_BREAK
  185. "</borders>" OPTIONAL_LINE_BREAK
  186. "<cellStyleXfs count=\"1\">" OPTIONAL_LINE_BREAK
  187. //"<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/>" OPTIONAL_LINE_BREAK
  188. "<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\">" OPTIONAL_LINE_BREAK
  189. "<alignment horizontal=\"general\" vertical=\"top\" wrapText=\"0\" shrinkToFit=\"0\" textRotation=\"0\" indent=\"0\"/>" OPTIONAL_LINE_BREAK
  190. "</xf>" OPTIONAL_LINE_BREAK
  191. "</cellStyleXfs>" OPTIONAL_LINE_BREAK
  192. "<cellXfs count=\"6\">" OPTIONAL_LINE_BREAK
  193. "<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/>" OPTIONAL_LINE_BREAK
  194. #define STYLE_HEADER 1
  195. "<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyBorder=\"1\" applyAlignment=\"1\"><alignment vertical=\"top\"/></xf>" OPTIONAL_LINE_BREAK
  196. #define STYLE_GENERAL 2
  197. "<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyAlignment=\"1\"><alignment vertical=\"top\"/></xf>" OPTIONAL_LINE_BREAK
  198. #define STYLE_TEXT 3
  199. "<xf numFmtId=\"49\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyNumberFormat=\"1\" applyAlignment=\"1\"><alignment vertical=\"top\" wrapText=\"1\"/></xf>" OPTIONAL_LINE_BREAK
  200. #define STYLE_INTEGER 4
  201. "<xf numFmtId=\"1\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyNumberFormat=\"1\" applyAlignment=\"1\"><alignment vertical=\"top\"/></xf>" OPTIONAL_LINE_BREAK
  202. #define STYLE_DATETIME 5
  203. "<xf numFmtId=\"22\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyNumberFormat=\"1\" applyAlignment=\"1\"><alignment horizontal=\"center\" vertical=\"top\"/></xf>" OPTIONAL_LINE_BREAK
  204. "</cellXfs>" OPTIONAL_LINE_BREAK
  205. //"<cellStyles count=\"2\">" OPTIONAL_LINE_BREAK
  206. //"<cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"/>" OPTIONAL_LINE_BREAK
  207. //"</cellStyles>" OPTIONAL_LINE_BREAK
  208. "<dxfs count=\"0\"/>" OPTIONAL_LINE_BREAK
  209. //"<tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\" defaultPivotStyle=\"PivotStyleLight16\"/>" OPTIONAL_LINE_BREAK
  210. "</styleSheet>" OPTIONAL_LINE_BREAK;
  211. #endif
  212. #ifndef WITHOUT_XLSX_THEMES
  213. const char* theme_xml =
  214. XML_HEADER
  215. "<theme xmlns=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\">" OPTIONAL_LINE_BREAK
  216. "<themeElements><clrScheme name=\"Office\"><dk1><sysClr val=\"windowText\" lastClr=\"000000\"/></dk1><lt1><sysClr val=\"window\" lastClr=\"FFFFFF\"/></lt1><dk2><srgbClr val=\"1F497D\"/></dk2><lt2><srgbClr val=\"EEECE1\"/></lt2><accent1><srgbClr val=\"4F81BD\"/></accent1><accent2><srgbClr val=\"C0504D\"/></accent2><accent3><srgbClr val=\"9BBB59\"/></accent3><accent4><srgbClr val=\"8064A2\"/></accent4><accent5><srgbClr val=\"4BACC6\"/></accent5><accent6><srgbClr val=\"F79646\"/></accent6><hlink><srgbClr val=\"0000FF\"/></hlink><folHlink><srgbClr val=\"800080\"/></folHlink></clrScheme><fontScheme name=\"Office\"><majorFont><latin typeface=\"Cambria\"/><ea typeface=\"\"/><cs typeface=\"\"/><font script=\"Jpan\" typeface=\"MS Pゴシック\"/><font script=\"Hang\" typeface=\"맑은 고딕\"/><font script=\"Hans\" typeface=\"宋体\"/><font script=\"Hant\" typeface=\"新細明體\"/><font script=\"Arab\" typeface=\"Times New Roman\"/><font script=\"Hebr\" typeface=\"Times New Roman\"/><font script=\"Thai\" typeface=\"Tahoma\"/><font script=\"Ethi\" typeface=\"Nyala\"/><font script=\"Beng\" typeface=\"Vrinda\"/><font script=\"Gujr\" typeface=\"Shruti\"/><font script=\"Khmr\" typeface=\"MoolBoran\"/><font script=\"Knda\" typeface=\"Tunga\"/><font script=\"Guru\" typeface=\"Raavi\"/><font script=\"Cans\" typeface=\"Euphemia\"/><font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><font script=\"Thaa\" typeface=\"MV Boli\"/><font script=\"Deva\" typeface=\"Mangal\"/><font script=\"Telu\" typeface=\"Gautami\"/><font script=\"Taml\" typeface=\"Latha\"/><font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><font script=\"Orya\" typeface=\"Kalinga\"/><font script=\"Mlym\" typeface=\"Kartika\"/><font script=\"Laoo\" typeface=\"DokChampa\"/><font script=\"Sinh\" typeface=\"Iskoola Pota\"/><font script=\"Mong\" typeface=\"Mongolian Baiti\"/><font script=\"Viet\" typeface=\"Times New Roman\"/><font script=\"Uigh\" typeface=\"Microsoft Uighur\"/></majorFont><minorFont><latin typeface=\"Calibri\"/><ea typeface=\"\"/><cs typeface=\"\"/><font script=\"Jpan\" typeface=\"MS Pゴシック\"/><font script=\"Hang\" typeface=\"맑은 고딕\"/><font script=\"Hans\" typeface=\"宋体\"/><font script=\"Hant\" typeface=\"新細明體\"/><font script=\"Arab\" typeface=\"Arial\"/><font script=\"Hebr\" typeface=\"Arial\"/><font script=\"Thai\" typeface=\"Tahoma\"/><font script=\"Ethi\" typeface=\"Nyala\"/><font script=\"Beng\" typeface=\"Vrinda\"/><font script=\"Gujr\" typeface=\"Shruti\"/><font script=\"Khmr\" typeface=\"DaunPenh\"/><font script=\"Knda\" typeface=\"Tunga\"/><font script=\"Guru\" typeface=\"Raavi\"/><font script=\"Cans\" typeface=\"Euphemia\"/><font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><font script=\"Thaa\" typeface=\"MV Boli\"/><font script=\"Deva\" typeface=\"Mangal\"/><font script=\"Telu\" typeface=\"Gautami\"/><font script=\"Taml\" typeface=\"Latha\"/><font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><font script=\"Orya\" typeface=\"Kalinga\"/><font script=\"Mlym\" typeface=\"Kartika\"/><font script=\"Laoo\" typeface=\"DokChampa\"/><font script=\"Sinh\" typeface=\"Iskoola Pota\"/><font script=\"Mong\" typeface=\"Mongolian Baiti\"/><font script=\"Viet\" typeface=\"Arial\"/><font script=\"Uigh\" typeface=\"Microsoft Uighur\"/></minorFont></fontScheme><fmtScheme name=\"Office\"><fillStyleLst><solidFill><schemeClr val=\"phClr\"/></solidFill><gradFill rotWithShape=\"1\"><gsLst><gs pos=\"0\"><schemeClr val=\"phClr\"><tint val=\"50000\"/><satMod val=\"300000\"/></schemeClr></gs><gs pos=\"35000\"><schemeClr val=\"phClr\"><tint val=\"37000\"/><satMod val=\"300000\"/></schemeClr></gs><gs pos=\"100000\"><schemeClr val=\"phClr\"><tint val=\"15000\"/><satMod val=\"350000\"/></schemeClr></gs></gsLst><lin ang=\"16200000\" scaled=\"1\"/></gradFill><gradFill rotWithShape=\"1\"><gsLst><gs pos=\"0\"><schemeClr val=\"phClr\"><shade val=\"51000\"/><satMod val=\"130000\"/></schemeClr></gs><gs pos=\"80000\"><schemeClr val=\"phClr\"><shade val=\"93000\"/><satMod val=\"130000\"/></schemeClr></gs><gs pos=\"100000\"><schemeClr val=\"phClr\"><shade val=\"94000\"/><satMod val=\"135000\"/></schemeClr></gs></gsLst><lin ang=\"16200000\" scaled=\"0\"/></gradFill></fillStyleLst><lnStyleLst><ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><solidFill><schemeClr val=\"phClr\"><shade val=\"95000\"/><satMod val=\"105000\"/></schemeClr></solidFill><prstDash val=\"solid\"/></ln><ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><solidFill><schemeClr val=\"phClr\"/></solidFill><prstDash val=\"solid\"/></ln><ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><solidFill><schemeClr val=\"phClr\"/></solidFill><prstDash val=\"solid\"/></ln></lnStyleLst><effectStyleLst><effectStyle><effectLst><outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\"><srgbClr val=\"000000\"><alpha val=\"38000\"/></srgbClr></outerShdw></effectLst></effectStyle><effectStyle><effectLst><outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\"><srgbClr val=\"000000\"><alpha val=\"35000\"/></srgbClr></outerShdw></effectLst></effectStyle><effectStyle><effectLst><outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\"><srgbClr val=\"000000\"><alpha val=\"35000\"/></srgbClr></outerShdw></effectLst><scene3d><camera prst=\"orthographicFront\"><rot lat=\"0\" lon=\"0\" rev=\"0\"/></camera><lightRig rig=\"threePt\" dir=\"t\"><rot lat=\"0\" lon=\"0\" rev=\"1200000\"/></lightRig></scene3d><sp3d><bevelT w=\"63500\" h=\"25400\"/></sp3d></effectStyle></effectStyleLst><bgFillStyleLst><solidFill><schemeClr val=\"phClr\"/></solidFill><gradFill rotWithShape=\"1\"><gsLst><gs pos=\"0\"><schemeClr val=\"phClr\"><tint val=\"40000\"/><satMod val=\"350000\"/></schemeClr></gs><gs pos=\"40000\"><schemeClr val=\"phClr\"><tint val=\"45000\"/><shade val=\"99000\"/><satMod val=\"350000\"/></schemeClr></gs><gs pos=\"100000\"><schemeClr val=\"phClr\"><shade val=\"20000\"/><satMod val=\"255000\"/></schemeClr></gs></gsLst><path path=\"circle\"><fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/></path></gradFill><gradFill rotWithShape=\"1\"><gsLst><gs pos=\"0\"><schemeClr val=\"phClr\"><tint val=\"80000\"/><satMod val=\"300000\"/></schemeClr></gs><gs pos=\"100000\"><schemeClr val=\"phClr\"><shade val=\"30000\"/><satMod val=\"200000\"/></schemeClr></gs></gsLst><path path=\"circle\"><fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/></path></gradFill></bgFillStyleLst></fmtScheme></themeElements><objectDefaults/><extraClrSchemeLst/>" OPTIONAL_LINE_BREAK
  217. "</theme>" OPTIONAL_LINE_BREAK;
  218. #endif
  219. #ifndef WITHOUT_XLSX_SHAREDSTRINGS
  220. const char* sharedstrings_xml =
  221. XML_HEADER
  222. "<sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"/>" OPTIONAL_LINE_BREAK;
  223. //"<sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"0\" uniqueCount=\"0\"/>" OPTIONAL_LINE_BREAK;
  224. //"<sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"1\" uniqueCount=\"1\">" OPTIONAL_LINE_BREAK
  225. //"<si><t></t></si>" OPTIONAL_LINE_BREAK
  226. //"</sst>" OPTIONAL_LINE_BREAK;
  227. #endif
  228. const char* workbook_rels_xml =
  229. XML_HEADER
  230. "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">" OPTIONAL_LINE_BREAK
  231. #ifndef WITHOUT_XLSX_STYLES
  232. "<Relationship Id=\"" XML_WORKBOOK_RELID_XL_STYLES "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"" XML_FILENAME_XL_STYLES "\"/>" OPTIONAL_LINE_BREAK
  233. #endif
  234. "<Relationship Id=\"" XML_WORKBOOK_RELID_XL_WORKSHEET1 "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"" XML_FOLDER_WORKSHEETS XML_FILENAME_XL_WORKSHEET1 "\"/>" OPTIONAL_LINE_BREAK
  235. #ifndef WITHOUT_XLSX_SHAREDSTRINGS
  236. "<Relationship Id=\"" XML_WORKBOOK_RELID_XL_SHAREDSTRINGS "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings\" Target=\"" XML_FILENAME_XL_SHAREDSTRINGS "\"/>" OPTIONAL_LINE_BREAK
  237. #endif
  238. #ifndef WITHOUT_XLSX_THEMES
  239. "<Relationship Id=\"" XML_WORKBOOK_RELID_XL_THEME1 "\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme\" Target=\"" XML_FOLDER_THEMES XML_FILENAME_XL_THEME1 "\"/>" OPTIONAL_LINE_BREAK
  240. #endif
  241. "</Relationships>" OPTIONAL_LINE_BREAK;
  242. const char* workbook_xml =
  243. XML_HEADER
  244. "<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">" OPTIONAL_LINE_BREAK
  245. //"<workbookPr/>" OPTIONAL_LINE_BREAK
  246. "<bookViews>" OPTIONAL_LINE_BREAK
  247. //"<workbookView/>" OPTIONAL_LINE_BREAK
  248. "<workbookView activeTab=\"0\"/>" OPTIONAL_LINE_BREAK
  249. //"<workbookView activeTab=\"0\" xWindow=\"0\" yWindow=\"0\"/>" OPTIONAL_LINE_BREAK
  250. "</bookViews>" OPTIONAL_LINE_BREAK
  251. "<sheets>" OPTIONAL_LINE_BREAK
  252. "<sheet name=\"%s\" sheetId=\"1\" r:id=\"" XML_WORKBOOK_RELID_XL_WORKSHEET1 "\"/>" OPTIONAL_LINE_BREAK
  253. "</sheets>" OPTIONAL_LINE_BREAK
  254. "</workbook>" OPTIONAL_LINE_BREAK;
  255. const char* worksheet_xml_begin =
  256. XML_HEADER
  257. "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">" OPTIONAL_LINE_BREAK;
  258. //"<dimension ref=\"A1\"/> OPTIONAL_LINE_BREAK"
  259. const char* worksheet_xml_freeze_top_row =
  260. "<sheetViews>" OPTIONAL_LINE_BREAK
  261. "<sheetView tabSelected=\"1\" workbookViewId=\"0\">" OPTIONAL_LINE_BREAK
  262. "<pane ySplit=\"1\" topLeftCell=\"A2\" activePane=\"bottomLeft\" state=\"frozen\"/>" OPTIONAL_LINE_BREAK
  263. "<selection pane=\"bottomLeft\"/>" OPTIONAL_LINE_BREAK
  264. "</sheetView>" OPTIONAL_LINE_BREAK
  265. "</sheetViews>" OPTIONAL_LINE_BREAK;
  266. const char* worksheet_xml_start_data =
  267. "<sheetData>" OPTIONAL_LINE_BREAK;
  268. const char* worksheet_xml_end =
  269. "</sheetData>" OPTIONAL_LINE_BREAK
  270. //"<pageMargins left=\"0.75\" right=\"0.75\" top=\"1\" bottom=\"1\" header=\"0.5\" footer=\"0.5\"/>" OPTIONAL_LINE_BREAK
  271. "</worksheet>" OPTIONAL_LINE_BREAK;
  272. ////////////////////////////////////////////////////////////////////////
  273. #ifdef USE_LIBZIP
  274. zip_int64_t zip_file_add_custom (ZIPFILETYPE* zip, const char* filename, zip_source_t* zipsrc)
  275. {
  276. zip_int64_t index;
  277. if ((index = zip_file_add(zip, filename, zipsrc, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8)) >= 0) {
  278. zip_set_file_compression(zip, index, ZIP_CM_DEFLATE, 9);
  279. //zip_set_file_compression(zip, index, ZIP_CM_DEFLATE, 5);
  280. //zip_set_file_compression(zip, index, ZIP_CM_STORE, 0);
  281. //zip_file_set_external_attributes(zip, index, 0, ZIP_OPSYS_DOS, 0);
  282. zip_file_set_external_attributes(zip, index, 0, ZIP_OPSYS_VFAT, 0);
  283. //zip_file_set_comment(zip, index, "Test", 4, ZIP_FL_ENC_UTF_8);
  284. //zip_file_set_mtime(zip, index, time(NULL), 0);
  285. //zip_file_extra_field_delete(zip, index, ZIP_EXTRA_FIELD_ALL, ZIP_FL_CENTRAL | ZIP_FL_LOCAL);
  286. }
  287. return index;
  288. }
  289. #endif
  290. int zip_add_content_buffer (ZIPFILETYPE* zip, const char* filename, const char* buf, size_t buflen, int mustfree)
  291. {
  292. #ifdef USE_MINIZIP
  293. zip_fileinfo zipinfo;
  294. time_t now = time(NULL);
  295. struct tm* newtm = localtime(&now);
  296. zipinfo.tmz_date.tm_sec = newtm->tm_sec;
  297. zipinfo.tmz_date.tm_min = newtm->tm_min;
  298. zipinfo.tmz_date.tm_hour = newtm->tm_hour;
  299. zipinfo.tmz_date.tm_mday = newtm->tm_mday;
  300. zipinfo.tmz_date.tm_mon = newtm->tm_mon;
  301. zipinfo.tmz_date.tm_year = newtm->tm_year;
  302. zipinfo.dosDate = 0;
  303. zipinfo.internal_fa = 0;
  304. zipinfo.external_fa = 0;
  305. if (zipOpenNewFileInZip(zip, filename, &zipinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, 9) != ZIP_OK) {
  306. fprintf(stderr, "Error creating file \"%s\" inside zip file\n", filename);/////
  307. return 1;
  308. }
  309. if (zipWriteInFileInZip(zip, buf, buflen) != ZIP_OK) {
  310. fprintf(stderr, "Error writing to file \"%s\" inside zip file\n", filename);/////
  311. return 1;
  312. }
  313. zipCloseFileInZip(zip);
  314. if (mustfree)
  315. free((char*)buf);
  316. #else
  317. zip_source_t* zipsrc;
  318. if ((zipsrc = zip_source_buffer(zip, buf, buflen, mustfree)) == NULL) {
  319. fprintf(stderr, "Error creating file \"%s\" inside zip file\n", filename);/////
  320. return 1;
  321. }
  322. if (zip_file_add_custom(zip, filename, zipsrc) < 0) {
  323. fprintf(stderr, "Error in zip_file_add for file %s\n", filename);/////
  324. zip_source_free(zipsrc);
  325. return 2;
  326. }
  327. #endif
  328. return 0;
  329. }
  330. int zip_add_static_content_string (ZIPFILETYPE* zip, const char* filename, const char* data)
  331. {
  332. return zip_add_content_buffer(zip, filename, data, strlen(data), 0);
  333. }
  334. int zip_add_dynamic_content_string (ZIPFILETYPE* zip, const char* filename, const char* data, ...)
  335. {
  336. int result;
  337. char* buf;
  338. int buflen;
  339. va_list args;
  340. va_start(args, data);
  341. buflen = vsnprintf(NULL, 0, data, args);
  342. if (buflen < 0 || (buf = (char*)malloc(buflen + 1)) == NULL) {
  343. result = -1;
  344. } else {
  345. va_end(args);
  346. va_start(args, data);
  347. vsnprintf(buf, buflen + 1, data, args);
  348. result = zip_add_content_buffer(zip, filename, buf, buflen, 1);
  349. }
  350. va_end(args);
  351. return result;
  352. }
  353. ////////////////////////////////////////////////////////////////////////
  354. //replace part of a string
  355. char* str_replace (char** s, size_t pos, size_t len, char* replacement)
  356. {
  357. if (!s || !*s)
  358. return NULL;
  359. size_t totallen = strlen(*s);
  360. size_t replacementlen = strlen(replacement);
  361. if (pos > totallen)
  362. pos = totallen;
  363. if (pos + len > totallen)
  364. len = totallen - pos;
  365. if (replacementlen > len)
  366. if ((*s = (char*)realloc(*s, totallen - len + replacementlen + 1)) == NULL)
  367. return NULL;
  368. memmove(*s + pos + replacementlen, *s + pos + len, totallen - pos - len + 1);
  369. memcpy(*s + pos, replacement, replacementlen);
  370. return *s;
  371. }
  372. //fix string for use as XML data
  373. char* fix_xml_special_chars (char** s)
  374. {
  375. int pos = 0;
  376. while (*s && (*s)[pos]) {
  377. switch ((*s)[pos]) {
  378. case '&' :
  379. str_replace(s, pos, 1, "&amp;");
  380. pos += 5;
  381. break;
  382. case '\"' :
  383. str_replace(s, pos, 1, "&quot;");
  384. pos += 6;
  385. break;
  386. case '\'' :
  387. str_replace(s, pos, 1, "&apos;");
  388. pos += 6;
  389. break;
  390. case '<' :
  391. str_replace(s, pos, 1, "&lt;");
  392. pos += 4;
  393. break;
  394. case '>' :
  395. str_replace(s, pos, 1, "&gt;");
  396. pos += 4;
  397. break;
  398. case '\r' :
  399. str_replace(s, pos, 1, "");
  400. break;
  401. default:
  402. pos++;
  403. break;
  404. }
  405. }
  406. return *s;
  407. }
  408. /*
  409. //add data to a null-terminated buffer and update the length counter
  410. int vappend_data (char** pdata, size_t* pdatalen, const char* format, va_list args)
  411. {
  412. int len;
  413. va_list args2;
  414. va_copy(args2, args);
  415. //va_start(args, format);
  416. if ((len = vsnprintf(NULL, 0, format, args)) < 0)
  417. return -1;
  418. va_end(args);
  419. if ((*pdata = (char*)realloc(*pdata, *pdatalen + len + 1)) == NULL)
  420. return -1;
  421. vsnprintf(*pdata + *pdatalen, len + 1, format, args2);
  422. va_end(args2);
  423. *pdatalen += len;
  424. return len;
  425. }
  426. //add formatted data to a null-terminated buffer and update the length counter
  427. int append_data (char** pdata, size_t* pdatalen, const char* format, ...)
  428. {
  429. int result;
  430. va_list args;
  431. va_start(args, format);
  432. result = vappend_data(pdata, pdatalen, format, args);
  433. va_end(args);
  434. return result;
  435. }
  436. */
  437. //add formatted data to a null-terminated buffer and update the length counter
  438. int append_data (char** pdata, size_t* pdatalen, const char* format, ...)
  439. {
  440. int len;
  441. va_list args;
  442. va_start(args, format);
  443. len = vsnprintf(NULL, 0, format, args);
  444. va_end(args);
  445. if (len < 0)
  446. return -1;
  447. if ((*pdata = (char*)realloc(*pdata, *pdatalen + len + 1)) == NULL)
  448. return -1;
  449. va_start(args, format);
  450. vsnprintf(*pdata + *pdatalen, len + 1, format, args);
  451. va_end(args);
  452. *pdatalen += len;
  453. return len;
  454. }
  455. #ifndef NO_COLUMN_NUMBERS
  456. /*
  457. //insert formatted data into a null-terminated buffer at the specified position and update the length counter
  458. int insert_data (char** pdata, size_t* pdatalen, size_t pos, const char* format, ...)
  459. {
  460. int len;
  461. va_list args;
  462. va_start(args, format);
  463. len = vsnprintf(NULL, 0, format, args);
  464. va_end(args);
  465. if (len < 0)
  466. return -1;
  467. if ((*pdata = (char*)realloc(*pdata, *pdatalen + len + 1)) == NULL)
  468. return -1;
  469. if (pos > *pdatalen)
  470. pos = *pdatalen;
  471. if (pos < *pdatalen)
  472. memmove(*pdata + pos + len, *pdata + pos, *pdatalen - pos + 1);
  473. else
  474. (*pdata)[pos + len] = 0;
  475. va_start(args, format);
  476. len = vsnprintf(*pdata + pos, len, format, args);
  477. va_end(args);
  478. *pdatalen += len;
  479. return len;
  480. }
  481. char* get_A1col (uint64_t col)
  482. {
  483. char* result = NULL;
  484. size_t resultlen = 0;
  485. if (col > 0) {
  486. do {
  487. col--;
  488. insert_data(&result, &resultlen, 0, "%c", 'A' + (col % 26));
  489. col = col / 26;
  490. } while (col > 0);
  491. }
  492. return result;
  493. }
  494. */
  495. char* get_A1col (uint64_t col)
  496. {
  497. char* result = NULL;
  498. size_t resultlen = 0;
  499. //allocate 19 bytes as the maximum value for 64-bit devided by 26 has 18 digits
  500. if (col > 0 && (result = (char*)malloc(19)) != NULL) {
  501. result[0] = 0;
  502. do {
  503. col--;
  504. memmove(result + 1, result, ++resultlen);
  505. result[0] = 'A' + (col % 26);
  506. col = col / 26;
  507. } while (col > 0);
  508. }
  509. return result;
  510. }
  511. #endif
  512. #define need_space_preserve_attr(value) 1
  513. /*
  514. int need_space_preserve_attr (const char* value)
  515. {
  516. /////TO DO: return non-zero only if space at beginning or end, or contains multiple consecutive spaces
  517. return 1;
  518. }
  519. */
  520. ////////////////////////////////////////////////////////////////////////
  521. struct column_info_struct {
  522. int width;
  523. int maxwidth;
  524. struct column_info_struct* next;
  525. };
  526. struct xlsxio_write_struct {
  527. char* filename;
  528. char* sheetname;
  529. ZIPFILETYPE* zip;
  530. #ifdef USE_WINTHREADS
  531. HANDLE thread;
  532. #else
  533. pthread_t thread;
  534. #endif
  535. FILE* pipe_read;
  536. FILE* pipe_write;
  537. struct column_info_struct* columninfo;
  538. struct column_info_struct** pcurrentcolumn;
  539. char* buf;
  540. size_t buflen;
  541. size_t rowstobuffer;
  542. size_t rowheight;
  543. int freezetop;
  544. int sheetopen;
  545. int rowopen;
  546. #ifndef NO_ROW_NUMBERS
  547. uint64_t rownr;
  548. #ifndef NO_COLUMN_NUMBERS
  549. uint64_t colnr;
  550. #endif
  551. #endif
  552. };
  553. #ifndef NO_ROW_NUMBERS
  554. #define ROWNRTAG " r=\"%" PRIu64 "\""
  555. #define ROWNRPARAM(handle) , handle->rownr
  556. #ifndef NO_COLUMN_NUMBERS
  557. #define COLNRTAG " r=\"%s%" PRIu64 "\""
  558. #endif
  559. #endif
  560. //thread function used for creating .xlsx file from pipe
  561. #ifdef USE_WINTHREADS
  562. DWORD WINAPI thread_proc (LPVOID arg)
  563. #else
  564. void* thread_proc (void* arg)
  565. #endif
  566. {
  567. xlsxiowriter handle = (xlsxiowriter)arg;
  568. //generate required files
  569. zip_add_static_content_string(handle->zip, XML_FILENAME_CONTENTTYPES, content_types_xml);
  570. zip_add_static_content_string(handle->zip, XML_FOLDER_DOCPROPS XML_FILENAME_DOCPROPS_CORE, docprops_core_xml);
  571. zip_add_static_content_string(handle->zip, XML_FOLDER_DOCPROPS XML_FILENAME_DOCPROPS_APP, docprops_app_xml);
  572. zip_add_static_content_string(handle->zip, XML_FOLDER_RELS XML_FILENAME_RELS, rels_xml);
  573. #ifndef WITHOUT_XLSX_STYLES
  574. zip_add_static_content_string(handle->zip, XML_FOLDER_XL XML_FILENAME_XL_STYLES, styles_xml);
  575. #endif
  576. #ifndef WITHOUT_XLSX_THEMES
  577. zip_add_static_content_string(handle->zip, XML_FOLDER_XL XML_FOLDER_THEMES XML_FILENAME_XL_THEME1, theme_xml);
  578. #endif
  579. zip_add_static_content_string(handle->zip, XML_FOLDER_XL XML_FOLDER_RELS XML_FILENAME_XL_WORKBOOK_RELS, workbook_rels_xml);
  580. { //TO DO: this crashes on Linux
  581. char* sheetname = NULL;
  582. if (handle->sheetname) {
  583. sheetname = strdup(handle->sheetname);
  584. if (sheetname) {
  585. if (strlen(sheetname) > XML_SHEETNAME_MAXLEN)
  586. sheetname[XML_SHEETNAME_MAXLEN] = 0;
  587. fix_xml_special_chars(&sheetname);
  588. }
  589. }
  590. zip_add_dynamic_content_string(handle->zip, XML_FOLDER_XL XML_FILENAME_XL_WORKBOOK, workbook_xml, (sheetname ? sheetname : "Sheet1"));
  591. free(sheetname);
  592. }
  593. #ifndef WITHOUT_XLSX_SHAREDSTRINGS
  594. zip_add_static_content_string(handle->zip, XML_FOLDER_XL XML_FILENAME_XL_SHAREDSTRINGS, sharedstrings_xml);
  595. #endif
  596. //add sheet content file with pipe data
  597. #ifdef USE_MINIZIP
  598. #define MINIZIP_PIPE_BUFFER_SIZE 1024
  599. //#error TO DO:
  600. if (zipOpenNewFileInZip(handle->zip, XML_FOLDER_XL XML_FOLDER_WORKSHEETS XML_FILENAME_XL_WORKSHEET1, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, 9) != ZIP_OK) {
  601. fprintf(stderr, "Error adding file");
  602. } else {
  603. char* buf;
  604. size_t buflen;
  605. if ((buf = (char*)malloc(MINIZIP_PIPE_BUFFER_SIZE)) == NULL) {
  606. fprintf(stderr, "Memory allocation error");/////
  607. } else {
  608. while ((buflen = fread(buf, 1, MINIZIP_PIPE_BUFFER_SIZE, handle->pipe_read)) > 0) {
  609. if (zipWriteInFileInZip(handle->zip, buf, buflen) != ZIP_OK) {
  610. fprintf(stderr, "Error writing file inside archive");/////
  611. break;
  612. }
  613. }
  614. free(buf);
  615. }
  616. fclose(handle->pipe_read);
  617. zipCloseFileInZip(handle->zip);
  618. zipClose(handle->zip, NULL);
  619. }
  620. #else
  621. zip_source_t* zipsrc = zip_source_filep(handle->zip, handle->pipe_read, 0, -1);
  622. if (zip_file_add_custom(handle->zip, XML_FOLDER_XL XML_FOLDER_WORKSHEETS XML_FILENAME_XL_WORKSHEET1, zipsrc) < 0) {
  623. zip_source_free(zipsrc);
  624. fprintf(stderr, "Error adding file");
  625. }
  626. #ifdef ZIP_RDONLY
  627. zip_file_set_mtime(handle->zip, zip_get_num_entries(handle->zip, 0) - 1, time(NULL), 0);
  628. #endif
  629. //close zip file (processes all data, will block until pipe is closed)
  630. if (zip_close(handle->zip) != 0) {
  631. int ze, se;
  632. #ifdef ZIP_RDONLY
  633. zip_error_t* error = zip_get_error(handle->zip);
  634. ze = zip_error_code_zip(error);
  635. se = zip_error_code_system(error);
  636. #else
  637. zip_error_get(handle->zip, &ze, &se);
  638. #endif
  639. fprintf(stderr, "zip_close failed (%i,%i)\n", ze, se);/////
  640. fprintf(stderr, "can't close zip archive : %s\n", zip_strerror(handle->zip));
  641. }
  642. #endif
  643. handle->zip = NULL;
  644. handle->pipe_read = NULL;
  645. #ifdef USE_WINTHREADS
  646. return 0;
  647. #else
  648. return NULL;
  649. #endif
  650. }
  651. ////////////////////////////////////////////////////////////////////////
  652. DLL_EXPORT_XLSXIO xlsxiowriter xlsxiowrite_open (const char* filename, const char* sheetname)
  653. {
  654. xlsxiowriter handle;
  655. if (!filename)
  656. return NULL;
  657. if ((handle = (xlsxiowriter)malloc(sizeof(struct xlsxio_write_struct))) != NULL) {
  658. int pipefd[2];
  659. //initialize
  660. handle->filename = strdup(filename);
  661. handle->sheetname = (sheetname ? strdup(sheetname) : NULL);
  662. handle->zip = NULL;
  663. //handle->pipe_read = NULL;
  664. //handle->pipe_write = NULL;
  665. handle->columninfo = NULL;
  666. handle->pcurrentcolumn = &handle->columninfo;
  667. handle->buf = NULL;
  668. handle->buflen = 0;
  669. handle->rowstobuffer = DEFAULT_BUFFERED_ROWS;
  670. handle->rowheight = 0;
  671. handle->freezetop = 0;
  672. handle->sheetopen = 0;
  673. handle->rowopen = 0;
  674. #ifndef NO_ROW_NUMBERS
  675. handle->rownr = 0;
  676. #ifndef NO_COLUMN_NUMBERS
  677. handle->colnr = 0;
  678. #endif
  679. #endif
  680. //remove filename first if it already exists
  681. unlink(filename);
  682. //initialize zip file object
  683. #ifdef USE_MINIZIP
  684. if ((handle->zip = zipOpen(handle->filename, 0)) == NULL) {
  685. #else
  686. if ((handle->zip = zip_open(handle->filename, ZIP_CREATE, NULL)) == NULL) {
  687. #endif
  688. fprintf(stderr, "Error writing to file %s\n", filename);/////
  689. //unlink(filename);
  690. free(handle->filename);
  691. free(handle);
  692. return NULL;
  693. }
  694. //create pipe
  695. if (pipe(pipefd) != 0) {
  696. fprintf(stderr, "Error creating pipe\n");/////
  697. free(handle);
  698. return NULL;
  699. }
  700. handle->pipe_read = fdopen(pipefd[0], "rb");
  701. handle->pipe_write = fdopen(pipefd[1], "wb");
  702. //create and start thread that will receive data via pipe
  703. #ifdef USE_WINTHREADS
  704. if ((handle->thread = CreateThread(NULL, 0, thread_proc, handle, 0, NULL)) == NULL) {
  705. #else
  706. if (pthread_create(&handle->thread, NULL, thread_proc, handle) != 0) {
  707. #endif
  708. fprintf(stderr, "Error creating thread\n");/////
  709. #ifdef USE_MINIZIP
  710. zipClose(handle->zip, NULL);
  711. #else
  712. zip_close(handle->zip);
  713. #endif
  714. //unlink(filename);
  715. free(handle->filename);
  716. fclose(handle->pipe_read);
  717. fclose(handle->pipe_write);
  718. free(handle);
  719. return NULL;
  720. }
  721. //write initial worksheet data
  722. fprintf(handle->pipe_write, "%s", worksheet_xml_begin);
  723. }
  724. return handle;
  725. }
  726. void flush_buffer (xlsxiowriter handle);
  727. DLL_EXPORT_XLSXIO int xlsxiowrite_close (xlsxiowriter handle)
  728. {
  729. struct column_info_struct* colinfo;
  730. struct column_info_struct* colinfonext;
  731. if (!handle)
  732. return -1;
  733. //finalize data
  734. if (handle->pipe_write) {
  735. //check if buffer should be flushed
  736. if (!handle->sheetopen)
  737. flush_buffer(handle);
  738. //close row if needed
  739. if (handle->rowopen)
  740. fprintf(handle->pipe_write, "</row>" OPTIONAL_LINE_BREAK);
  741. //write worksheet data
  742. fprintf(handle->pipe_write, "%s", worksheet_xml_end);
  743. //close pipe
  744. fclose(handle->pipe_write);
  745. }
  746. //wait for thread to finish
  747. #ifdef USE_WINTHREADS
  748. WaitForSingleObject(handle->thread, INFINITE);
  749. #else
  750. pthread_join(handle->thread, NULL);
  751. #endif
  752. //clean up
  753. colinfo = handle->columninfo;
  754. while (colinfo) {
  755. colinfonext = colinfo->next;
  756. free(colinfo);
  757. colinfo = colinfonext;
  758. }
  759. free(handle->filename);
  760. free(handle->sheetname);
  761. if (handle->zip)
  762. #ifdef USE_MINIZIP
  763. zipClose(handle->zip, NULL);
  764. #else
  765. zip_close(handle->zip);
  766. #endif
  767. if (handle->pipe_read)
  768. fclose(handle->pipe_read);
  769. free(handle);
  770. return 0;
  771. }
  772. #ifndef WITHOUT_XLSX_STYLES
  773. #define STYLE_ATTR_HELPER(x) #x
  774. #define STYLE_ATTR(style) " s=\"" STYLE_ATTR_HELPER(style) "\""
  775. #else
  776. #define STYLE_ATTR(style) ""
  777. #endif
  778. //output start of row
  779. void write_row_start (xlsxiowriter handle, const char* rowattr)
  780. {
  781. #ifndef NO_ROW_NUMBERS
  782. handle->rownr++;
  783. #ifndef NO_COLUMN_NUMBERS
  784. handle->colnr = 0;
  785. #endif
  786. #endif
  787. if (handle->sheetopen) {
  788. if (!handle->rowheight)
  789. fprintf(handle->pipe_write, "<row%s" ROWNRTAG ">", (rowattr ? rowattr : "") ROWNRPARAM(handle));
  790. else
  791. fprintf(handle->pipe_write, "<row ht=\"%.6G\" customHeight=\"1\"%s" ROWNRTAG ">", CALCULATE_COLUMN_HEIGHT(handle->rowheight), (rowattr ? rowattr : "") ROWNRPARAM(handle));
  792. } else {
  793. if (!handle->rowheight)
  794. append_data(&handle->buf, &handle->buflen, "<row%s" ROWNRTAG ">", (rowattr ? rowattr : "") ROWNRPARAM(handle));
  795. else
  796. append_data(&handle->buf, &handle->buflen, "<row ht=\"%.6G\" customHeight=\"1\"%s" ROWNRTAG ">", CALCULATE_COLUMN_HEIGHT(handle->rowheight), (rowattr ? rowattr : "") ROWNRPARAM(handle));
  797. }
  798. handle->rowopen = 1;
  799. }
  800. //output cell data
  801. void write_cell_data (xlsxiowriter handle, const char* rowattr, const char* prefix, const char* suffix, const char* format, ...)
  802. {
  803. va_list args;
  804. #if !defined(NO_ROW_NUMBERS) && !defined(NO_COLUMN_NUMBERS)
  805. char* cellcoord;
  806. #endif
  807. if (!handle)
  808. return;
  809. //start new row if needed
  810. if (!handle->rowopen)
  811. write_row_start(handle, rowattr);
  812. //get formatted data
  813. int datalen;
  814. char* data;
  815. va_start(args, format);
  816. if (format && (datalen = vsnprintf(NULL, 0, format, args)) >= 0 && (data = (char*)malloc(datalen + 1)) != NULL) {
  817. va_end(args);
  818. va_start(args, format);
  819. vsnprintf(data, datalen + 1, format, args);
  820. //prepare data for XML output
  821. fix_xml_special_chars(&data);
  822. } else {
  823. data = NULL;
  824. datalen = 0;
  825. }
  826. va_end(args);
  827. //determine cell coordinate
  828. #if !defined(NO_ROW_NUMBERS) && !defined(NO_COLUMN_NUMBERS)
  829. cellcoord = get_A1col(++handle->colnr);
  830. #define COLNRPARAM(handle) , cellcoord, handle->rownr
  831. #else
  832. #define COLNRPARAM(handle)
  833. #endif
  834. //add cell data
  835. if (handle->sheetopen) {
  836. //write cell data
  837. if (prefix)
  838. fprintf(handle->pipe_write, prefix COLNRPARAM(handle));
  839. if (data)
  840. fprintf(handle->pipe_write, "%s", data);
  841. if (suffix)
  842. fprintf(handle->pipe_write, "%s", suffix);
  843. } else {
  844. //add cell data to buffer
  845. if (prefix)
  846. append_data(&handle->buf, &handle->buflen, prefix COLNRPARAM(handle));
  847. if (data)
  848. append_data(&handle->buf, &handle->buflen, "%s", data);
  849. if (suffix)
  850. append_data(&handle->buf, &handle->buflen, suffix);
  851. //collect cell information
  852. if (!handle->sheetopen) {
  853. if (!*handle->pcurrentcolumn) {
  854. //create new column information structure
  855. struct column_info_struct* colinfo;
  856. if ((colinfo = (struct column_info_struct*)malloc(sizeof(struct column_info_struct))) != NULL) {
  857. colinfo->width = 0;
  858. colinfo->maxwidth = 0;
  859. colinfo->next = NULL;
  860. *handle->pcurrentcolumn = colinfo;
  861. }
  862. }
  863. //keep track of biggest column width
  864. if (data) {
  865. //only count first line in multiline data
  866. char* p = strchr(data, '\n');
  867. if (p)
  868. datalen = p - data;
  869. //remember this length if it is the longest one so far
  870. if (datalen > 0 && datalen > (*handle->pcurrentcolumn)->maxwidth)
  871. (*handle->pcurrentcolumn)->maxwidth = datalen;
  872. }
  873. //prepare for the next column
  874. handle->pcurrentcolumn = &(*handle->pcurrentcolumn)->next;
  875. }
  876. }
  877. #if !defined(NO_ROW_NUMBERS) && !defined(NO_COLUMN_NUMBERS)
  878. free(cellcoord);
  879. #endif
  880. free(data);
  881. }
  882. //output buffered data and stop buffering
  883. void flush_buffer (xlsxiowriter handle)
  884. {
  885. //write section to freeze top row
  886. if (handle->freezetop > 0)
  887. fprintf(handle->pipe_write, "%s", worksheet_xml_freeze_top_row);
  888. //default to row height of 1 line
  889. //fprintf(handle->pipe_write, "<sheetFormatPr defaultRowHeight=\"%.6G\" customHeight=\"1\"/> OPTIONAL_LINE_BREAK", (double)12.75);
  890. //write column information
  891. if (handle->columninfo) {
  892. int col = 0;
  893. int len;
  894. struct column_info_struct* colinfo = handle->columninfo;
  895. fprintf(handle->pipe_write, "<cols>");
  896. while (colinfo) {
  897. ++col;
  898. //determine column width
  899. len = colinfo->width;
  900. if (len == 0) {
  901. //use detected maximum length if column width specified was zero
  902. if (colinfo->maxwidth > 0)
  903. len = colinfo->maxwidth;
  904. } else if (len < 0) {
  905. //use detected maximum length if column width specified was negative and the detected maximum length is larger than the absolute value of the specified width
  906. len = -len;
  907. if (colinfo->maxwidth > len)
  908. len = colinfo->maxwidth;
  909. }
  910. if (len)
  911. fprintf(handle->pipe_write, "<col min=\"%i\" max=\"%i\" width=\"%.6G\" customWidth=\"1\"/>" OPTIONAL_LINE_BREAK, col, col, CALCULATE_COLUMN_WIDTH(len));
  912. else
  913. fprintf(handle->pipe_write, "<col min=\"%i\" max=\"%i\"/>" OPTIONAL_LINE_BREAK, col, col);
  914. colinfo = colinfo->next;
  915. }
  916. fprintf(handle->pipe_write, "</cols>" OPTIONAL_LINE_BREAK);
  917. }
  918. //write initial data
  919. fprintf(handle->pipe_write, "%s", worksheet_xml_start_data);
  920. //write buffer and clear it
  921. if (handle->buf) {
  922. if (handle->buflen > 0)
  923. fwrite(handle->buf, 1, handle->buflen, handle->pipe_write);
  924. free(handle->buf);
  925. handle->buf = NULL;
  926. }
  927. handle->buflen = 0;
  928. handle->sheetopen = 1;
  929. }
  930. DLL_EXPORT_XLSXIO void xlsxiowrite_set_detection_rows (xlsxiowriter handle, size_t rows)
  931. {
  932. //abort if currently not buffering
  933. if (!handle->rowstobuffer || handle->sheetopen)
  934. return;
  935. //set number of rows to buffer
  936. handle->rowstobuffer = rows;
  937. //flush when zero was specified
  938. if (!rows)
  939. flush_buffer(handle);
  940. }
  941. DLL_EXPORT_XLSXIO void xlsxiowrite_set_row_height (xlsxiowriter handle, size_t height)
  942. {
  943. handle->rowheight = height;
  944. }
  945. DLL_EXPORT_XLSXIO void xlsxiowrite_add_column (xlsxiowriter handle, const char* value, int width)
  946. {
  947. struct column_info_struct** pcolinfo = handle->pcurrentcolumn;
  948. if (value) {
  949. if (need_space_preserve_attr(value))
  950. write_cell_data(handle, STYLE_ATTR(STYLE_HEADER), "<c t=\"inlineStr\"" STYLE_ATTR(STYLE_HEADER) COLNRTAG "><is xml:space=\"preserve\"><t>", "</t></is></c>", "%s", value);
  951. else
  952. write_cell_data(handle, STYLE_ATTR(STYLE_HEADER), "<c t=\"inlineStr\"" STYLE_ATTR(STYLE_HEADER) COLNRTAG "><is><t>", "</t></is></c>", "%s", value);
  953. } else {
  954. write_cell_data(handle, STYLE_ATTR(STYLE_HEADER), "<c" STYLE_ATTR(STYLE_HEADER) COLNRTAG "/>", NULL, NULL);
  955. }
  956. if (*pcolinfo)
  957. (*pcolinfo)->width = width;
  958. if (handle->freezetop == 0)
  959. handle->freezetop = 1;
  960. }
  961. DLL_EXPORT_XLSXIO void xlsxiowrite_add_cell_string (xlsxiowriter handle, const char* value)
  962. {
  963. if (value) {
  964. if (need_space_preserve_attr(value))
  965. write_cell_data(handle, NULL, "<c t=\"inlineStr\"" STYLE_ATTR(STYLE_TEXT) COLNRTAG "><is xml:space=\"preserve\"><t>", "</t></is></c>", "%s", value);
  966. else
  967. write_cell_data(handle, NULL, "<c t=\"inlineStr\"" STYLE_ATTR(STYLE_TEXT) COLNRTAG "><is><t>", "</t></is></c>", "%s", value);
  968. } else {
  969. write_cell_data(handle, NULL, "<c" STYLE_ATTR(STYLE_TEXT) COLNRTAG "/>", NULL, NULL);
  970. }
  971. }
  972. DLL_EXPORT_XLSXIO void xlsxiowrite_add_cell_int (xlsxiowriter handle, int64_t value)
  973. {
  974. write_cell_data(handle, NULL, "<c" STYLE_ATTR(STYLE_INTEGER) COLNRTAG "><v>", "</v></c>", "%" PRIi64, value);
  975. }
  976. DLL_EXPORT_XLSXIO void xlsxiowrite_add_cell_float (xlsxiowriter handle, double value)
  977. {
  978. write_cell_data(handle, NULL, "<c" STYLE_ATTR(STYLE_GENERAL) COLNRTAG "><v>", "</v></c>", "%.32G", value);
  979. }
  980. DLL_EXPORT_XLSXIO void xlsxiowrite_add_cell_datetime (xlsxiowriter handle, time_t value)
  981. {
  982. double timestamp = ((double)(value) + .499) / 86400 + 25569; //conversion from Unix to Excel timestamp
  983. write_cell_data(handle, NULL, "<c" STYLE_ATTR(STYLE_DATETIME) COLNRTAG "><v>", "</v></c>", "%.16G", timestamp);
  984. }
  985. /*
  986. Windows (And Mac Office 2011+):
  987. Unix Timestamp = (Excel Timestamp - 25569) * 86400
  988. Excel Timestamp = (Unix Timestamp / 86400) + 25569
  989. MAC OS X (pre Office 2011):
  990. Unix Timestamp = (Excel Timestamp - 24107) * 86400
  991. Excel Timestamp = (Unix Timestamp / 86400) + 24107
  992. */
  993. DLL_EXPORT_XLSXIO void xlsxiowrite_next_row (xlsxiowriter handle)
  994. {
  995. if (!handle)
  996. return;
  997. //check if buffer should be flushed
  998. if (!handle->sheetopen) {
  999. if (handle->rowstobuffer > 0) {
  1000. if (--handle->rowstobuffer == 0) {
  1001. flush_buffer(handle);
  1002. } else {
  1003. }
  1004. }
  1005. }
  1006. //start new row if needed
  1007. if (!handle->rowopen)
  1008. write_row_start(handle, NULL);
  1009. //end row
  1010. if (handle->rowstobuffer == 0)
  1011. fprintf(handle->pipe_write, "</row>" OPTIONAL_LINE_BREAK);
  1012. else
  1013. append_data(&handle->buf, &handle->buflen, "</row>" OPTIONAL_LINE_BREAK);
  1014. handle->rowopen = 0;
  1015. handle->pcurrentcolumn = &handle->columninfo;
  1016. }