├── .gitignore ├── AUTHORS ├── CMakeLists.txt ├── LICENSE ├── README ├── TODO ├── include ├── biffwriter.h ├── bsdqueue.h ├── excel.h ├── format.h ├── formula.h ├── hashhelp.h ├── io_handler.h ├── olewriter.h ├── stream.h ├── workbook.h └── worksheet.h ├── msvc ├── libexcel.dsp └── stdint.h ├── src ├── Makefile ├── Makefile.lccw32 ├── Makefile.mingw ├── biffwriter.c ├── format.c ├── formula.c ├── hashhelp.c ├── io_handler.c ├── olewriter.c ├── stream.c ├── workbook.c └── worksheet.c └── tests ├── CMakeLists.txt ├── Makefile ├── Makefile.mingw ├── example1.c ├── example2.c ├── example3.c └── merge1.c /.gitignore: -------------------------------------------------------------------------------- 1 | # git-ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | *.[oad] 6 | *.exe 7 | example* 8 | *.xls 9 | tests/merge1 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Devin Smith 2 | 3 | libexcel was based on John McNamara's (jmcnamara@cpan.org) wonderful Perl 4 | Spreadsheet-WriteExcel module. 5 | 6 | The packet stream code is Copyright (C) 2003-2005, Claudio Leite and from the 7 | bsflite AIM client. 8 | 9 | MSVC patches from Wei Mingzhi. 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT (libexcel C) 2 | CMAKE_MINIMUM_REQUIRED (VERSION 2.8) 3 | 4 | SET(CMAKE_C_FLAGS "-Wall -O2 -pipe") 5 | INCLUDE_DIRECTORIES(include) 6 | 7 | LIST(APPEND libexcel_src src/format.c src/hashhelp.c src/stream.c src/worksheet.c src/biffwriter.c src/formula.c src/olewriter.c src/workbook.c src/io_handler.c) 8 | 9 | ADD_LIBRARY(excelStatic STATIC ${libexcel_src}) 10 | ADD_LIBRARY(excel SHARED ${libexcel_src}) 11 | 12 | ADD_SUBDIRECTORY(tests) 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Some portions of this code are released under a different license. See 2 | individual files for details. 3 | ============================================================================= 4 | Copyright (c) 2010 Devin Smith 5 | Based on early versions of Spreadsheet::WriteExcel 6 | Copyright (c) 2000-2001 John McNamara 7 | 8 | Permission to use, copy, modify, and distribute this software for any 9 | purpose with or without fee is hereby granted, provided that the above 10 | copyright notice and this permission notice appear in all copies. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | 20 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | libexcel is a C based library for creating Excel XLS spreadsheets. 2 | It is heavily based on Spreadsheet::WriteExcel by John McNamara. 3 | 4 | BUILDING 5 | =========================================================================== 6 | Simply change to the src directory and execute make (or gmake on BSD 7 | systems). BSD make is currently not supported you must use GNU make. 8 | 9 | This will build a static library called libexcel.a 10 | You can then change into the tests directory to build some sample apps that 11 | utilize the library. 12 | 13 | On Windows you can use mingw32 or the lcc-win32 compiler system. 14 | You may need to alter the makefile to set paths to your compiler. 15 | 16 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Better documentation. 2 | - Add formulas. 3 | - Support newer BIFF versions. 4 | - Support xlsx (unlikely). 5 | -------------------------------------------------------------------------------- /include/biffwriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __XLS_BIFFWRITER_H__ 20 | #define __XLS_BIFFWRITER_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | struct bwctx { 27 | int byte_order; 28 | unsigned char *data; 29 | unsigned int _sz; /* Don't touch */ 30 | unsigned int datasize; 31 | 32 | void (*append) (void *xlsctx, void *data, size_t size); 33 | }; 34 | 35 | struct bwctx * bw_new(void); 36 | void bw_destroy(struct bwctx *bw); 37 | void bw_store_eof(struct bwctx *bw); 38 | void bw_store_bof(struct bwctx *bw, uint16_t type); 39 | void bw_append(void *xlsctx, void *data, size_t size); 40 | void bw_prepend(struct bwctx *bw, void *data, size_t size); 41 | 42 | void reverse(unsigned char *data, int size); 43 | 44 | #endif /* __XLS_BIFFWRITER_H__ */ 45 | -------------------------------------------------------------------------------- /include/bsdqueue.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */ 2 | /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1991, 1993 6 | * The Regents of the University of California. All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the University nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | * 32 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 33 | */ 34 | 35 | #ifndef _SYS_QUEUE_H_ 36 | #define _SYS_QUEUE_H_ 37 | 38 | /* 39 | * This file defines five types of data structures: singly-linked lists, 40 | * lists, simple queues, tail queues, and circular queues. 41 | * 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A list is headed by a single forward pointer (or an array of forward 54 | * pointers for a hash table header). The elements are doubly linked 55 | * so that an arbitrary element can be removed without a need to 56 | * traverse the list. New elements can be added to the list before 57 | * or after an existing element or at the head of the list. A list 58 | * may only be traversed in the forward direction. 59 | * 60 | * A simple queue is headed by a pair of pointers, one the head of the 61 | * list and the other to the tail of the list. The elements are singly 62 | * linked to save space, so elements can only be removed from the 63 | * head of the list. New elements can be added to the list before or after 64 | * an existing element, at the head of the list, or at the end of the 65 | * list. A simple queue may only be traversed in the forward direction. 66 | * 67 | * A tail queue is headed by a pair of pointers, one to the head of the 68 | * list and the other to the tail of the list. The elements are doubly 69 | * linked so that an arbitrary element can be removed without a need to 70 | * traverse the list. New elements can be added to the list before or 71 | * after an existing element, at the head of the list, or at the end of 72 | * the list. A tail queue may be traversed in either direction. 73 | * 74 | * A circle queue is headed by a pair of pointers, one to the head of the 75 | * list and the other to the tail of the list. The elements are doubly 76 | * linked so that an arbitrary element can be removed without a need to 77 | * traverse the list. New elements can be added to the list before or after 78 | * an existing element, at the head of the list, or at the end of the list. 79 | * A circle queue may be traversed in either direction, but has a more 80 | * complex end of list detection. 81 | * 82 | * For details on the use of these macros, see the queue(3) manual page. 83 | */ 84 | 85 | #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) 86 | #define _Q_INVALIDATE(a) (a) = ((void *)-1) 87 | #else 88 | #define _Q_INVALIDATE(a) 89 | #endif 90 | 91 | /* 92 | * Singly-linked List definitions. 93 | */ 94 | #define SLIST_HEAD(name, type) \ 95 | struct name { \ 96 | struct type *slh_first; /* first element */ \ 97 | } 98 | 99 | #define SLIST_HEAD_INITIALIZER(head) \ 100 | { NULL } 101 | 102 | #if 0 103 | #define SLIST_ENTRY(type) \ 104 | struct { \ 105 | struct type *sle_next; /* next element */ \ 106 | } 107 | #endif 108 | 109 | /* 110 | * Singly-linked List access methods. 111 | */ 112 | #define SLIST_FIRST(head) ((head)->slh_first) 113 | #define SLIST_END(head) NULL 114 | #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) 115 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 116 | 117 | #define SLIST_FOREACH(var, head, field) \ 118 | for((var) = SLIST_FIRST(head); \ 119 | (var) != SLIST_END(head); \ 120 | (var) = SLIST_NEXT(var, field)) 121 | 122 | #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 123 | for ((varp) = &SLIST_FIRST((head)); \ 124 | ((var) = *(varp)) != SLIST_END(head); \ 125 | (varp) = &SLIST_NEXT((var), field)) 126 | 127 | /* 128 | * Singly-linked List functions. 129 | */ 130 | #define SLIST_INIT(head) { \ 131 | SLIST_FIRST(head) = SLIST_END(head); \ 132 | } 133 | 134 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 135 | (elm)->field.sle_next = (slistelm)->field.sle_next; \ 136 | (slistelm)->field.sle_next = (elm); \ 137 | } while (0) 138 | 139 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 140 | (elm)->field.sle_next = (head)->slh_first; \ 141 | (head)->slh_first = (elm); \ 142 | } while (0) 143 | 144 | #define SLIST_REMOVE_NEXT(head, elm, field) do { \ 145 | (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ 146 | } while (0) 147 | 148 | #define SLIST_REMOVE_HEAD(head, field) do { \ 149 | (head)->slh_first = (head)->slh_first->field.sle_next; \ 150 | } while (0) 151 | 152 | #define SLIST_REMOVE(head, elm, type, field) do { \ 153 | if ((head)->slh_first == (elm)) { \ 154 | SLIST_REMOVE_HEAD((head), field); \ 155 | } else { \ 156 | struct type *curelm = (head)->slh_first; \ 157 | \ 158 | while (curelm->field.sle_next != (elm)) \ 159 | curelm = curelm->field.sle_next; \ 160 | curelm->field.sle_next = \ 161 | curelm->field.sle_next->field.sle_next; \ 162 | _Q_INVALIDATE((elm)->field.sle_next); \ 163 | } \ 164 | } while (0) 165 | 166 | /* 167 | * List definitions. 168 | */ 169 | #define LIST_HEAD(name, type) \ 170 | struct name { \ 171 | struct type *lh_first; /* first element */ \ 172 | } 173 | 174 | #define LIST_HEAD_INITIALIZER(head) \ 175 | { NULL } 176 | 177 | #define LIST_ENTRY(type) \ 178 | struct { \ 179 | struct type *le_next; /* next element */ \ 180 | struct type **le_prev; /* address of previous next element */ \ 181 | } 182 | 183 | /* 184 | * List access methods 185 | */ 186 | #define LIST_FIRST(head) ((head)->lh_first) 187 | #define LIST_END(head) NULL 188 | #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) 189 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 190 | 191 | #define LIST_FOREACH(var, head, field) \ 192 | for((var) = LIST_FIRST(head); \ 193 | (var)!= LIST_END(head); \ 194 | (var) = LIST_NEXT(var, field)) 195 | 196 | /* 197 | * List functions. 198 | */ 199 | #define LIST_INIT(head) do { \ 200 | LIST_FIRST(head) = LIST_END(head); \ 201 | } while (0) 202 | 203 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 204 | if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ 205 | (listelm)->field.le_next->field.le_prev = \ 206 | &(elm)->field.le_next; \ 207 | (listelm)->field.le_next = (elm); \ 208 | (elm)->field.le_prev = &(listelm)->field.le_next; \ 209 | } while (0) 210 | 211 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 212 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 213 | (elm)->field.le_next = (listelm); \ 214 | *(listelm)->field.le_prev = (elm); \ 215 | (listelm)->field.le_prev = &(elm)->field.le_next; \ 216 | } while (0) 217 | 218 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 219 | if (((elm)->field.le_next = (head)->lh_first) != NULL) \ 220 | (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ 221 | (head)->lh_first = (elm); \ 222 | (elm)->field.le_prev = &(head)->lh_first; \ 223 | } while (0) 224 | 225 | #define LIST_REMOVE(elm, field) do { \ 226 | if ((elm)->field.le_next != NULL) \ 227 | (elm)->field.le_next->field.le_prev = \ 228 | (elm)->field.le_prev; \ 229 | *(elm)->field.le_prev = (elm)->field.le_next; \ 230 | _Q_INVALIDATE((elm)->field.le_prev); \ 231 | _Q_INVALIDATE((elm)->field.le_next); \ 232 | } while (0) 233 | 234 | #define LIST_REPLACE(elm, elm2, field) do { \ 235 | if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ 236 | (elm2)->field.le_next->field.le_prev = \ 237 | &(elm2)->field.le_next; \ 238 | (elm2)->field.le_prev = (elm)->field.le_prev; \ 239 | *(elm2)->field.le_prev = (elm2); \ 240 | _Q_INVALIDATE((elm)->field.le_prev); \ 241 | _Q_INVALIDATE((elm)->field.le_next); \ 242 | } while (0) 243 | 244 | /* 245 | * Simple queue definitions. 246 | */ 247 | #define SIMPLEQ_HEAD(name, type) \ 248 | struct name { \ 249 | struct type *sqh_first; /* first element */ \ 250 | struct type **sqh_last; /* addr of last next element */ \ 251 | } 252 | 253 | #define SIMPLEQ_HEAD_INITIALIZER(head) \ 254 | { NULL, &(head).sqh_first } 255 | 256 | #define SIMPLEQ_ENTRY(type) \ 257 | struct { \ 258 | struct type *sqe_next; /* next element */ \ 259 | } 260 | 261 | /* 262 | * Simple queue access methods. 263 | */ 264 | #define SIMPLEQ_FIRST(head) ((head)->sqh_first) 265 | #define SIMPLEQ_END(head) NULL 266 | #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) 267 | #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) 268 | 269 | #define SIMPLEQ_FOREACH(var, head, field) \ 270 | for((var) = SIMPLEQ_FIRST(head); \ 271 | (var) != SIMPLEQ_END(head); \ 272 | (var) = SIMPLEQ_NEXT(var, field)) 273 | 274 | /* 275 | * Simple queue functions. 276 | */ 277 | #define SIMPLEQ_INIT(head) do { \ 278 | (head)->sqh_first = NULL; \ 279 | (head)->sqh_last = &(head)->sqh_first; \ 280 | } while (0) 281 | 282 | #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ 283 | if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ 284 | (head)->sqh_last = &(elm)->field.sqe_next; \ 285 | (head)->sqh_first = (elm); \ 286 | } while (0) 287 | 288 | #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ 289 | (elm)->field.sqe_next = NULL; \ 290 | *(head)->sqh_last = (elm); \ 291 | (head)->sqh_last = &(elm)->field.sqe_next; \ 292 | } while (0) 293 | 294 | #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 295 | if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ 296 | (head)->sqh_last = &(elm)->field.sqe_next; \ 297 | (listelm)->field.sqe_next = (elm); \ 298 | } while (0) 299 | 300 | #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ 301 | if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ 302 | (head)->sqh_last = &(head)->sqh_first; \ 303 | } while (0) 304 | 305 | /* 306 | * Tail queue definitions. 307 | */ 308 | #define TAILQ_HEAD(name, type) \ 309 | struct name { \ 310 | struct type *tqh_first; /* first element */ \ 311 | struct type **tqh_last; /* addr of last next element */ \ 312 | } 313 | 314 | #define TAILQ_HEAD_INITIALIZER(head) \ 315 | { NULL, &(head).tqh_first } 316 | 317 | #define TAILQ_ENTRY(type) \ 318 | struct { \ 319 | struct type *tqe_next; /* next element */ \ 320 | struct type **tqe_prev; /* address of previous next element */ \ 321 | } 322 | 323 | /* 324 | * tail queue access methods 325 | */ 326 | #define TAILQ_FIRST(head) ((head)->tqh_first) 327 | #define TAILQ_END(head) NULL 328 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 329 | #define TAILQ_LAST(head, headname) \ 330 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 331 | /* XXX */ 332 | #define TAILQ_PREV(elm, headname, field) \ 333 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 334 | #define TAILQ_EMPTY(head) \ 335 | (TAILQ_FIRST(head) == TAILQ_END(head)) 336 | 337 | #define TAILQ_FOREACH(var, head, field) \ 338 | for((var) = TAILQ_FIRST(head); \ 339 | (var) != TAILQ_END(head); \ 340 | (var) = TAILQ_NEXT(var, field)) 341 | 342 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 343 | for((var) = TAILQ_LAST(head, headname); \ 344 | (var) != TAILQ_END(head); \ 345 | (var) = TAILQ_PREV(var, headname, field)) 346 | 347 | /* 348 | * Tail queue functions. 349 | */ 350 | #define TAILQ_INIT(head) do { \ 351 | (head)->tqh_first = NULL; \ 352 | (head)->tqh_last = &(head)->tqh_first; \ 353 | } while (0) 354 | 355 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 356 | if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ 357 | (head)->tqh_first->field.tqe_prev = \ 358 | &(elm)->field.tqe_next; \ 359 | else \ 360 | (head)->tqh_last = &(elm)->field.tqe_next; \ 361 | (head)->tqh_first = (elm); \ 362 | (elm)->field.tqe_prev = &(head)->tqh_first; \ 363 | } while (0) 364 | 365 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 366 | (elm)->field.tqe_next = NULL; \ 367 | (elm)->field.tqe_prev = (head)->tqh_last; \ 368 | *(head)->tqh_last = (elm); \ 369 | (head)->tqh_last = &(elm)->field.tqe_next; \ 370 | } while (0) 371 | 372 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 373 | if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ 374 | (elm)->field.tqe_next->field.tqe_prev = \ 375 | &(elm)->field.tqe_next; \ 376 | else \ 377 | (head)->tqh_last = &(elm)->field.tqe_next; \ 378 | (listelm)->field.tqe_next = (elm); \ 379 | (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ 380 | } while (0) 381 | 382 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 383 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 384 | (elm)->field.tqe_next = (listelm); \ 385 | *(listelm)->field.tqe_prev = (elm); \ 386 | (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ 387 | } while (0) 388 | 389 | #define TAILQ_REMOVE(head, elm, field) do { \ 390 | if (((elm)->field.tqe_next) != NULL) \ 391 | (elm)->field.tqe_next->field.tqe_prev = \ 392 | (elm)->field.tqe_prev; \ 393 | else \ 394 | (head)->tqh_last = (elm)->field.tqe_prev; \ 395 | *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ 396 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 397 | _Q_INVALIDATE((elm)->field.tqe_next); \ 398 | } while (0) 399 | 400 | #define TAILQ_REPLACE(head, elm, elm2, field) do { \ 401 | if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ 402 | (elm2)->field.tqe_next->field.tqe_prev = \ 403 | &(elm2)->field.tqe_next; \ 404 | else \ 405 | (head)->tqh_last = &(elm2)->field.tqe_next; \ 406 | (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ 407 | *(elm2)->field.tqe_prev = (elm2); \ 408 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 409 | _Q_INVALIDATE((elm)->field.tqe_next); \ 410 | } while (0) 411 | 412 | /* 413 | * Circular queue definitions. 414 | */ 415 | #define CIRCLEQ_HEAD(name, type) \ 416 | struct name { \ 417 | struct type *cqh_first; /* first element */ \ 418 | struct type *cqh_last; /* last element */ \ 419 | } 420 | 421 | #define CIRCLEQ_HEAD_INITIALIZER(head) \ 422 | { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } 423 | 424 | #define CIRCLEQ_ENTRY(type) \ 425 | struct { \ 426 | struct type *cqe_next; /* next element */ \ 427 | struct type *cqe_prev; /* previous element */ \ 428 | } 429 | 430 | /* 431 | * Circular queue access methods 432 | */ 433 | #define CIRCLEQ_FIRST(head) ((head)->cqh_first) 434 | #define CIRCLEQ_LAST(head) ((head)->cqh_last) 435 | #define CIRCLEQ_END(head) ((void *)(head)) 436 | #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) 437 | #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) 438 | #define CIRCLEQ_EMPTY(head) \ 439 | (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) 440 | 441 | #define CIRCLEQ_FOREACH(var, head, field) \ 442 | for((var) = CIRCLEQ_FIRST(head); \ 443 | (var) != CIRCLEQ_END(head); \ 444 | (var) = CIRCLEQ_NEXT(var, field)) 445 | 446 | #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ 447 | for((var) = CIRCLEQ_LAST(head); \ 448 | (var) != CIRCLEQ_END(head); \ 449 | (var) = CIRCLEQ_PREV(var, field)) 450 | 451 | /* 452 | * Circular queue functions. 453 | */ 454 | #define CIRCLEQ_INIT(head) do { \ 455 | (head)->cqh_first = CIRCLEQ_END(head); \ 456 | (head)->cqh_last = CIRCLEQ_END(head); \ 457 | } while (0) 458 | 459 | #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 460 | (elm)->field.cqe_next = (listelm)->field.cqe_next; \ 461 | (elm)->field.cqe_prev = (listelm); \ 462 | if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ 463 | (head)->cqh_last = (elm); \ 464 | else \ 465 | (listelm)->field.cqe_next->field.cqe_prev = (elm); \ 466 | (listelm)->field.cqe_next = (elm); \ 467 | } while (0) 468 | 469 | #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ 470 | (elm)->field.cqe_next = (listelm); \ 471 | (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ 472 | if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ 473 | (head)->cqh_first = (elm); \ 474 | else \ 475 | (listelm)->field.cqe_prev->field.cqe_next = (elm); \ 476 | (listelm)->field.cqe_prev = (elm); \ 477 | } while (0) 478 | 479 | #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ 480 | (elm)->field.cqe_next = (head)->cqh_first; \ 481 | (elm)->field.cqe_prev = CIRCLEQ_END(head); \ 482 | if ((head)->cqh_last == CIRCLEQ_END(head)) \ 483 | (head)->cqh_last = (elm); \ 484 | else \ 485 | (head)->cqh_first->field.cqe_prev = (elm); \ 486 | (head)->cqh_first = (elm); \ 487 | } while (0) 488 | 489 | #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ 490 | (elm)->field.cqe_next = CIRCLEQ_END(head); \ 491 | (elm)->field.cqe_prev = (head)->cqh_last; \ 492 | if ((head)->cqh_first == CIRCLEQ_END(head)) \ 493 | (head)->cqh_first = (elm); \ 494 | else \ 495 | (head)->cqh_last->field.cqe_next = (elm); \ 496 | (head)->cqh_last = (elm); \ 497 | } while (0) 498 | 499 | #define CIRCLEQ_REMOVE(head, elm, field) do { \ 500 | if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ 501 | (head)->cqh_last = (elm)->field.cqe_prev; \ 502 | else \ 503 | (elm)->field.cqe_next->field.cqe_prev = \ 504 | (elm)->field.cqe_prev; \ 505 | if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ 506 | (head)->cqh_first = (elm)->field.cqe_next; \ 507 | else \ 508 | (elm)->field.cqe_prev->field.cqe_next = \ 509 | (elm)->field.cqe_next; \ 510 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 511 | _Q_INVALIDATE((elm)->field.cqe_next); \ 512 | } while (0) 513 | 514 | #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ 515 | if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ 516 | CIRCLEQ_END(head)) \ 517 | (head).cqh_last = (elm2); \ 518 | else \ 519 | (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ 520 | if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ 521 | CIRCLEQ_END(head)) \ 522 | (head).cqh_first = (elm2); \ 523 | else \ 524 | (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ 525 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 526 | _Q_INVALIDATE((elm)->field.cqe_next); \ 527 | } while (0) 528 | 529 | #endif /* !_SYS_QUEUE_H_ */ 530 | -------------------------------------------------------------------------------- /include/excel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __XLS_EXCEL_H__ 20 | #define __XLS_EXCEL_H__ 21 | 22 | /* Top level includes. You should only need to include this file in your 23 | * projects. */ 24 | #include "workbook.h" 25 | #include "worksheet.h" 26 | #include "format.h" 27 | 28 | #endif /* __XLS_EXCEL_H__ */ 29 | -------------------------------------------------------------------------------- /include/format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __XLS_FORMAT_H__ 20 | #define __XLS_FORMAT_H__ 21 | 22 | #include 23 | 24 | #include "biffwriter.h" 25 | #include "bsdqueue.h" 26 | #include "stream.h" 27 | 28 | struct xl_format { 29 | int xf_index; 30 | int font_index; 31 | char *fontname; 32 | int size; 33 | int bold; 34 | int italic; 35 | int color; 36 | int underline; 37 | int font_strikeout; 38 | int font_outline; 39 | int font_shadow; 40 | int font_script; 41 | int font_family; 42 | int font_charset; 43 | char *num_format_str; 44 | int num_format; 45 | int text_h_align; 46 | int text_wrap; 47 | int text_v_align; 48 | int text_justlast; 49 | int rotation; 50 | int fg_color; 51 | int bg_color; 52 | int pattern; 53 | int bottom; 54 | int top; 55 | int left; 56 | int right; 57 | int bottom_color; 58 | int top_color; 59 | int left_color; 60 | int right_color; 61 | }; 62 | 63 | struct xl_format *fmt_new(int idx); 64 | void fmt_destroy(struct xl_format *fmt); 65 | struct pkt *fmt_get_font(struct xl_format *fmt); 66 | struct pkt *fmt_get_xf(struct xl_format *fmt, int style); 67 | int fmt_gethash(struct xl_format *fmt); 68 | 69 | /* format setters */ 70 | void fmt_set_bold(struct xl_format *fmt, int bold_val); 71 | void fmt_set_color(struct xl_format *fmt, char *colorname); 72 | void fmt_set_align(struct xl_format *fmt, char *align); 73 | void fmt_set_size(struct xl_format *fmt, int size); 74 | void fmt_set_font(struct xl_format *fmt, char *font); 75 | void fmt_set_colori(struct xl_format *fmt, int colorval); 76 | void fmt_set_num_format(struct xl_format *fmt, int format); 77 | void fmt_set_border_color(struct xl_format *fmt, char *colorname); 78 | void fmt_set_border(struct xl_format *fmt, int format); 79 | void fmt_set_pattern(struct xl_format *fmt, int pattern); 80 | void fmt_set_bg_color(struct xl_format *fmt, char *colorname); 81 | void fmt_set_fg_color(struct xl_format *fmt, char *colorname); 82 | void fmt_set_text_wrap(struct xl_format *fmt, int val); 83 | void fmt_set_rotation(struct xl_format *fmt, int val); 84 | void fmt_set_merge(struct xl_format *fmt); 85 | void fmt_set_underline(struct xl_format *fmt, int val); 86 | void fmt_set_num_format_str(struct xl_format *fmt, char *str); 87 | 88 | #endif /* __XLS_FORMAT_H__ */ 89 | -------------------------------------------------------------------------------- /include/formula.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __XLS_FORMULA_H__ 18 | #define __XLS_FORMULA_H__ 19 | 20 | #include 21 | 22 | #include "stream.h" 23 | 24 | int process_formula(char *input, struct pkt *pkt); 25 | 26 | #endif /* __XLS_FORMULA_H__ */ 27 | -------------------------------------------------------------------------------- /include/hashhelp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __XLS_HASHHELP_H__ 18 | #define __XLS_HASHHELP_H__ 19 | 20 | /* This is not a generic hashtable implementation. The data type is a simple 21 | * integer (which was all I needed) */ 22 | 23 | struct hashnode { 24 | int key; 25 | int data; 26 | struct hashnode *next; 27 | }; 28 | 29 | struct htbl { 30 | size_t filled; 31 | size_t size; 32 | struct hashnode **nodes; 33 | }; 34 | 35 | struct htbl *hashtbl_new(size_t size); 36 | void hashtbl_destroy(struct htbl *tbl); 37 | int hashtbl_insert(struct htbl *tbl, int key, int data); 38 | int hashtbl_get(struct htbl *tbl, int key); 39 | 40 | #endif /* __XLS_HASHHELP_H__ */ 41 | -------------------------------------------------------------------------------- /include/io_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Guilherme Steinmann 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BELIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __XLS_IO_HANDLER_H__ 18 | #define __XLS_IO_HANDLER_H__ 19 | 20 | #include 21 | 22 | struct xl_io_handler { 23 | void* (*create)(const char *filename); 24 | int (*write )(void* handle, const void* buffer, size_t size); 25 | int (*close )(void* handle); 26 | }; 27 | 28 | void* xl_file_create(const char *filename); 29 | int xl_file_write(void *handle,const void* buffer,size_t size); 30 | int xl_file_close(void *handle); 31 | 32 | extern struct xl_io_handler xl_file_handler; 33 | 34 | #endif /* __XLS_IO_HANDLER_H__ */ 35 | -------------------------------------------------------------------------------- /include/olewriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __XLS_OLEWRITER_H__ 20 | #define __XLS_OLEWRITER_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | #include "io_handler.h" 26 | 27 | struct owctx { 28 | const char *olefilename; 29 | struct xl_io_handler io_handler; 30 | void* io_handle; 31 | int fileclosed; 32 | int biff_only; 33 | int size_allowed; 34 | int biffsize; 35 | int booksize; 36 | int big_blocks; 37 | int list_blocks; 38 | int root_start; 39 | int block_count; 40 | }; 41 | 42 | struct owctx * ow_new(const char *filename); 43 | struct owctx * ow_new_ex(struct xl_io_handler io_handler, const char *filename); 44 | void ow_destroy(struct owctx *ow); 45 | int ow_set_size(struct owctx *ow, int biffsize); 46 | void ow_write_header(struct owctx *ow); 47 | void ow_write(struct owctx *ow, void *data, size_t size); 48 | void ow_close(struct owctx *ow); 49 | 50 | #endif /* __XLS_OLEWRITER_H__ */ 51 | -------------------------------------------------------------------------------- /include/stream.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2003-2005, Claudio Leite 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of the BSF Software Project nor the names of its 16 | * contributors may be used to endorse or promote products derived 17 | * from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 30 | */ 31 | 32 | /* This code is based on Claudio Leite's packet.c file inside the 33 | * imcomm module of his bsflite program. Claudio states that his code was 34 | * inspired by libfaim's (now defunct) bstream (binary stream) 35 | * implementation. 36 | */ 37 | 38 | #ifndef __STREAM_H__ 39 | #define __STREAM_H__ 40 | 41 | #include 42 | #include 43 | 44 | #define VARIABLE_PACKET 1 45 | #define FIXED_PACKET 2 46 | 47 | struct pkt { 48 | unsigned char *data; 49 | size_t offset; 50 | size_t len; 51 | }; 52 | 53 | struct pkt_rdr 54 | { 55 | unsigned char *data; 56 | size_t len; 57 | int offset; 58 | }; 59 | 60 | /* packet creation functions */ 61 | void pkt_addraw(struct pkt *p, const unsigned char *bytes, size_t len); 62 | void pkt_addzero(struct pkt *p, int num_zeros); 63 | void pkt_add8(struct pkt *p, uint8_t val); 64 | void pkt_add16(struct pkt *p, uint16_t val); 65 | void pkt_add16_le(struct pkt *p, uint16_t val); 66 | void pkt_add32(struct pkt *p, uint32_t val); 67 | void pkt_add32_le(struct pkt *p, uint32_t val); 68 | void pkt_write_data_len(struct pkt *p); 69 | void pkt_addstring(struct pkt *p, const char *bytes); 70 | void pkt_free(struct pkt * p); 71 | 72 | /* Raw routines */ 73 | struct pkt * pkt_init(size_t len, int type); 74 | 75 | #endif /* __STREAM_H__ */ 76 | 77 | -------------------------------------------------------------------------------- /include/workbook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __XLS_WORKBOOK_H__ 20 | #define __XLS_WORKBOOK_H__ 21 | 22 | #include 23 | 24 | #include "biffwriter.h" 25 | #include "format.h" 26 | #include "olewriter.h" 27 | #include "worksheet.h" 28 | #include "bsdqueue.h" 29 | #include "io_handler.h" 30 | 31 | struct wbookctx { 32 | struct bwctx *biff; 33 | 34 | int store_in_memory; 35 | struct owctx *OLEwriter; 36 | int epoch1904; 37 | int activesheet; 38 | int firstsheet; 39 | int fileclosed; 40 | int biffsize; 41 | int codepage; 42 | char *sheetname; 43 | struct xl_format *tmp_format; 44 | struct xl_format *url_format; 45 | int xf_index; 46 | 47 | int sheetcount; 48 | struct wsheetctx **sheets; 49 | 50 | int formatcount; 51 | struct xl_format **formats; 52 | }; 53 | 54 | struct wbookctx *wbook_new(const char *filename, int store_in_memory); 55 | struct wbookctx *wbook_new_ex(struct xl_io_handler io_handler, const char *filename, int store_in_memory); 56 | void wbook_close(struct wbookctx *wb); 57 | void wbook_destroy(struct wbookctx *wb); 58 | struct wsheetctx *wbook_addworksheet(struct wbookctx *wbook, char *sname); 59 | struct xl_format *wbook_addformat(struct wbookctx *wbook); 60 | 61 | #endif /* __XLS_WORKBOOK_H__ */ 62 | -------------------------------------------------------------------------------- /include/worksheet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef __XLS_WORKSHEET_H__ 20 | #define __XLS_WORKSHEET_H__ 21 | 22 | #include 23 | 24 | #include "biffwriter.h" 25 | #include "bsdqueue.h" 26 | #include "format.h" 27 | 28 | struct col_info { 29 | int first_col; 30 | int last_col; 31 | int col_width; 32 | int xf; 33 | int grbit; 34 | 35 | TAILQ_ENTRY(col_info) cis; 36 | }; 37 | 38 | struct wsheetctx { 39 | struct bwctx base; 40 | char *name; 41 | int index; 42 | int activesheet; 43 | int firstsheet; 44 | struct xl_format *url_format; 45 | int using_tmpfile; 46 | 47 | FILE *fp; 48 | int fileclosed; 49 | int offset; 50 | int xls_rowmax; 51 | int xls_colmax; 52 | int xls_strmax; 53 | int dim_rowmin; 54 | int dim_rowmax; 55 | int dim_colmin; 56 | int dim_colmax; 57 | 58 | int sel_frow; 59 | int sel_fcol; 60 | int sel_lrow; 61 | int sel_lcol; 62 | 63 | TAILQ_HEAD(colinfo_list, col_info) colinfos; 64 | }; 65 | 66 | struct wsheetctx * wsheet_new(char *name, int index, int activesheet, int firstsheet, struct xl_format *url, int store_in_memory); 67 | void wsheet_destroy(struct wsheetctx *xls); 68 | int xls_write_number(struct wsheetctx *xls, int row, int col, double num); 69 | int xls_write_string(struct wsheetctx *xls, int row, int col, char *str); 70 | int xls_writef_string(struct wsheetctx *xls, int row, int col, char *str, struct xl_format *fmt); 71 | int xls_writef_number(struct wsheetctx *xls, int row, int col, double num, struct xl_format *fmt); 72 | int xls_write_blank(struct wsheetctx *xls, int row, int col, struct xl_format *fmt); 73 | int wsheet_writef_formula(struct wsheetctx *xls, int row, int col, char *formula, struct xl_format *fmt); 74 | int wsheet_write_url(struct wsheetctx *wsheet, int row, int col, char *url, char *str, struct xl_format *fmt); 75 | void wsheet_close(struct wsheetctx *xls); 76 | unsigned char *wsheet_get_data(struct wsheetctx *ws, size_t *sz); 77 | void wsheet_set_column(struct wsheetctx *ws, int fcol, int lcol, int width); 78 | void wsheet_set_selection(struct wsheetctx *ws, int frow, int fcol, int lrow, int lcol); 79 | void wsheet_set_row(struct wsheetctx *ws, int row, int height, struct xl_format *fmt); 80 | 81 | #endif /* __XLS_WORKSHEET_H__ */ 82 | -------------------------------------------------------------------------------- /msvc/libexcel.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="libexcel" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Static Library" 0x0104 6 | 7 | CFG=libexcel - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "libexcel.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "libexcel.mak" CFG="libexcel - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "libexcel - Win32 Release" (based on "Win32 (x86) Static Library") 21 | !MESSAGE "libexcel - Win32 Debug" (based on "Win32 (x86) Static Library") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "libexcel - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 44 | # ADD CPP /nologo /G6 /W3 /GX /O2 /I "..\include" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D snprintf=_snprintf /YX /FD /c 45 | # ADD BASE RSC /l 0x804 /d "NDEBUG" 46 | # ADD RSC /l 0x804 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LIB32=link.exe -lib 51 | # ADD BASE LIB32 /nologo 52 | # ADD LIB32 /nologo 53 | 54 | !ELSEIF "$(CFG)" == "libexcel - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Target_Dir "" 66 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 67 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D snprintf=_snprintf /YX /FD /GZ /c 68 | # ADD BASE RSC /l 0x804 /d "_DEBUG" 69 | # ADD RSC /l 0x804 /d "_DEBUG" 70 | BSC32=bscmake.exe 71 | # ADD BASE BSC32 /nologo 72 | # ADD BSC32 /nologo 73 | LIB32=link.exe -lib 74 | # ADD BASE LIB32 /nologo 75 | # ADD LIB32 /nologo 76 | 77 | !ENDIF 78 | 79 | # Begin Target 80 | 81 | # Name "libexcel - Win32 Release" 82 | # Name "libexcel - Win32 Debug" 83 | # Begin Group "Source Files" 84 | 85 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 86 | # Begin Source File 87 | 88 | SOURCE=..\src\biffwriter.c 89 | # End Source File 90 | # Begin Source File 91 | 92 | SOURCE=..\src\format.c 93 | # End Source File 94 | # Begin Source File 95 | 96 | SOURCE=..\src\formula.c 97 | # End Source File 98 | # Begin Source File 99 | 100 | SOURCE=..\src\hashhelp.c 101 | # End Source File 102 | # Begin Source File 103 | 104 | SOURCE=..\src\olewriter.c 105 | # End Source File 106 | # Begin Source File 107 | 108 | SOURCE=..\src\stream.c 109 | # End Source File 110 | # Begin Source File 111 | 112 | SOURCE=..\src\workbook.c 113 | # End Source File 114 | # Begin Source File 115 | 116 | SOURCE=..\src\worksheet.c 117 | # End Source File 118 | # End Group 119 | # Begin Group "Header Files" 120 | 121 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 122 | # Begin Source File 123 | 124 | SOURCE=..\include\biffwriter.h 125 | # End Source File 126 | # Begin Source File 127 | 128 | SOURCE=..\include\bsdqueue.h 129 | # End Source File 130 | # Begin Source File 131 | 132 | SOURCE=..\include\excel.h 133 | # End Source File 134 | # Begin Source File 135 | 136 | SOURCE=..\include\format.h 137 | # End Source File 138 | # Begin Source File 139 | 140 | SOURCE=..\include\formula.h 141 | # End Source File 142 | # Begin Source File 143 | 144 | SOURCE=..\include\hashhelp.h 145 | # End Source File 146 | # Begin Source File 147 | 148 | SOURCE=..\include\olewriter.h 149 | # End Source File 150 | # Begin Source File 151 | 152 | SOURCE=.\stdint.h 153 | # End Source File 154 | # Begin Source File 155 | 156 | SOURCE=..\include\stream.h 157 | # End Source File 158 | # Begin Source File 159 | 160 | SOURCE=..\include\workbook.h 161 | # End Source File 162 | # Begin Source File 163 | 164 | SOURCE=..\include\worksheet.h 165 | # End Source File 166 | # End Group 167 | # End Target 168 | # End Project 169 | -------------------------------------------------------------------------------- /msvc/stdint.h: -------------------------------------------------------------------------------- 1 | // ISO C9x compliant stdint.h for Microsoft Visual Studio 2 | // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 3 | // 4 | // Copyright (c) 2006-2008 Alexander Chemeris 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright notice, 10 | // this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. The name of the author may be used to endorse or promote products 17 | // derived from this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | #ifndef _MSC_VER // [ 33 | #error "Use this header only with Microsoft Visual C++ compilers!" 34 | #endif // _MSC_VER ] 35 | 36 | #ifndef _MSC_STDINT_H_ // [ 37 | #define _MSC_STDINT_H_ 38 | 39 | #if _MSC_VER > 1000 40 | #pragma once 41 | #endif 42 | 43 | #include 44 | 45 | // For Visual Studio 6 in C++ mode and for many Visual Studio versions when 46 | // compiling for ARM we should wrap include with 'extern "C++" {}' 47 | // or compiler give many errors like this: 48 | // error C2733: second C linkage of overloaded function 'wmemchr' not allowed 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | # include 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | // Define _W64 macros to mark types changing their size, like intptr_t. 58 | #ifndef _W64 59 | # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 60 | # define _W64 __w64 61 | # else 62 | # define _W64 63 | # endif 64 | #endif 65 | 66 | 67 | // 7.18.1 Integer types 68 | 69 | // 7.18.1.1 Exact-width integer types 70 | 71 | // Visual Studio 6 and Embedded Visual C++ 4 doesn't 72 | // realize that, e.g. char has the same size as __int8 73 | // so we give up on __intX for them. 74 | #if (_MSC_VER < 1300) 75 | typedef signed char int8_t; 76 | typedef signed short int16_t; 77 | typedef signed int int32_t; 78 | typedef unsigned char uint8_t; 79 | typedef unsigned short uint16_t; 80 | typedef unsigned int uint32_t; 81 | #else 82 | typedef signed __int8 int8_t; 83 | typedef signed __int16 int16_t; 84 | typedef signed __int32 int32_t; 85 | typedef unsigned __int8 uint8_t; 86 | typedef unsigned __int16 uint16_t; 87 | typedef unsigned __int32 uint32_t; 88 | #endif 89 | typedef signed __int64 int64_t; 90 | typedef unsigned __int64 uint64_t; 91 | 92 | 93 | // 7.18.1.2 Minimum-width integer types 94 | typedef int8_t int_least8_t; 95 | typedef int16_t int_least16_t; 96 | typedef int32_t int_least32_t; 97 | typedef int64_t int_least64_t; 98 | typedef uint8_t uint_least8_t; 99 | typedef uint16_t uint_least16_t; 100 | typedef uint32_t uint_least32_t; 101 | typedef uint64_t uint_least64_t; 102 | 103 | // 7.18.1.3 Fastest minimum-width integer types 104 | typedef int8_t int_fast8_t; 105 | typedef int16_t int_fast16_t; 106 | typedef int32_t int_fast32_t; 107 | typedef int64_t int_fast64_t; 108 | typedef uint8_t uint_fast8_t; 109 | typedef uint16_t uint_fast16_t; 110 | typedef uint32_t uint_fast32_t; 111 | typedef uint64_t uint_fast64_t; 112 | 113 | // 7.18.1.4 Integer types capable of holding object pointers 114 | #ifdef _WIN64 // [ 115 | typedef signed __int64 intptr_t; 116 | typedef unsigned __int64 uintptr_t; 117 | #else // _WIN64 ][ 118 | typedef _W64 signed int intptr_t; 119 | typedef _W64 unsigned int uintptr_t; 120 | #endif // _WIN64 ] 121 | 122 | // 7.18.1.5 Greatest-width integer types 123 | typedef int64_t intmax_t; 124 | typedef uint64_t uintmax_t; 125 | 126 | 127 | // 7.18.2 Limits of specified-width integer types 128 | 129 | #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 130 | 131 | // 7.18.2.1 Limits of exact-width integer types 132 | #define INT8_MIN ((int8_t)_I8_MIN) 133 | #define INT8_MAX _I8_MAX 134 | #define INT16_MIN ((int16_t)_I16_MIN) 135 | #define INT16_MAX _I16_MAX 136 | #define INT32_MIN ((int32_t)_I32_MIN) 137 | #define INT32_MAX _I32_MAX 138 | #define INT64_MIN ((int64_t)_I64_MIN) 139 | #define INT64_MAX _I64_MAX 140 | #define UINT8_MAX _UI8_MAX 141 | #define UINT16_MAX _UI16_MAX 142 | #define UINT32_MAX _UI32_MAX 143 | #define UINT64_MAX _UI64_MAX 144 | 145 | // 7.18.2.2 Limits of minimum-width integer types 146 | #define INT_LEAST8_MIN INT8_MIN 147 | #define INT_LEAST8_MAX INT8_MAX 148 | #define INT_LEAST16_MIN INT16_MIN 149 | #define INT_LEAST16_MAX INT16_MAX 150 | #define INT_LEAST32_MIN INT32_MIN 151 | #define INT_LEAST32_MAX INT32_MAX 152 | #define INT_LEAST64_MIN INT64_MIN 153 | #define INT_LEAST64_MAX INT64_MAX 154 | #define UINT_LEAST8_MAX UINT8_MAX 155 | #define UINT_LEAST16_MAX UINT16_MAX 156 | #define UINT_LEAST32_MAX UINT32_MAX 157 | #define UINT_LEAST64_MAX UINT64_MAX 158 | 159 | // 7.18.2.3 Limits of fastest minimum-width integer types 160 | #define INT_FAST8_MIN INT8_MIN 161 | #define INT_FAST8_MAX INT8_MAX 162 | #define INT_FAST16_MIN INT16_MIN 163 | #define INT_FAST16_MAX INT16_MAX 164 | #define INT_FAST32_MIN INT32_MIN 165 | #define INT_FAST32_MAX INT32_MAX 166 | #define INT_FAST64_MIN INT64_MIN 167 | #define INT_FAST64_MAX INT64_MAX 168 | #define UINT_FAST8_MAX UINT8_MAX 169 | #define UINT_FAST16_MAX UINT16_MAX 170 | #define UINT_FAST32_MAX UINT32_MAX 171 | #define UINT_FAST64_MAX UINT64_MAX 172 | 173 | // 7.18.2.4 Limits of integer types capable of holding object pointers 174 | #ifdef _WIN64 // [ 175 | # define INTPTR_MIN INT64_MIN 176 | # define INTPTR_MAX INT64_MAX 177 | # define UINTPTR_MAX UINT64_MAX 178 | #else // _WIN64 ][ 179 | # define INTPTR_MIN INT32_MIN 180 | # define INTPTR_MAX INT32_MAX 181 | # define UINTPTR_MAX UINT32_MAX 182 | #endif // _WIN64 ] 183 | 184 | // 7.18.2.5 Limits of greatest-width integer types 185 | #define INTMAX_MIN INT64_MIN 186 | #define INTMAX_MAX INT64_MAX 187 | #define UINTMAX_MAX UINT64_MAX 188 | 189 | // 7.18.3 Limits of other integer types 190 | 191 | #ifdef _WIN64 // [ 192 | # define PTRDIFF_MIN _I64_MIN 193 | # define PTRDIFF_MAX _I64_MAX 194 | #else // _WIN64 ][ 195 | # define PTRDIFF_MIN _I32_MIN 196 | # define PTRDIFF_MAX _I32_MAX 197 | #endif // _WIN64 ] 198 | 199 | #define SIG_ATOMIC_MIN INT_MIN 200 | #define SIG_ATOMIC_MAX INT_MAX 201 | 202 | #ifndef SIZE_MAX // [ 203 | # ifdef _WIN64 // [ 204 | # define SIZE_MAX _UI64_MAX 205 | # else // _WIN64 ][ 206 | # define SIZE_MAX _UI32_MAX 207 | # endif // _WIN64 ] 208 | #endif // SIZE_MAX ] 209 | 210 | // WCHAR_MIN and WCHAR_MAX are also defined in 211 | #ifndef WCHAR_MIN // [ 212 | # define WCHAR_MIN 0 213 | #endif // WCHAR_MIN ] 214 | #ifndef WCHAR_MAX // [ 215 | # define WCHAR_MAX _UI16_MAX 216 | #endif // WCHAR_MAX ] 217 | 218 | #define WINT_MIN 0 219 | #define WINT_MAX _UI16_MAX 220 | 221 | #endif // __STDC_LIMIT_MACROS ] 222 | 223 | 224 | // 7.18.4 Limits of other integer types 225 | 226 | #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 227 | 228 | // 7.18.4.1 Macros for minimum-width integer constants 229 | 230 | #define INT8_C(val) val##i8 231 | #define INT16_C(val) val##i16 232 | #define INT32_C(val) val##i32 233 | #define INT64_C(val) val##i64 234 | 235 | #define UINT8_C(val) val##ui8 236 | #define UINT16_C(val) val##ui16 237 | #define UINT32_C(val) val##ui32 238 | #define UINT64_C(val) val##ui64 239 | 240 | // 7.18.4.2 Macros for greatest-width integer constants 241 | #define INTMAX_C INT64_C 242 | #define UINTMAX_C UINT64_C 243 | 244 | #endif // __STDC_CONSTANT_MACROS ] 245 | 246 | 247 | #endif // _MSC_STDINT_H_ ] 248 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for libexcel. 2 | 3 | .PHONY: all clean 4 | 5 | SRCS = biffwriter.c worksheet.c format.c formula.c hashhelp.c olewriter.c stream.c workbook.c io_handler.c 6 | 7 | OBJS = $(SRCS:.c=.o) 8 | 9 | CC = gcc 10 | AR = ar 11 | 12 | ifeq ($(OS),Windows_NT) 13 | RM = del /Q /F 14 | CP = copy /Y 15 | else 16 | RM = rm -f 17 | CP = cp -f 18 | endif 19 | 20 | INTERNAL_CFLAGS = -Wall -I../include 21 | CPPFLAGS += -MMD -MP -MT $@ 22 | CFLAGS = -O2 -pipe 23 | 24 | LIB = libexcel 25 | STATIC_LIB = libexcel.a 26 | 27 | all: $(LIB) 28 | 29 | debug: CPPFLAGS = 30 | debug: CFLAGS = -O0 -g 31 | debug: $(LIB) 32 | 33 | $(LIB): $(STATIC_LIB) 34 | 35 | $(STATIC_LIB): $(OBJS) 36 | $(RM) $(STATIC_LIB) 37 | $(AR) cru $(STATIC_LIB) $(OBJS) 38 | ranlib $(STATIC_LIB) 39 | 40 | clean: 41 | $(RM) $(OBJS) $(STATIC_LIB) 42 | $(RM) *.d 43 | 44 | .c.o: 45 | $(CC) $(INTERNAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 46 | 47 | # Include automatically generated dependency files 48 | -include $(wildcard *.d) 49 | -------------------------------------------------------------------------------- /src/Makefile.lccw32: -------------------------------------------------------------------------------- 1 | # Makefile for libexcel. 2 | 3 | .PHONY: all clean 4 | 5 | SRCS = biffwriter.c worksheet.c format.c olewriter.c \ 6 | stream.c workbook.c 7 | 8 | OBJS = $(SRCS:.c=.o) 9 | 10 | CC = c:\lcc\bin\lcc 11 | AR = c:\lcc\bin\lcclib 12 | 13 | INTERNAL_CFLAGS = -A -I../include 14 | CFLAGS= -O 15 | 16 | LIB = libexcel 17 | STATIC_LIB = libexcel.lib 18 | 19 | all: $(LIB) 20 | 21 | $(LIB): $(STATIC_LIB) 22 | 23 | $(STATIC_LIB): $(OBJS) 24 | $(AR) /out:$(STATIC_LIB) $(OBJS) 25 | 26 | clean: 27 | del $(OBJS) $(STATIC_LIB) 28 | 29 | .c.o: 30 | $(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -o $@ -c $< 31 | 32 | -------------------------------------------------------------------------------- /src/Makefile.mingw: -------------------------------------------------------------------------------- 1 | # Makefile for libexcel. 2 | 3 | .PHONY: all clean 4 | 5 | SRCS = biffwriter.c hashhelp.c worksheet.c format.c formula.c olewriter.c \ 6 | stream.c workbook.c 7 | 8 | OBJS = $(SRCS:.c=.o) 9 | 10 | CC = gcc 11 | AR = ar 12 | 13 | INTERNAL_CFLAGS = -Wall -I../include 14 | CPPFLAGS += -MMD -MP -MT $@ 15 | CFLAGS= -O2 -pipe 16 | 17 | LIB = libexcel 18 | STATIC_LIB = libexcel.a 19 | 20 | all: $(LIB) 21 | 22 | $(LIB): $(STATIC_LIB) 23 | 24 | $(STATIC_LIB): $(OBJS) 25 | $(AR) cru $(STATIC_LIB) $(OBJS) 26 | ranlib $(STATIC_LIB) 27 | 28 | clean: 29 | del $(OBJS) $(STATIC_LIB) 30 | del *.d 31 | 32 | .c.o: 33 | $(CC) $(INTERNAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 34 | 35 | # Include automatically generated dependency files 36 | -include $(wildcard *.d) 37 | -------------------------------------------------------------------------------- /src/biffwriter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "biffwriter.h" 24 | #include "stream.h" 25 | 26 | const int g_BIFF_version = 0x0500; 27 | 28 | int bw_init(struct bwctx *bw); 29 | 30 | struct bwctx * bw_new(void) 31 | { 32 | struct bwctx *bw; 33 | 34 | bw = malloc(sizeof(struct bwctx)); 35 | 36 | if (bw_init(bw) == -1) { 37 | free(bw); 38 | return NULL; 39 | } 40 | 41 | return bw; 42 | } 43 | 44 | void bw_destroy(struct bwctx *bw) 45 | { 46 | free(bw->data); 47 | free(bw); 48 | } 49 | 50 | void reverse(unsigned char *data, int size) 51 | { 52 | unsigned char *t, *m; 53 | 54 | t = data + size; 55 | m = data + size / 2; 56 | while (data != m) { 57 | unsigned char c = *data; 58 | *data++ = *--t; 59 | *t = c; 60 | } 61 | } 62 | 63 | int bw_setbyteorder(struct bwctx *bw) 64 | { 65 | double d = 1.2345; 66 | unsigned char data[8]; 67 | unsigned char hexdata[8] = {0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F}; 68 | 69 | /* Test for endian */ 70 | memcpy(data, &d, sizeof(data)); 71 | if (memcmp(data, hexdata, sizeof(data))) { 72 | bw->byte_order = 1; 73 | } else { 74 | reverse(data, sizeof(data)); 75 | if (memcmp(data, hexdata, sizeof(data))) { 76 | bw->byte_order = 0; 77 | } else { 78 | return -1; 79 | } 80 | } 81 | return 0; 82 | } 83 | 84 | int bw_init(struct bwctx *bw) 85 | { 86 | bw->data = NULL; 87 | bw->datasize = 0; 88 | bw->_sz = 0; 89 | bw_setbyteorder(bw); 90 | bw->append = bw_append; 91 | 92 | return 0; 93 | } 94 | 95 | #define ROUNDVAL 16 96 | #define ROUNDUP(n) (((n)+ROUNDVAL-1)&-ROUNDVAL) 97 | 98 | void bw_resize(struct bwctx *bw, size_t size) 99 | { 100 | if (bw->_sz != size) { 101 | if (size > 0) { 102 | if (bw->data == NULL) 103 | bw->data = malloc(ROUNDUP(1 + size)); 104 | else 105 | bw->data = realloc(bw->data, ROUNDUP(1 + size)); 106 | bw->_sz = size; 107 | } else if (bw->data != NULL) { 108 | free(bw->data); 109 | bw->data = NULL; 110 | } 111 | } 112 | } 113 | 114 | void bw_append(void *xlsctx, void *data, size_t size) 115 | { 116 | struct bwctx *bw = (struct bwctx *)xlsctx; 117 | 118 | int len = bw->_sz; 119 | bw_resize(bw, len + size); 120 | memcpy(bw->data + len, data, size); 121 | bw->datasize += size; 122 | } 123 | 124 | void bw_prepend(struct bwctx *bw, void *data, size_t size) 125 | { 126 | int len = bw->_sz; 127 | bw_resize(bw, len + size); 128 | memmove(bw->data + size, bw->data, len); 129 | memcpy(bw->data, data, size); 130 | bw->datasize += size; 131 | } 132 | 133 | 134 | /**************************************************************************** 135 | * bw_store_bof(struct bwctx *bw, uint16_t type) 136 | * 137 | * type = 0x0005, Workbook 138 | * type = 0x0010, Worksheet 139 | * 140 | * Writes Excel BOF (Beginning of File) record to indicate the beginning of 141 | * a stream or substream in the BIFF file 142 | */ 143 | void bw_store_bof(struct bwctx *bw, uint16_t type) 144 | { 145 | uint16_t name = 0x0809; /* Record identifier */ 146 | uint16_t length = 0x0008; /* Number of bytes to follow */ 147 | 148 | /* According to the SDK "build" and "year" should be set to zero. 149 | * However, this throws a warning in Excel 5. So, use these 150 | * magic umbers */ 151 | uint16_t build = 0x096C; 152 | uint16_t year = 0x07C9; 153 | 154 | struct pkt *pkt; 155 | 156 | pkt = pkt_init(12, FIXED_PACKET); 157 | 158 | /* Construct header */ 159 | pkt_add16_le(pkt, name); 160 | pkt_add16_le(pkt, length); 161 | 162 | /* Construct data */ 163 | pkt_add16_le(pkt, g_BIFF_version); 164 | pkt_add16_le(pkt, type); 165 | pkt_add16_le(pkt, build); 166 | pkt_add16_le(pkt, year); 167 | bw_prepend(bw, pkt->data, pkt->len); 168 | pkt_free(pkt); 169 | } 170 | 171 | /**************************************************************************** 172 | * bw_store_eof(struct bwctx *bw) 173 | * 174 | * Writes Excel EOF (End of File) record to indicate the end of a BIFF stream. 175 | */ 176 | void bw_store_eof(struct bwctx *bw) 177 | { 178 | struct pkt *pkt; 179 | uint16_t name = 0x000A; /* Record identifier */ 180 | uint16_t length = 0x0000; /* Number of bytes to follow */ 181 | 182 | pkt = pkt_init(4, FIXED_PACKET); 183 | 184 | /* Construct header */ 185 | pkt_add16_le(pkt, name); 186 | pkt_add16_le(pkt, length); 187 | 188 | bw->append(bw, pkt->data, pkt->len); 189 | pkt_free(pkt); 190 | } 191 | -------------------------------------------------------------------------------- /src/format.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "format.h" 24 | #include "stream.h" 25 | 26 | static int fmt_get_color(char *colorname); 27 | 28 | struct xl_format * fmt_new(int idx) 29 | { 30 | struct xl_format *ret; 31 | 32 | ret = malloc(sizeof(struct xl_format)); 33 | 34 | ret->xf_index = idx; 35 | ret->font_index = 0; 36 | ret->fontname = strdup("Arial"); 37 | ret->size = 10; 38 | ret->bold = 0x0190; 39 | ret->italic = 0; 40 | ret->color = 0x7FFF; 41 | ret->underline = 0; 42 | ret->font_strikeout = 0; 43 | ret->font_outline = 0; 44 | ret->font_shadow = 0; 45 | ret->font_script = 0; 46 | ret->font_family = 0; 47 | ret->font_charset = 0; 48 | 49 | ret->num_format = 0; 50 | ret->num_format_str = NULL; 51 | 52 | ret->text_h_align = 0; 53 | ret->text_wrap = 0; 54 | ret->text_v_align = 2; 55 | ret->text_justlast = 0; 56 | ret->rotation = 0; 57 | 58 | ret->fg_color = 0x40; 59 | ret->bg_color = 0x41; 60 | 61 | ret->pattern = 0; 62 | 63 | ret->bottom = 0; 64 | ret->top = 0; 65 | ret->left = 0; 66 | ret->right = 0; 67 | 68 | ret->bottom_color = 0x40; 69 | ret->top_color = 0x40; 70 | ret->left_color = 0x40; 71 | ret->right_color = 0x40; 72 | 73 | return ret; 74 | } 75 | 76 | void fmt_destroy(struct xl_format *fmt) 77 | { 78 | free(fmt->fontname); 79 | free(fmt->num_format_str); 80 | free(fmt); 81 | } 82 | 83 | /* 84 | * Generate an Excel BIFF XF record. */ 85 | struct pkt *fmt_get_xf(struct xl_format *fmt, int style) 86 | { 87 | struct pkt *pkt; 88 | unsigned int align; 89 | int atr_num; 90 | int atr_fnt; 91 | int atr_alc; 92 | int atr_bdr; 93 | int atr_pat; 94 | int atr_prot; 95 | unsigned int icv; 96 | unsigned int fill; 97 | unsigned int border1; 98 | unsigned int border2; 99 | 100 | pkt = pkt_init(20, FIXED_PACKET); 101 | if (pkt == NULL) 102 | return NULL; 103 | 104 | /* Flags to indicate if attributes have been set */ 105 | atr_num = (fmt->num_format != 0); 106 | atr_fnt = (fmt->font_index != 0); 107 | atr_alc = fmt->text_wrap; 108 | atr_bdr = (fmt->bottom || fmt->top || fmt->left || fmt->right); 109 | atr_pat = (fmt->fg_color || fmt->bg_color || fmt->pattern); 110 | atr_prot = 0; 111 | 112 | /* Zero the default border colour if the border has not been set */ 113 | if (fmt->bottom == 0) fmt->bottom_color = 0; 114 | if (fmt->top == 0) fmt->top_color = 0; 115 | if (fmt->right == 0) fmt->right_color = 0; 116 | if (fmt->left == 0) fmt->left_color = 0; 117 | 118 | align = fmt->text_h_align; 119 | align |= fmt->text_wrap << 3; 120 | align |= fmt->text_v_align << 4; 121 | align |= fmt->text_justlast << 7; 122 | align |= fmt->rotation << 8; 123 | align |= atr_num << 10; 124 | align |= atr_fnt << 11; 125 | align |= atr_alc << 12; 126 | align |= atr_bdr << 13; 127 | align |= atr_pat << 14; 128 | align |= atr_prot << 15; 129 | 130 | icv = fmt->fg_color; 131 | icv |= fmt->bg_color << 7; 132 | 133 | fill = fmt->pattern; 134 | fill |= fmt->bottom << 6; 135 | fill |= fmt->bottom_color << 9; 136 | 137 | border1 = fmt->top; 138 | border1 |= fmt->left << 3; 139 | border1 |= fmt->right << 6; 140 | border1 |= fmt->top_color << 9; 141 | 142 | border2 = fmt->left_color; 143 | border2 |= fmt->right_color << 7; 144 | 145 | /* Write header */ 146 | pkt_add16_le(pkt, 0x00E0); /* Record identifier */ 147 | pkt_add16_le(pkt, 0x0010); /* Number of bytes to follow */ 148 | 149 | /* Payload */ 150 | pkt_add16_le(pkt, fmt->font_index); /* Index to FONT record */ 151 | pkt_add16_le(pkt, fmt->num_format); /* Index to FORMAT record */ 152 | pkt_add16_le(pkt, style); /* Style and other options */ 153 | pkt_add16_le(pkt, align); /* Alignment */ 154 | pkt_add16_le(pkt, icv); /* Color palette and other options */ 155 | pkt_add16_le(pkt, fill); /* Fill and border line style */ 156 | pkt_add16_le(pkt, border1); /* Border line style and color */ 157 | pkt_add16_le(pkt, border2); /* Border color */ 158 | 159 | return pkt; 160 | } 161 | 162 | /* 163 | * Generate an Excel BIFF FONT record. */ 164 | struct pkt *fmt_get_font(struct xl_format *fmt) 165 | { 166 | struct pkt *pkt; 167 | int cch; 168 | int grbit; 169 | 170 | pkt = pkt_init(0, VARIABLE_PACKET); 171 | if (pkt == NULL) 172 | return NULL; 173 | 174 | cch = strlen(fmt->fontname); 175 | 176 | grbit = 0x00; 177 | if (fmt->italic) 178 | grbit |= 0x02; 179 | if (fmt->font_strikeout) 180 | grbit |= 0x08; 181 | if (fmt->font_outline) 182 | grbit |= 0x10; 183 | if (fmt->font_shadow) 184 | grbit |= 0x20; 185 | 186 | /* Write header */ 187 | pkt_add16_le(pkt, 0x0031); /* Record identifier */ 188 | pkt_add16_le(pkt, 0x000F + cch); /* Number of bytes to follow */ 189 | 190 | /* Write data */ 191 | pkt_add16_le(pkt, fmt->size * 20); /* Height of font (1/20th of a point) */ 192 | pkt_add16_le(pkt, grbit); /* Font attributes */ 193 | pkt_add16_le(pkt, fmt->color); /* Index to color palette */ 194 | pkt_add16_le(pkt, fmt->bold); /* Bold style */ 195 | pkt_add16_le(pkt, fmt->font_script); /* Superscript/subscript */ 196 | pkt_add8(pkt, fmt->underline); /* Underline */ 197 | pkt_add8(pkt, fmt->font_family); /* Font family */ 198 | pkt_add8(pkt, fmt->font_charset); /* Font charset */ 199 | pkt_add8(pkt, 0x00); /* Reserved */ 200 | pkt_add8(pkt, cch); /* Length of font name (count of ch) */ 201 | pkt_addraw(pkt, (unsigned char *)fmt->fontname, cch); /* Fontname */ 202 | 203 | return pkt; 204 | } 205 | 206 | void fmt_set_bold(struct xl_format *fmt, int bold_val) 207 | { 208 | if (bold_val > 0) 209 | fmt->bold = 0x2BC; 210 | else 211 | fmt->bold = 0x190; 212 | } 213 | 214 | struct key_value { 215 | char *name; 216 | int value; 217 | }; 218 | 219 | void fmt_set_align(struct xl_format *fmt, char *align) 220 | { 221 | int i; 222 | int num_vals; 223 | struct key_value halign[] = { 224 | {"left", 1}, 225 | {"centre", 2}, 226 | {"center", 2}, 227 | {"right", 3}, 228 | {"fill", 4}, 229 | {"justify", 5}, 230 | {"merge", 6} 231 | }; 232 | struct key_value valign[] = { 233 | {"top", 0}, 234 | {"vcentre", 1}, 235 | {"vcenter", 1}, 236 | {"bottom", 2}, 237 | {"vjustify", 3} 238 | }; 239 | 240 | num_vals = sizeof(halign) / sizeof(struct key_value); 241 | for (i = 0; i < num_vals; i++) { 242 | if (strcmp(align, halign[i].name) == 0) { 243 | fmt->text_h_align = halign[i].value; 244 | return; 245 | } 246 | } 247 | 248 | num_vals = sizeof(valign) / sizeof(struct key_value); 249 | for (i = 0; i < num_vals; i++) { 250 | if (strcmp(align, valign[i].name) == 0) { 251 | fmt->text_v_align = valign[i].value; 252 | return; 253 | } 254 | } 255 | } 256 | 257 | void fmt_set_merge(struct xl_format *fmt) 258 | { 259 | fmt->text_h_align = 6; 260 | } 261 | 262 | void fmt_set_color(struct xl_format *fmt, char *colorname) 263 | { 264 | fmt->color = fmt_get_color(colorname); 265 | } 266 | 267 | void fmt_set_text_wrap(struct xl_format *fmt, int val) 268 | { 269 | fmt->text_wrap = val; 270 | } 271 | 272 | void fmt_set_border_color(struct xl_format *fmt, char *colorname) 273 | { 274 | int color; 275 | 276 | color = fmt_get_color(colorname); 277 | fmt->bottom_color = color; 278 | fmt->top_color = color; 279 | fmt->left_color = color; 280 | fmt->right_color = color; 281 | } 282 | 283 | void fmt_set_bg_color(struct xl_format *fmt, char *colorname) 284 | { 285 | fmt->bg_color = fmt_get_color(colorname); 286 | } 287 | 288 | void fmt_set_fg_color(struct xl_format *fmt, char *colorname) 289 | { 290 | fmt->fg_color = fmt_get_color(colorname); 291 | } 292 | 293 | void fmt_set_border(struct xl_format *fmt, int style) 294 | { 295 | fmt->bottom = style; 296 | fmt->top = style; 297 | fmt->left = style; 298 | fmt->right = style; 299 | } 300 | 301 | void fmt_set_colori(struct xl_format *fmt, int colorval) 302 | { 303 | if (colorval < 8 || colorval > 63) 304 | fmt->color = 0x7FFF; 305 | 306 | fmt->color = colorval; 307 | } 308 | 309 | void fmt_set_pattern(struct xl_format *fmt, int pattern) 310 | { 311 | fmt->pattern = pattern; 312 | } 313 | 314 | void fmt_set_rotation(struct xl_format *fmt, int val) 315 | { 316 | fmt->rotation = val; 317 | } 318 | 319 | void fmt_set_size(struct xl_format *fmt, int size) 320 | { 321 | fmt->size = size; 322 | } 323 | 324 | void fmt_set_num_format(struct xl_format *fmt, int format) 325 | { 326 | fmt->num_format = format; 327 | } 328 | 329 | void fmt_set_font(struct xl_format *fmt, char *font) 330 | { 331 | if (fmt->fontname) 332 | free(fmt->fontname); 333 | fmt->fontname = strdup(font); 334 | } 335 | 336 | void fmt_set_underline(struct xl_format *fmt, int val) 337 | { 338 | fmt->underline = val; 339 | } 340 | 341 | void fmt_set_num_format_str(struct xl_format *fmt, char *str) 342 | { 343 | fmt->num_format_str = strdup(str); 344 | } 345 | 346 | static int fmt_get_color(char *colorname) 347 | { 348 | int num_colors; 349 | int i; 350 | 351 | struct key_value colors[] = { 352 | {"aqua", 0x0F}, 353 | {"black", 0x08}, 354 | {"blue", 0x0C}, 355 | {"fuchsia", 0x0E}, 356 | {"gray", 0x17}, 357 | {"grey", 0x17}, 358 | {"green", 0x11}, 359 | {"lime", 0x0B}, 360 | {"navy", 0x12}, 361 | {"orange", 0x1D}, 362 | {"purple", 0x24}, 363 | {"red", 0x0A}, 364 | {"silver", 0x16}, 365 | {"white", 0x09}, 366 | {"yellow", 0x0D} 367 | }; 368 | 369 | num_colors = sizeof(colors) / sizeof(struct key_value); 370 | for (i = 0; i < num_colors; i++) { 371 | if (strcmp(colorname, colors[i].name) == 0) 372 | return colors[i].value; 373 | } 374 | 375 | return 0x7FFF; 376 | } 377 | 378 | static int fhc(char *str) 379 | { 380 | int hash = 0; 381 | while (*str) 382 | hash = (31 * hash) + *str++; 383 | return hash; 384 | } 385 | 386 | int fmt_gethash(struct xl_format *fmt) 387 | { 388 | int hash; 389 | 390 | hash = fhc(fmt->fontname); 391 | hash += fmt->size; 392 | hash += (fmt->font_script + fmt->underline); 393 | hash += (fmt->font_strikeout + fmt->bold + fmt->font_outline); 394 | hash += (fmt->font_family + fmt->font_charset); 395 | hash += (fmt->font_shadow + fmt->color + fmt->italic); 396 | if (fmt->num_format_str != NULL) 397 | hash += fhc(fmt->num_format_str); 398 | 399 | return hash; 400 | } 401 | -------------------------------------------------------------------------------- /src/formula.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "bsdqueue.h" 23 | #include "formula.h" 24 | #include "stream.h" 25 | 26 | enum token_types { 27 | TOKEN_EQUALS, 28 | TOKEN_LPAREN, 29 | TOKEN_RPAREN, 30 | TOKEN_OPERATOR, 31 | TOKEN_CELL, 32 | TOKEN_CELLRANGE, 33 | TOKEN_FUNCTION, 34 | TOKEN_NUMBER, 35 | TOKEN_STRING, 36 | TOKEN_COMMA 37 | }; 38 | 39 | enum tokenizer_state { 40 | TS_DEFAULT, 41 | TS_WORD, 42 | TS_NUMBER, 43 | TS_STRING 44 | }; 45 | 46 | struct token { 47 | int type; 48 | char *data; 49 | TAILQ_ENTRY(token) tokens; 50 | }; 51 | 52 | /* Declaration type */ 53 | TAILQ_HEAD(token_list, token); 54 | 55 | struct xl_functions { 56 | char *name; 57 | int code; 58 | int argc; 59 | int class; 60 | }; 61 | 62 | struct xl_functions biff5_funcs[] = { 63 | {"SUM", 4, -1, 0}, 64 | {"ABS", 24, 1, 1} 65 | }; 66 | 67 | #ifdef FORMULA_DEBUG 68 | static void dump_hex(void *vp, int length); 69 | #endif 70 | 71 | int is_func(char *func) 72 | { 73 | int num_funcs; 74 | int i; 75 | 76 | num_funcs = sizeof(biff5_funcs) / sizeof(biff5_funcs[0]); 77 | for (i = 0; i < num_funcs; i++) { 78 | if (strcmp(func, biff5_funcs[i].name) == 0) 79 | return 1; 80 | } 81 | return 0; 82 | } 83 | 84 | void tokenize(char *inp, struct token_list *tl) 85 | { 86 | char token[128]; 87 | int tp; 88 | char ch; 89 | char *strpos = inp, *strend = inp + strlen(inp); 90 | int state; 91 | struct token *tn; 92 | 93 | state = TS_DEFAULT; 94 | tp = 0; 95 | tn = NULL; 96 | 97 | /* We can skip the first = */ 98 | if (*strpos == '=') 99 | strpos++; 100 | 101 | while(strpos <= strend) { 102 | ch = *strpos; 103 | switch (state) { 104 | case TS_DEFAULT: 105 | if (ch == '\0') { 106 | break; 107 | } 108 | if (ch == '=') { 109 | tn = malloc(sizeof(struct token)); 110 | tn->type = TOKEN_EQUALS; 111 | tn->data = NULL; 112 | TAILQ_INSERT_TAIL(tl, tn, tokens); 113 | } else if (ch == ' ') { 114 | /* Do nothing */ 115 | } else if (ch == '(') { 116 | tn = malloc(sizeof(struct token)); 117 | tn->type = TOKEN_LPAREN; 118 | tn->data = NULL; 119 | TAILQ_INSERT_TAIL(tl, tn, tokens); 120 | } else if (ch == ')') { 121 | tn = malloc(sizeof(struct token)); 122 | tn->type = TOKEN_RPAREN; 123 | tn->data = NULL; 124 | TAILQ_INSERT_TAIL(tl, tn, tokens); 125 | } else if (ch == '+' || ch == '-' || ch == '>' || ch == '<' || 126 | ch == '*' || ch == '/') { 127 | /* Special case, check if this is a negative number / cell */ 128 | if (ch == '-' && tn != NULL && tn->type == TOKEN_OPERATOR) { 129 | token[tp++] = ch; 130 | } else { 131 | tn = malloc(sizeof(struct token)); 132 | tn->type = TOKEN_OPERATOR; 133 | token[0] = ch; 134 | token[1] = '\0'; 135 | tn->data = strdup(token); 136 | TAILQ_INSERT_TAIL(tl, tn, tokens); 137 | } 138 | } else if (ch == ',') { 139 | tn = malloc(sizeof(struct token)); 140 | tn->type = TOKEN_COMMA; 141 | tn->data = NULL; 142 | TAILQ_INSERT_TAIL(tl, tn, tokens); 143 | } else if (ch >= 'A' && ch <= 'Z') { 144 | token[tp++] = ch; 145 | state = TS_WORD; 146 | } else if (ch >= '0' && ch <= '9') { 147 | token[tp++] = ch; 148 | state = TS_NUMBER; 149 | } else if (ch == '$') { 150 | token[tp++] = ch; 151 | state = TS_WORD; 152 | } else if (ch == '"') { 153 | state = TS_STRING; 154 | } 155 | else printf("UNKNOWN TOKEN\n"); 156 | break; 157 | case TS_WORD: 158 | if (ch >= 'A' && ch <= 'Z') { 159 | token[tp++] = ch; 160 | } else if (ch == '$') { 161 | token[tp++] = ch; 162 | } else if (ch == ':') { 163 | token[tp++] = ch; 164 | } else if (ch >= '0' && ch <= '9') { 165 | token[tp++] = ch; 166 | } else { 167 | token[tp] = '\0'; 168 | tp = 0; 169 | if (is_func(token)) { 170 | tn = malloc(sizeof(struct token)); 171 | tn->type = TOKEN_FUNCTION; 172 | tn->data = strdup(token); 173 | TAILQ_INSERT_TAIL(tl, tn, tokens); 174 | } else if (strchr(token, ':') != NULL) { 175 | tn = malloc(sizeof(struct token)); 176 | tn->type = TOKEN_CELLRANGE; 177 | tn->data = strdup(token); 178 | TAILQ_INSERT_TAIL(tl, tn, tokens); 179 | } else { 180 | /* Assume it's a cell? */ 181 | tn = malloc(sizeof(struct token)); 182 | tn->type = TOKEN_CELL; 183 | tn->data = strdup(token); 184 | TAILQ_INSERT_TAIL(tl, tn, tokens); 185 | } 186 | state = TS_DEFAULT; 187 | continue; 188 | } 189 | break; 190 | case TS_STRING: 191 | if (ch == '"') { 192 | token[tp] = '\0'; 193 | tp = 0; 194 | tn = malloc(sizeof(struct token)); 195 | tn->type = TOKEN_STRING; 196 | tn->data = strdup(token); 197 | TAILQ_INSERT_TAIL(tl, tn, tokens); 198 | state = TS_DEFAULT; 199 | } else 200 | token[tp++] = ch; 201 | break; 202 | case TS_NUMBER: 203 | if (ch < '0' || ch > '9') { 204 | token[tp] = '\0'; 205 | tp = 0; 206 | tn = malloc(sizeof(struct token)); 207 | tn->type = TOKEN_NUMBER; 208 | tn->data = strdup(token); 209 | TAILQ_INSERT_TAIL(tl, tn, tokens); 210 | state = TS_DEFAULT; 211 | continue; 212 | } else 213 | token[tp++] = ch; 214 | break; 215 | } 216 | strpos++; 217 | } 218 | } 219 | 220 | /* operators 221 | * precedence operators associativity 222 | * 1 ! right to left 223 | * 2 * / % left to right 224 | * 3 + - left to right 225 | * 4 = right to left */ 226 | int op_preced(const char c) 227 | { 228 | switch(c) { 229 | case '!': 230 | return 4; 231 | case '*': case '/': case '%': 232 | return 3; 233 | case '+': case '-': 234 | return 2; 235 | case '=': 236 | return 1; 237 | } 238 | return 0; 239 | } 240 | 241 | int op_left_assoc(const char c) 242 | { 243 | switch(c) { 244 | /* left to right */ 245 | case '*': case '/': case '%': case '+': case '-': 246 | return 1; 247 | /* right to left */ 248 | case '=': case '!': 249 | return 0; 250 | } 251 | return 0; 252 | } 253 | 254 | void encode_operator(struct pkt *pkt, const char op) 255 | { 256 | switch (op) { 257 | case '+': 258 | pkt_add8(pkt, 0x03); /* tAdd */ 259 | break; 260 | case '-': 261 | pkt_add8(pkt, 0x04); /* tSub */ 262 | break; 263 | case '*': 264 | pkt_add8(pkt, 0x05); /* tMul */ 265 | break; 266 | case '/': 267 | pkt_add8(pkt, 0x06); /* tDiv */ 268 | break; 269 | } 270 | } 271 | 272 | void encode_number(struct pkt *pkt, const char *data) 273 | { 274 | int number; 275 | 276 | number = strtol(data, NULL, 10); 277 | pkt_add8(pkt, 0x1E); /* tInt */ 278 | if (number < 0) { 279 | pkt_add16_le(pkt, -number); 280 | pkt_add8(pkt, 0x13); /* tUminus */ 281 | } else 282 | pkt_add16_le(pkt, number); 283 | } 284 | 285 | /* Convert a cell in A1 notation to 0 based row/column notation: 286 | * Examples: $A$1 -> 0, 0 287 | * Returns: row, col, row_rel, col_rel 288 | */ 289 | int parse_A1(const char *cell, int *row_out, int *col_out, int *row_rel, int *col_rel) 290 | { 291 | int i; 292 | int mul; 293 | int col; 294 | int row; 295 | int col_absolute; 296 | int row_absolute; 297 | int row_start; 298 | 299 | col_absolute = 0; 300 | row_absolute = 0; 301 | /* Check if the first character is a $. If the $ is present, then the 302 | * column is an absolute position. If it is missing the column is 303 | * relative. */ 304 | if (cell[0] == '$') { 305 | col_absolute = 1; 306 | } 307 | 308 | /* Scan through the cell string looking for a $ or [0-9] */ 309 | row_start = strcspn(cell + col_absolute, "$0123456789") + col_absolute; 310 | if (row_start == strlen(cell)) { 311 | printf("Invalid\n"); 312 | return -1; 313 | } 314 | 315 | if (cell[row_start] == '$') { 316 | row_absolute = 1; 317 | row_start++; 318 | } 319 | 320 | mul = 0; 321 | col = 0; 322 | for (i = row_start - 1 - row_absolute; i >= col_absolute; i--) { 323 | if (mul == 0) 324 | col += (cell[i] - 65); 325 | else 326 | col += (mul * 26 * (cell[i] - 64)); 327 | mul++; 328 | } 329 | 330 | row = strtol(cell + row_start, NULL, 10); 331 | row--; 332 | 333 | if (row_out) 334 | *row_out = row; 335 | if (col_out) 336 | *col_out = col; 337 | if (row_rel) 338 | *row_rel = !row_absolute; 339 | if (col_rel) 340 | *col_rel = !col_absolute; 341 | 342 | return 0; 343 | } 344 | 345 | void encode_cell(struct pkt *pkt, const char *data, int class) 346 | { 347 | int row, col, c_rel, r_rel; 348 | 349 | if (parse_A1(data, &row, &col, &r_rel, &c_rel) == -1) 350 | return; 351 | 352 | row |= c_rel << 14; 353 | row |= r_rel << 15; 354 | pkt_add8(pkt, 0x44); /* RefV */ 355 | pkt_add16_le(pkt, row); 356 | pkt_add8(pkt, col); 357 | #if 0 358 | col |= c_rel << 14; 359 | col |= r_rel << 15; 360 | 361 | pkt_add8(pkt, 0x44); /* RefV */ 362 | pkt_add16_le(pkt, row); 363 | pkt_add16_le(pkt, col); 364 | #endif 365 | 366 | } 367 | 368 | void encode_function(struct pkt *pkt, const char *data, const int argc) 369 | { 370 | int num_funcs; 371 | int i; 372 | 373 | num_funcs = sizeof(biff5_funcs) / sizeof(biff5_funcs[0]); 374 | for (i = 0; i < num_funcs; i++) { 375 | if (strcmp(data, biff5_funcs[i].name) == 0) 376 | break; 377 | } 378 | if (i == num_funcs) { 379 | /* This should never happen!! */ 380 | return; 381 | } 382 | 383 | if (biff5_funcs[i].argc >= 0) { 384 | pkt_add8(pkt, 0x41); /* tFuncV */ 385 | } else { 386 | pkt_add8(pkt, 0x42); /* tFuncVarV */ 387 | pkt_add8(pkt, argc); 388 | } 389 | pkt_add16_le(pkt, biff5_funcs[i].code); 390 | } 391 | 392 | struct func_stack { 393 | int argc; 394 | int class; 395 | }; 396 | 397 | /* Based on code from: 398 | * http://en.wikipedia.org/wiki/Shunting-yard_algorithm */ 399 | int parse_token_list(struct token_list *tlist, struct pkt *pkt) 400 | { 401 | struct token *token; 402 | struct token *stack[32]; 403 | unsigned int sl; /* Stack length */ 404 | struct func_stack func_stack[32]; /* Function stack */ 405 | unsigned int fl; /* Function length */ 406 | struct token *sctoken; 407 | 408 | sl = 0; 409 | fl = 0; 410 | func_stack[fl].argc = 0; 411 | func_stack[fl].class = 1; 412 | /* Process one token at a time */ 413 | TAILQ_FOREACH(token, tlist, tokens) { 414 | /* if it's a number encode it right away */ 415 | if (token->type == TOKEN_NUMBER) { 416 | encode_number(pkt, token->data); 417 | func_stack[fl].argc++; 418 | } 419 | else if (token->type == TOKEN_CELL) { 420 | encode_cell(pkt, token->data, func_stack[fl].class); 421 | func_stack[fl].argc++; 422 | } 423 | /* If it's a function push it onto the stack */ 424 | else if (token->type == TOKEN_FUNCTION) { 425 | stack[sl] = token; 426 | ++sl; 427 | func_stack[fl].argc++; 428 | fl++; 429 | func_stack[fl].argc = 0; 430 | } else if (token->type == TOKEN_OPERATOR) { 431 | while (sl > 0) { 432 | sctoken = stack[sl - 1]; 433 | /* While there is an operator token, o2, at the top of the stack 434 | * op1 is left-associative and its precedence is less than 435 | * or equal to that of op2, or op1 is right-associative and its 436 | * precedence is less than that of op2 */ 437 | if (sctoken->type == TOKEN_OPERATOR && 438 | ((op_left_assoc(sctoken->data[0]) && 439 | (op_preced(sctoken->data[0]) <= op_preced(sctoken->data[0]))) || 440 | (!op_left_assoc(sctoken->data[0]) && 441 | (op_preced(sctoken->data[0]) < op_preced(sctoken->data[0]))))) { 442 | /* encode operator */ 443 | encode_operator(pkt, sctoken->data[0]); 444 | sl--; 445 | } else { 446 | break; 447 | } 448 | } 449 | /* Push operator onto the stack */ 450 | stack[sl] = token; 451 | ++sl; 452 | /* When we encounter an operator, we can subtract 1 from the argument 453 | * count of the current function because (almost always?) the next 454 | * token is an operand and shouldn't count towards the argument count. */ 455 | func_stack[fl].argc--; 456 | } 457 | /* If the token is a left parenthesis, then push it onto the stack. */ 458 | else if (token->type == TOKEN_LPAREN) { 459 | stack[sl] = token; 460 | ++sl; 461 | } 462 | /* If the token is a right parenthesis: */ 463 | else if (token->type == TOKEN_RPAREN) { 464 | int pe = 0; 465 | /* Until the token at the top of the stack is a left parenthesis, 466 | * pop operators off the stack onto the output queue */ 467 | while (sl > 0) { 468 | sctoken = stack[sl - 1]; 469 | if (sctoken->type == TOKEN_LPAREN) { 470 | pe = 1; 471 | break; 472 | } 473 | else { 474 | if (sctoken->type == TOKEN_OPERATOR) { 475 | encode_operator(pkt, sctoken->data[0]); 476 | } else { 477 | printf("Need to encode for unknown token!\n"); 478 | } 479 | sl--; 480 | } 481 | } 482 | /* If the stack runs out without finding a left parenthesis, then there 483 | * are mismatched parentheses. */ 484 | if (!pe) { 485 | printf("Error: parentheses mismatched\n"); 486 | return -1; 487 | } 488 | /* Pop the left parenthesis from the stack, but not onto the output queue. */ 489 | sl--; 490 | /* If the token at the top of the stack is a function token, pop it onto 491 | * the output queue. */ 492 | if (sl > 0) { 493 | sctoken = stack[sl - 1]; 494 | if (sctoken->type == TOKEN_FUNCTION) { 495 | #ifdef FORMULA_DEBUG 496 | printf("Arg count for function: %d\n", func_stack[fl].argc); 497 | #endif 498 | encode_function(pkt, sctoken->data, func_stack[fl].argc); 499 | sl--; 500 | fl--; 501 | } 502 | } 503 | } 504 | } 505 | 506 | /* When there are no more tokens to read: 507 | * While there are still operator tokens in the stack: */ 508 | while(sl > 0) { 509 | sctoken = stack[sl - 1]; 510 | if (sctoken->type == TOKEN_LPAREN || sctoken->type == TOKEN_RPAREN) { 511 | printf("Error: parentheses mismatched\n"); 512 | return -1; 513 | } 514 | if (sctoken->type == TOKEN_NUMBER) { 515 | encode_number(pkt, token->data); 516 | } else if (sctoken->type == TOKEN_OPERATOR) { 517 | encode_operator(pkt, sctoken->data[0]); 518 | } else { 519 | printf("There's still something to encode\n"); 520 | } 521 | --sl; 522 | } 523 | 524 | #ifdef FORMULA_DEBUG 525 | dump_hex(pkt->data, pkt->len); 526 | #endif 527 | 528 | return 0; 529 | } 530 | 531 | #ifdef FORMULA_DEBUG 532 | static void dump_hex(void *vp, int length) 533 | { 534 | char linebuf[80]; 535 | int i; 536 | int linebuf_dirty = 0; 537 | unsigned char *p = (unsigned char *)vp; 538 | 539 | memset(linebuf, ' ', sizeof(linebuf)); 540 | linebuf[70] = '\0'; 541 | 542 | for (i=0; i < length; ++i) { 543 | int x = i % 16; 544 | int ch = (unsigned)p[i]; 545 | char hex[20]; 546 | if (x >= 8) 547 | x = x * 3 + 1; 548 | else 549 | x = x * 3; 550 | snprintf(hex, sizeof(hex), "%02x", ch); 551 | linebuf[x] = hex[0]; 552 | linebuf[x+1] = hex[1]; 553 | 554 | if (isprint(ch)) 555 | linebuf[52+(i%16)] = ch; 556 | else 557 | linebuf[52+(i%16)] = '.'; 558 | 559 | linebuf_dirty = 1; 560 | if (!((i+1)%16)) { 561 | printf("%s\n", linebuf); 562 | memset(linebuf, ' ', sizeof(linebuf)); 563 | linebuf[70] = '\0'; 564 | linebuf_dirty = 0; 565 | } 566 | } 567 | if (linebuf_dirty == 1) 568 | printf("%s\n", linebuf); 569 | } 570 | #endif 571 | 572 | int process_formula(char *input, struct pkt *pkt) 573 | { 574 | struct token_list tlist; 575 | struct token *token; 576 | 577 | #ifdef FORMULA_DEBUG 578 | printf("Input: %s\n", input); 579 | #endif 580 | TAILQ_INIT(&tlist); 581 | tokenize(input, &tlist); 582 | #ifdef FORMULA_DEBUG 583 | printf("---\n"); 584 | TAILQ_FOREACH(token, &tlist, tokens) { 585 | switch (token->type) { 586 | case TOKEN_EQUALS: 587 | printf("TOKEN_EQUALS\n"); 588 | break; 589 | case TOKEN_LPAREN: 590 | printf("TOKEN_LPAREN\n"); 591 | break; 592 | case TOKEN_RPAREN: 593 | printf("TOKEN_RPAREN\n"); 594 | break; 595 | case TOKEN_OPERATOR: 596 | printf("TOKEN_OPERATOR: %s\n", token->data); 597 | break; 598 | case TOKEN_CELL: 599 | printf("TOKEN_CELL: %s\n", token->data); 600 | break; 601 | case TOKEN_CELLRANGE: 602 | printf("TOKEN_CELLRANGE: %s\n", token->data); 603 | break; 604 | case TOKEN_FUNCTION: 605 | printf("TOKEN_FUNCTION: %s\n", token->data); 606 | break; 607 | case TOKEN_NUMBER: 608 | printf("TOKEN_NUMBER: %s\n", token->data); 609 | break; 610 | case TOKEN_STRING: 611 | printf("TOKEN_STRING: %s\n", token->data); 612 | break; 613 | case TOKEN_COMMA: 614 | printf("TOKEN_COMMA\n"); 615 | break; 616 | default: 617 | printf("Unknown token %d\n", token->type); 618 | } 619 | } 620 | #endif 621 | parse_token_list(&tlist, pkt); 622 | while ((token = TAILQ_FIRST(&tlist))) { 623 | TAILQ_REMOVE(&tlist, token, tokens); 624 | free(token->data); 625 | free(token); 626 | } 627 | return 0; 628 | } 629 | -------------------------------------------------------------------------------- /src/hashhelp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include "hashhelp.h" 19 | 20 | struct htbl *hashtbl_new(size_t size) 21 | { 22 | struct htbl *table; 23 | 24 | table = malloc(sizeof(struct htbl)); 25 | if (table == NULL) 26 | return NULL; 27 | 28 | table->nodes = calloc(size, sizeof(struct hashnode *)); 29 | if (table->nodes == NULL) { 30 | free(table); 31 | return NULL; 32 | } 33 | 34 | if (size <= 0) 35 | size = 10; /* A sane default */ 36 | 37 | table->filled = 0; 38 | table->size = size; 39 | return table; 40 | } 41 | 42 | void hashtbl_destroy(struct htbl *tbl) 43 | { 44 | size_t n; 45 | struct hashnode *node, *oldnode; 46 | 47 | for (n = 0; n < tbl->size; n++) { 48 | node = tbl->nodes[n]; 49 | while (node) { 50 | oldnode = node; 51 | node = node->next; 52 | free(oldnode); 53 | } 54 | } 55 | free(tbl->nodes); 56 | free(tbl); 57 | } 58 | 59 | static void hashtbl_resize(struct htbl *tbl, int new_size) 60 | { 61 | struct htbl *newtbl; 62 | size_t n; 63 | struct hashnode *node; 64 | 65 | newtbl = hashtbl_new(new_size); 66 | /* For some reason we can't allocate new nodes, but that's actually 67 | * ok because we'll just use the old inefficient hash table. */ 68 | if (newtbl == NULL) 69 | return; 70 | 71 | for (n = 0; n < tbl->size; n++) { 72 | node = tbl->nodes[n]; 73 | while (node) { 74 | hashtbl_insert(newtbl, node->key, node->data); 75 | node = node->next; 76 | } 77 | } 78 | free(tbl->nodes); 79 | tbl->nodes = newtbl->nodes; 80 | tbl->filled = newtbl->filled; 81 | tbl->size = newtbl->size; 82 | free(newtbl); 83 | } 84 | 85 | int hashtbl_insert(struct htbl *tbl, int key, int data) 86 | { 87 | struct hashnode *node; 88 | size_t hash = key % tbl->size; 89 | 90 | if (tbl->filled >= (tbl->size << 2)) { 91 | hashtbl_resize(tbl, (tbl->size << 2)); 92 | } 93 | 94 | node = tbl->nodes[hash]; 95 | while (node) { 96 | if (node->key == key) { 97 | node->data = data; 98 | return 0; 99 | } 100 | node = node->next; 101 | } 102 | 103 | if (!(node = malloc(sizeof(struct hashnode)))) 104 | return -1; 105 | node->key = key; 106 | node->data = data; 107 | node->next = tbl->nodes[hash]; 108 | tbl->nodes[hash] = node; 109 | tbl->filled++; 110 | return 0; 111 | } 112 | 113 | int hashtbl_get(struct htbl *tbl, int key) 114 | { 115 | struct hashnode *node; 116 | size_t hash = key % tbl->size; 117 | 118 | node = tbl->nodes[hash]; 119 | while (node) { 120 | if (node->key == key) return node->data; 121 | node = node->next; 122 | } 123 | return -1; 124 | } 125 | -------------------------------------------------------------------------------- /src/io_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Guilherme Steinmann 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "io_handler.h" 18 | 19 | struct xl_io_handler xl_file_handler = { 20 | xl_file_create, 21 | xl_file_write, 22 | xl_file_close 23 | }; 24 | 25 | void* xl_file_create(const char *filename) 26 | { 27 | return filename ? (void*)fopen(filename,"wb") : NULL; 28 | } 29 | 30 | int xl_file_write(void *handle,const void* buffer,size_t size) 31 | { 32 | return handle ? fwrite(buffer,1,size,(FILE*)handle) : -1; 33 | } 34 | 35 | int xl_file_close(void *handle) 36 | { 37 | return handle ? fclose((FILE*)handle) : -1; 38 | } 39 | -------------------------------------------------------------------------------- /src/olewriter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "olewriter.h" 24 | #include "stream.h" 25 | #include "io_handler.h" 26 | 27 | int ow_init(struct owctx *ow, struct xl_io_handler io_handler, const char *filename); 28 | void ow_write_pps(struct owctx *ow, char *name, int pps_type, int pps_dir, int pps_start, int pps_size); 29 | void ow_write_property_storage(struct owctx *ow); 30 | void ow_write_padding(struct owctx *ow); 31 | void ow_write_big_block_depot(struct owctx *ow); 32 | 33 | struct owctx * ow_new(const char *filename) 34 | { 35 | return ow_new_ex(xl_file_handler,filename); 36 | } 37 | 38 | struct owctx * ow_new_ex(struct xl_io_handler io_handler, const char *filename) 39 | { 40 | struct owctx *ow; 41 | 42 | ow = malloc(sizeof(struct owctx)); 43 | 44 | if (ow_init(ow, io_handler, filename) == -1) { 45 | free(ow); 46 | return NULL; 47 | } 48 | 49 | return ow; 50 | } 51 | 52 | void ow_destroy(struct owctx *ow) 53 | { 54 | if (!ow->fileclosed) 55 | ow_close(ow); 56 | free(ow); 57 | } 58 | 59 | int ow_init(struct owctx *ow, struct xl_io_handler io_handler, const char *filename) 60 | { 61 | void *fp; 62 | 63 | ow->olefilename = filename; 64 | ow->io_handler = io_handler; 65 | ow->io_handle = NULL; 66 | ow->fileclosed = 0; 67 | ow->biff_only = 0; 68 | ow->size_allowed = 0; 69 | ow->biffsize = 0; 70 | ow->booksize = 0; 71 | ow->big_blocks = 0; 72 | ow->list_blocks = 0; 73 | ow->root_start = 0; 74 | ow->block_count = 4; 75 | 76 | if (filename == NULL) 77 | return -1; 78 | 79 | if (!ow->io_handler.create) return -1; 80 | if (!ow->io_handler.write) return -1; 81 | if (!ow->io_handler.close) return -1; 82 | 83 | /* Open file for writing */ 84 | fp = ow->io_handler.create(filename); 85 | if (fp == NULL) 86 | return -1; 87 | 88 | ow->io_handle = fp; 89 | 90 | return 0; 91 | } 92 | 93 | /**************************************************************************** 94 | * ow_set_size(struct owctx *ow, int biffsize) 95 | * 96 | * Set the size of the data to be written to the OLE stream 97 | * 98 | * big_blocks = (109 depot block * (128 -1 marker word) - 99 | * (1 * end words)) = 13842 100 | * maxsize = big_blocks * 512 bytes = 7087104 101 | */ 102 | int ow_set_size(struct owctx *ow, int biffsize) 103 | { 104 | int maxsize = 7087104; /* TODO: extend max size */ 105 | 106 | if (biffsize > maxsize) { 107 | ow->size_allowed = 0; 108 | return 0; 109 | } 110 | 111 | ow->biffsize = biffsize; 112 | /* Set the min file size to 4k to avoid having to use small blocks */ 113 | if (biffsize > 4096) { 114 | ow->booksize = biffsize; 115 | } else { 116 | ow->booksize = 4096; 117 | } 118 | 119 | ow->size_allowed = 1; 120 | return 1; 121 | } 122 | 123 | /**************************************************************************** 124 | * ow_calculate_sizes(struct owctx *ow) 125 | * 126 | * Calculate various sizes need for the OLE stream 127 | */ 128 | void ow_calculate_sizes(struct owctx *ow) 129 | { 130 | int datasize = ow->booksize; 131 | 132 | if (datasize % 512 == 0) { 133 | ow->big_blocks = datasize / 512; 134 | } else { 135 | ow->big_blocks = (datasize / 512) + 1; 136 | } 137 | 138 | /* There are 127 list blocks and 1 marker blocks for each big block 139 | * depot + 1 end of chain block */ 140 | ow->list_blocks = (ow->big_blocks / 127) + 1; 141 | ow->root_start = ow->big_blocks; 142 | } 143 | 144 | /**************************************************************************** 145 | * ow_write_header(struct owctx *ow) 146 | * 147 | * Write OLE header block. 148 | */ 149 | void ow_write_header(struct owctx *ow) 150 | { 151 | int root_start; 152 | int num_lists; 153 | struct pkt *pkt; 154 | int i; 155 | 156 | if (ow->biff_only) 157 | return; 158 | 159 | ow_calculate_sizes(ow); 160 | 161 | root_start = ow->root_start; 162 | num_lists = ow->list_blocks; 163 | 164 | pkt = pkt_init(0, VARIABLE_PACKET); 165 | pkt_add32(pkt, 0xD0CF11E0); /* OLE document file id part 1 */ 166 | pkt_add32(pkt, 0xA1B11AE1); /* OLE document file id part 2 */ 167 | pkt_add32_le(pkt, 0x00); /* UID of this file (can be all 0's) 1/4 */ 168 | pkt_add32_le(pkt, 0x00); /* UID of this file (can be all 0's) 2/4 */ 169 | pkt_add32_le(pkt, 0x00); /* UID of this file (can be all 0's) 3/4 */ 170 | pkt_add32_le(pkt, 0x00); /* UID of this file (can be all 0's) 4/4 */ 171 | pkt_add16_le(pkt, 0x3E); /* Revision number (almost always 0x003E) */ 172 | pkt_add16_le(pkt, 0x03); /* Version number (almost always 0x0003) */ 173 | pkt_add16(pkt, 0xFEFF); /* Byte order identifier: 174 | * (0xFEFF = Little Endian) 175 | * (0xFFFE = Big Endian) */ 176 | pkt_add16_le(pkt, 0x09); /* 2^x (9 = 512 bytes) */ 177 | pkt_add32_le(pkt, 0x06); /* Unknown 5 */ 178 | pkt_add32_le(pkt, 0x00); /* Unknown 5 */ 179 | pkt_add32_le(pkt, 0x00); /* Unknown 5 */ 180 | pkt_add32_le(pkt, num_lists); /* num_bbd_blocks */ 181 | pkt_add32_le(pkt, root_start); /* root_startblock */ 182 | pkt_add32_le(pkt, 0x00); /* Unknown 6 */ 183 | pkt_add32_le(pkt, 0x1000); /* Unknown 6 */ 184 | pkt_add32_le(pkt, -2); /* sbd_startblock */ 185 | pkt_add32_le(pkt, 0x00); /* Unknown 7 */ 186 | pkt_add32_le(pkt, -2); /* Unknown 7 */ 187 | pkt_add32_le(pkt, 0x00); /* Unknown 7 */ 188 | 189 | for (i = 1; i <= num_lists; i++) { 190 | root_start++; 191 | pkt_add32_le(pkt, root_start); 192 | 193 | } 194 | 195 | for (i = num_lists; i <= 108; i++) { 196 | pkt_add32_le(pkt, -1); /* Unused */ 197 | } 198 | 199 | ow->io_handler.write(ow->io_handle,pkt->data, pkt->len); 200 | 201 | pkt_free(pkt); 202 | } 203 | 204 | /**************************************************************************** 205 | * ow_close(struct owctx *ow) 206 | * 207 | * Write root entry, big block list and close the filehandle. 208 | * This routine is used to explicity close the open filehandle without 209 | * having to wait for destroy. 210 | */ 211 | void ow_close(struct owctx *ow) 212 | { 213 | if (!ow->size_allowed) 214 | return; 215 | 216 | if (!ow->biff_only) { 217 | ow_write_padding(ow); 218 | ow_write_property_storage(ow); 219 | ow_write_big_block_depot(ow); 220 | } 221 | ow->io_handler.close(ow->io_handle); 222 | ow->fileclosed = 1; 223 | } 224 | 225 | /**************************************************************************** 226 | * ow_write(struct owctx *ow) 227 | * 228 | * Write BIFF data to OLE file 229 | */ 230 | void ow_write(struct owctx *ow, void *data, size_t len) 231 | { 232 | ow->io_handler.write(ow->io_handle, data, len); 233 | } 234 | 235 | /**************************************************************************** 236 | * ow_write_big_block_depot(struct owctx *ow) 237 | * 238 | * Write big block depot. 239 | */ 240 | void ow_write_big_block_depot(struct owctx *ow) 241 | { 242 | int num_blocks = ow->big_blocks; 243 | int num_lists = ow->list_blocks; 244 | int total_blocks = num_lists * 128; 245 | int used_blocks = num_blocks + num_lists + 2; 246 | struct pkt *pkt; 247 | int i; 248 | 249 | pkt = pkt_init(0, VARIABLE_PACKET); 250 | for (i = 1; i <= num_blocks - 1; i++) { 251 | pkt_add32_le(pkt, i); 252 | } 253 | 254 | /* End of chain */ 255 | pkt_add32_le(pkt, -2); 256 | pkt_add32_le(pkt, -2); 257 | 258 | for (i = 1; i <= num_lists; i++) { 259 | pkt_add32_le(pkt, -3); 260 | } 261 | 262 | for (i = used_blocks; i <= total_blocks; i++) { 263 | pkt_add32_le(pkt, -1); 264 | } 265 | 266 | ow->io_handler.write(ow->io_handle,pkt->data, pkt->len); 267 | 268 | pkt_free(pkt); 269 | } 270 | 271 | /**************************************************************************** 272 | * ow_write_property_storage(struct owctx *ow) 273 | * 274 | * Write property storage. TODO: add summary sheets 275 | */ 276 | void ow_write_property_storage(struct owctx *ow) 277 | { 278 | //int rootsize = -2; 279 | int booksize = ow->booksize; 280 | 281 | ow_write_pps(ow, "Root Entry", 0x05, 1, -2, 0x00); 282 | ow_write_pps(ow, "Workbook", 0x02, -1, 0x00, booksize); 283 | ow_write_pps(ow, NULL, 0x00, -1, 0x00, 0x0000); 284 | ow_write_pps(ow, NULL, 0x00, -1, 0x00, 0x0000); 285 | } 286 | 287 | /**************************************************************************** 288 | * ow_write_pps(struct owctx *ow, char *name) 289 | * 290 | * Write property sheet in property storage 291 | */ 292 | void ow_write_pps(struct owctx *ow, char *name, int pps_type, int pps_dir, int pps_start, int pps_size) 293 | { 294 | unsigned char header[64]; 295 | int length; 296 | struct pkt *pkt; 297 | 298 | memset(header, 0, sizeof(header)); 299 | length = 0; 300 | if (name != NULL) 301 | { 302 | /* Simulate a unicode string */ 303 | char *p = name; 304 | int i = 0; 305 | while (*p != '\0') { 306 | header[i] = *p++; 307 | i += 2; 308 | } 309 | length = (strlen(name) * 2) + 2; 310 | } 311 | 312 | pkt = pkt_init(0, VARIABLE_PACKET); 313 | pkt_addraw(pkt, header, sizeof(header)); 314 | pkt_add16_le(pkt, length); /* pps_sizeofname 0x40 */ 315 | pkt_add16_le(pkt, pps_type); /* 0x42 */ 316 | pkt_add32_le(pkt, -1); /* pps_prev 0x44 */ 317 | pkt_add32_le(pkt, -1); /* pps_next 0x48 */ 318 | pkt_add32_le(pkt, pps_dir); /* pps_dir 0x4C */ 319 | 320 | pkt_add32_le(pkt, 0); /* unknown 0x50 */ 321 | pkt_add32_le(pkt, 0); /* unknown 0x54 */ 322 | pkt_add32_le(pkt, 0); /* unknown 0x58 */ 323 | pkt_add32_le(pkt, 0); /* unknown 0x5C */ 324 | pkt_add32_le(pkt, 0); /* unknown 0x60 */ 325 | 326 | pkt_add32_le(pkt, 0); /* pps_ts1s 0x64 */ 327 | pkt_add32_le(pkt, 0); /* pps_ts1d 0x68 */ 328 | pkt_add32_le(pkt, 0); /* pps_ts2s 0x6C */ 329 | pkt_add32_le(pkt, 0); /* pps_ts2d 0x70 */ 330 | pkt_add32_le(pkt, pps_start); /* pps_start 0x74 */ 331 | pkt_add32_le(pkt, pps_size); /* pps_size 0x78 */ 332 | pkt_add32_le(pkt, 0); /* unknown 0x7C */ 333 | 334 | ow->io_handler.write(ow->io_handle,pkt->data, pkt->len); 335 | 336 | pkt_free(pkt); 337 | } 338 | 339 | /**************************************************************************** 340 | * ow_write_padding(struct owctx *ow) 341 | * 342 | * Pad the end of the file 343 | */ 344 | void ow_write_padding(struct owctx *ow) 345 | { 346 | int biffsize = ow->biffsize; 347 | int min_size; 348 | 349 | if (biffsize < 4096) { 350 | min_size = 4096; 351 | } else { 352 | min_size = 512; 353 | } 354 | 355 | if (biffsize % min_size != 0) { 356 | int padding = min_size - (biffsize % min_size); 357 | unsigned char *buffer; 358 | 359 | buffer = malloc(padding); 360 | memset(buffer, 0, padding); 361 | ow->io_handler.write(ow->io_handle, buffer, padding); 362 | free(buffer); 363 | } 364 | } 365 | 366 | -------------------------------------------------------------------------------- /src/stream.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2003-2005, Claudio Leite 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of the BSF Software Project nor the names of its 16 | * contributors may be used to endorse or promote products derived 17 | * from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 30 | */ 31 | 32 | /* This code is based on Claudio Leite's packet.c file inside the 33 | * imcomm module of his bsflite program. Claudio states that his code was 34 | * inspired by libfaim's (now defunct) bstream (binary stream) 35 | * implementation. 36 | */ 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "stream.h" 44 | 45 | #define MAX_SIZE 16384 46 | 47 | struct pkt * 48 | pkt_init(size_t len, int type) 49 | { 50 | struct pkt *p = NULL; 51 | 52 | p = malloc((size_t) sizeof(struct pkt)); 53 | if (p == NULL) return NULL; 54 | 55 | if (type == VARIABLE_PACKET) p->data = malloc(MAX_SIZE); 56 | else p->data = malloc(len); 57 | 58 | if (p->data == NULL) { 59 | free(p); 60 | return NULL; 61 | } 62 | 63 | p->len = 0; 64 | p->offset = 0; 65 | 66 | return p; 67 | 68 | } 69 | 70 | void pkt_addraw(struct pkt *p, const unsigned char *bytes, size_t len) 71 | { 72 | memcpy(p->data + p->offset, bytes, len); 73 | p->offset += len; 74 | p->len += len; 75 | } 76 | 77 | void pkt_addzero(struct pkt *p, int num_zeros) 78 | { 79 | memset(p->data + p->offset, 0, num_zeros); 80 | p->offset += num_zeros; 81 | p->len += num_zeros; 82 | } 83 | 84 | void pkt_addstring(struct pkt *p, const char *bytes) { 85 | uint32_t len; 86 | 87 | len = strlen(bytes); 88 | pkt_addraw(p, (unsigned char *) bytes, len); 89 | } 90 | 91 | void pkt_add8(struct pkt *p, uint8_t val) 92 | { 93 | p->data[p->offset] = val; 94 | p->offset++; 95 | p->len++; 96 | } 97 | 98 | void pkt_add16_le(struct pkt *p, uint16_t val) 99 | { 100 | p->data[p->offset++] = (val & 0xff); 101 | p->data[p->offset++] = (val & 0xff00) >> 8; 102 | p->len += 2; 103 | } 104 | 105 | void pkt_add16(struct pkt *p, uint16_t val) 106 | { 107 | p->data[p->offset++] = (val & 0xff00) >> 8; 108 | p->data[p->offset++] = (val & 0xff); 109 | p->len += 2; 110 | } 111 | 112 | void pkt_add32_le(struct pkt *p, uint32_t val) 113 | { 114 | p->data[p->offset++] = (val & 0xff); 115 | p->data[p->offset++] = (val & 0xff00) >> 8; 116 | p->data[p->offset++] = (val & 0xff0000) >> 16; 117 | p->data[p->offset++] = (val & 0xff000000) >> 24; 118 | p->len += 4; 119 | } 120 | 121 | void pkt_add32(struct pkt *p, uint32_t val) 122 | { 123 | p->data[p->offset++] = (val & 0xff000000) >> 24; 124 | p->data[p->offset++] = (val & 0xff0000) >> 16; 125 | p->data[p->offset++] = (val & 0xff00) >> 8; 126 | p->data[p->offset++] = (val & 0xff); 127 | p->len += 4; 128 | } 129 | 130 | void pkt_free(struct pkt * p) 131 | { 132 | if (p == NULL) return; 133 | 134 | if (p->data != NULL) { 135 | free(p->data); 136 | } 137 | free(p); 138 | } 139 | 140 | -------------------------------------------------------------------------------- /src/workbook.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "workbook.h" 24 | #include "stream.h" 25 | #include "hashhelp.h" 26 | 27 | void wbook_store_window1(struct wbookctx *wbook); 28 | void wbook_store_all_fonts(struct wbookctx *wbook); 29 | void wbook_store_all_xfs(struct wbookctx *wbook); 30 | void wbook_store_all_styles(struct wbookctx *wbook); 31 | void wbook_store_boundsheet(struct wbookctx *wbook, char *sname, int offset); 32 | void wbook_store_workbook(struct wbookctx *wbook); 33 | static void wbook_store_1904(struct wbookctx *wbook); 34 | static void wbook_store_num_format(struct wbookctx *wbook, char *format, int index); 35 | static void wbook_store_codepage(struct wbookctx *wbook); 36 | void wbook_store_all_num_formats(struct wbookctx *wbook); 37 | 38 | struct wbookctx *wbook_new(const char *filename, int store_in_memory) 39 | { 40 | return wbook_new_ex(xl_file_handler, filename, store_in_memory); 41 | } 42 | 43 | struct wbookctx *wbook_new_ex(struct xl_io_handler io_handler, const char *filename, int store_in_memory) 44 | { 45 | struct wbookctx *wbook; 46 | 47 | wbook = malloc(sizeof(struct wbookctx)); 48 | wbook->biff = bw_new(); 49 | wbook->OLEwriter = ow_new_ex(io_handler,filename); 50 | if (wbook->OLEwriter == NULL) { 51 | free(wbook); 52 | return NULL; 53 | } 54 | wbook->store_in_memory = store_in_memory; 55 | wbook->epoch1904 = 0; 56 | wbook->activesheet = 0; 57 | wbook->firstsheet = 0; 58 | wbook->xf_index = 16; /* 15 style XF's and 1 cell XF. */ 59 | wbook->fileclosed = 0; 60 | wbook->biffsize = 0; 61 | wbook->sheetname = "Sheet"; 62 | wbook->tmp_format = fmt_new(0); 63 | wbook->url_format = NULL; 64 | wbook->codepage = 0x04E4; /* 1252 */ 65 | wbook->sheets = NULL; 66 | wbook->sheetcount = 0; 67 | wbook->formats = NULL; 68 | wbook->formatcount = 0; 69 | 70 | /* Add the default format for hyperlinks */ 71 | wbook->url_format = wbook_addformat(wbook); 72 | fmt_set_fg_color(wbook->url_format, "blue"); 73 | fmt_set_underline(wbook->url_format, 1); 74 | 75 | return wbook; 76 | } 77 | 78 | void wbook_close(struct wbookctx *wbook) 79 | { 80 | if (wbook->fileclosed) 81 | return; 82 | 83 | wbook_store_workbook(wbook); 84 | ow_close(wbook->OLEwriter); 85 | wbook->fileclosed = 1; 86 | } 87 | 88 | void wbook_destroy(struct wbookctx *wbook) 89 | { 90 | int i; 91 | 92 | if (!wbook->fileclosed) 93 | wbook_close(wbook); 94 | 95 | /* Delete all sheets */ 96 | for (i = 0; i < wbook->sheetcount; i++) { 97 | wsheet_destroy(wbook->sheets[i]); 98 | } 99 | 100 | /* Delete all formats */ 101 | for (i = 0; i < wbook->formatcount; i++) { 102 | //free(wbook->formats[i]); 103 | fmt_destroy(wbook->formats[i]); 104 | } 105 | 106 | fmt_destroy(wbook->tmp_format); 107 | ow_destroy(wbook->OLEwriter); 108 | bw_destroy(wbook->biff); 109 | 110 | free(wbook->sheets); 111 | free(wbook->formats); 112 | free(wbook); 113 | } 114 | 115 | struct wsheetctx * wbook_addworksheet(struct wbookctx *wbook, char *sname) 116 | { 117 | char *name = sname; 118 | int index; 119 | int malloc_flag = 0; 120 | struct wsheetctx *wsheet; 121 | 122 | if (name && strlen(name) > 31) 123 | name[31] = '\0'; 124 | 125 | index = wbook->sheetcount; 126 | if (sname == NULL) 127 | { 128 | int len = strlen(wbook->sheetname) + 20; 129 | 130 | name = malloc(len); 131 | snprintf(name, len, "%s%d", wbook->sheetname, index + 1); 132 | malloc_flag = 1; 133 | } 134 | 135 | if (wbook->sheets == NULL) 136 | wbook->sheets = malloc(sizeof(struct wsheetctx *)); 137 | else 138 | wbook->sheets = realloc(wbook->sheets, sizeof(struct wsheetctx *) * (index + 1)); 139 | 140 | wsheet = wsheet_new(name, index, wbook->activesheet, wbook->firstsheet, 141 | wbook->url_format, wbook->store_in_memory); 142 | wbook->sheets[index] = wsheet; 143 | wbook->sheetcount++; 144 | 145 | if (malloc_flag == 1) { 146 | free(name); 147 | } 148 | 149 | return wsheet; 150 | } 151 | 152 | /* Add a new format to the Excel workbook. This adds an XF record and 153 | * a FONT record. TODO: add a FORMAT record. */ 154 | struct xl_format *wbook_addformat(struct wbookctx *wbook) 155 | { 156 | int index; 157 | struct xl_format *fmt; 158 | 159 | index = wbook->formatcount; 160 | 161 | if (wbook->formats == NULL) 162 | wbook->formats = malloc(sizeof(struct xl_format *)); 163 | else 164 | wbook->formats = realloc(wbook->formats, sizeof(struct xl_format *) * (index + 1)); 165 | 166 | fmt = fmt_new(wbook->xf_index); 167 | wbook->xf_index += 1; 168 | 169 | wbook->formats[index] = fmt; 170 | wbook->formatcount++; 171 | 172 | return fmt; 173 | } 174 | 175 | /**************************************************************************** 176 | * 177 | * _calc_sheet_offsets() 178 | * 179 | * Calculate offsets for Worksheet BOF records. */ 180 | void wbook_calc_sheet_offsets(struct wbookctx *wbook) 181 | { 182 | int oBOF = 11; 183 | int oEOF = 4; 184 | int offset = wbook->biff->datasize; 185 | int i; 186 | 187 | for (i = 0; i < wbook->sheetcount; i++) { 188 | offset += oBOF + strlen(wbook->sheets[i]->name); 189 | } 190 | offset += oEOF; 191 | 192 | for (i = 0; i < wbook->sheetcount; i++) { 193 | wbook->sheets[i]->offset = offset; 194 | offset += ((struct bwctx *)wbook->sheets[i])->datasize; 195 | } 196 | 197 | wbook->biffsize = offset; 198 | } 199 | 200 | /* 201 | * wbook_store_workbook(struct wbookctx *wbook) 202 | * 203 | * Assemble worksheets into a workbook and send the BIFF data to an OLE 204 | * storage. 205 | * 206 | */ 207 | void wbook_store_workbook(struct wbookctx *wbook) 208 | { 209 | struct owctx *ole = wbook->OLEwriter; 210 | int i; 211 | 212 | /* Call the finalization methods for each worksheet */ 213 | for (i = 0; i < wbook->sheetcount; i++) { 214 | wsheet_close(wbook->sheets[i]); 215 | } 216 | 217 | /* Add workbook globals */ 218 | bw_store_bof(wbook->biff, 0x0005); 219 | wbook_store_codepage(wbook); 220 | wbook_store_window1(wbook); 221 | wbook_store_1904(wbook); 222 | wbook_store_all_fonts(wbook); 223 | wbook_store_all_num_formats(wbook); 224 | wbook_store_all_xfs(wbook); 225 | wbook_store_all_styles(wbook); 226 | wbook_calc_sheet_offsets(wbook); 227 | 228 | /* Add BOUNDSHEET records */ 229 | for (i = 0; i < wbook->sheetcount; i++) { 230 | wbook_store_boundsheet(wbook, wbook->sheets[i]->name, wbook->sheets[i]->offset); 231 | } 232 | 233 | bw_store_eof(wbook->biff); 234 | 235 | /* Write Worksheet data if data <~ 7MB */ 236 | if (ow_set_size(ole, wbook->biffsize)) { 237 | ow_write_header(ole); 238 | ow_write(ole, wbook->biff->data, wbook->biff->datasize); 239 | 240 | for (i = 0; i < wbook->sheetcount; i++) { 241 | unsigned char *tmp; 242 | size_t size; 243 | 244 | while ((tmp = wsheet_get_data(wbook->sheets[i], &size))) { 245 | ow_write(ole, tmp, size); 246 | free(tmp); 247 | } 248 | } 249 | } 250 | } 251 | 252 | /* Write Excel BIFF5-8 WINDOW1 record. */ 253 | void wbook_store_window1(struct wbookctx *wbook) 254 | { 255 | struct pkt *pkt; 256 | 257 | pkt = pkt_init(20, VARIABLE_PACKET); 258 | 259 | /* Write header */ 260 | pkt_add16_le(pkt, 0x003D); /* Record identifier */ 261 | pkt_add16_le(pkt, 0x0012); /* Number of bytes to follow */ 262 | 263 | /* Write data */ 264 | pkt_add16_le(pkt, 0x0000); /* Horizontal position of window */ 265 | pkt_add16_le(pkt, 0x0069); /* Vertical position of window */ 266 | pkt_add16_le(pkt, 0x339F); /* Width of window */ 267 | pkt_add16_le(pkt, 0x5D1B); /* Height of window */ 268 | pkt_add16_le(pkt, 0x0038); /* Option flags */ 269 | pkt_add16_le(pkt, wbook->activesheet); /* Selected worksheet */ 270 | pkt_add16_le(pkt, wbook->firstsheet); /* 1st displayed worksheet */ 271 | pkt_add16_le(pkt, 0x0001); /* Number of workbook tabs selected */ 272 | pkt_add16_le(pkt, 0x0258); /* Tab to scrollbar ratio */ 273 | 274 | bw_append(wbook->biff, pkt->data, pkt->len); 275 | pkt_free(pkt); 276 | } 277 | 278 | /* Write all FONT records. */ 279 | void wbook_store_all_fonts(struct wbookctx *wbook) 280 | { 281 | int i; 282 | struct pkt *font; 283 | struct htbl *fonts; 284 | int key; 285 | int index; 286 | 287 | font = fmt_get_font(wbook->tmp_format); 288 | for (i = 1; i < 6; i++) { 289 | bw_append(wbook->biff, font->data, font->len); 290 | } 291 | pkt_free(font); 292 | 293 | fonts = hashtbl_new(wbook->formatcount + 1); /* For tmp_format */ 294 | index = 6; /* First user defined FONT */ 295 | 296 | key = fmt_gethash(wbook->tmp_format); 297 | hashtbl_insert(fonts, key, 0); /* Index of the default font */ 298 | 299 | /* User defined fonts */ 300 | for (i = 0; i < wbook->formatcount; i++) { 301 | int data; 302 | key = fmt_gethash(wbook->formats[i]); 303 | data = hashtbl_get(fonts, key); 304 | if (data >= 0) { 305 | /* FONT has already been used */ 306 | wbook->formats[i]->font_index = data; 307 | } else { 308 | /* Add a new FONT record */ 309 | hashtbl_insert(fonts, key, index); 310 | wbook->formats[i]->font_index = index; 311 | index++; 312 | font = fmt_get_font(wbook->formats[i]); 313 | bw_append(wbook->biff, font->data, font->len); 314 | pkt_free(font); 315 | } 316 | } 317 | 318 | hashtbl_destroy(fonts); 319 | } 320 | 321 | /* Store user defined numerical formats ie. FORMAT records */ 322 | void wbook_store_all_num_formats(struct wbookctx *wbook) 323 | { 324 | int index = 164; /* Start from 0xA4 */ 325 | struct htbl *num_formats; 326 | int key; 327 | int i; 328 | 329 | num_formats = hashtbl_new(1); 330 | 331 | /* User defined formats */ 332 | for (i = 0; i < wbook->formatcount; i++) { 333 | int data; 334 | if (wbook->formats[i]->num_format_str == NULL) 335 | continue; 336 | key = fmt_gethash(wbook->formats[i]); 337 | data = hashtbl_get(num_formats, key); 338 | if (data >= 0) { 339 | /* FONT has already been used */ 340 | wbook->formats[i]->num_format = data; 341 | } else { 342 | /* Add a new FONT record */ 343 | hashtbl_insert(num_formats, key, index); 344 | wbook->formats[i]->num_format = index; 345 | wbook_store_num_format(wbook, wbook->formats[i]->num_format_str, index); 346 | index++; 347 | } 348 | } 349 | hashtbl_destroy(num_formats); 350 | } 351 | 352 | /* Write all XF records */ 353 | void wbook_store_all_xfs(struct wbookctx *wbook) 354 | { 355 | int i; 356 | struct pkt *xf; 357 | 358 | xf = fmt_get_xf(wbook->tmp_format, 0xFFF5); /* Style XF */ 359 | for (i = 0; i <= 14; i++) { 360 | bw_append(wbook->biff, xf->data, xf->len); 361 | } 362 | pkt_free(xf); 363 | 364 | xf = fmt_get_xf(wbook->tmp_format, 0x0001); /* Cell XF */ 365 | bw_append(wbook->biff, xf->data, xf->len); 366 | pkt_free(xf); 367 | 368 | /* User defined formats */ 369 | for (i = 0; i < wbook->formatcount; i++) { 370 | xf = fmt_get_xf(wbook->formats[i], 0x0001); 371 | bw_append(wbook->biff, xf->data, xf->len); 372 | pkt_free(xf); 373 | } 374 | } 375 | 376 | /* Write Excel BIFF STYLE record */ 377 | void wbook_store_style(struct wbookctx *wbook) 378 | { 379 | uint16_t name = 0x0093; /* Record identifier */ 380 | uint16_t length = 0x0004; /* Bytes to follow */ 381 | uint16_t ixfe = 0x0000; 382 | 383 | struct pkt *pkt; 384 | 385 | pkt = pkt_init(8, FIXED_PACKET); 386 | 387 | /* Write header */ 388 | pkt_add16_le(pkt, name); 389 | pkt_add16_le(pkt, length); 390 | 391 | /* Write data */ 392 | pkt_add16_le(pkt, ixfe); /* Index to style XF */ 393 | pkt_add8(pkt, 0x00); /* Built-in style */ 394 | pkt_add8(pkt, 0x00); /* Outline style level */ 395 | 396 | bw_append(wbook->biff, pkt->data, pkt->len); 397 | pkt_free(pkt); 398 | 399 | } 400 | 401 | /* Write all STYLE records. */ 402 | void wbook_store_all_styles(struct wbookctx *wbook) 403 | { 404 | wbook_store_style(wbook); 405 | } 406 | 407 | /* Writes Excel BIFF BOUNDSHEET record */ 408 | void wbook_store_boundsheet(struct wbookctx *wbook, char *sname, int offset) 409 | { 410 | uint16_t name = 0x0085; /* Record identifier */ 411 | uint16_t length; 412 | uint16_t grbit = 0x0000; 413 | int cch; 414 | struct pkt *pkt; 415 | 416 | length = 0x07 + strlen(sname); /* Number of bytes to follow */ 417 | cch = strlen(sname); 418 | 419 | pkt = pkt_init(0, VARIABLE_PACKET); 420 | 421 | /* Write header */ 422 | pkt_add16_le(pkt, name); 423 | pkt_add16_le(pkt, length); 424 | 425 | /* Write data */ 426 | pkt_add32_le(pkt, offset); /* Location of worksheet BOF */ 427 | pkt_add16_le(pkt, grbit); /* Sheet identifier */ 428 | pkt_add8(pkt, cch); /* Length of sheet name */ 429 | pkt_addraw(pkt, (unsigned char *)sname, cch); 430 | 431 | bw_append(wbook->biff, pkt->data, pkt->len); 432 | pkt_free(pkt); 433 | 434 | } 435 | 436 | /* Writes Excel FORMAT record for non "built-in" numerical formats. */ 437 | static void wbook_store_num_format(struct wbookctx *wbook, char *format, int index) 438 | { 439 | struct pkt *pkt; 440 | size_t cch; 441 | 442 | cch = strlen(format); 443 | pkt = pkt_init(0, VARIABLE_PACKET); 444 | 445 | /* Write header */ 446 | pkt_add16_le(pkt, 0x041E); /* Record identifier */ 447 | pkt_add16_le(pkt, 0x0003 + cch); 448 | 449 | /* Write data */ 450 | pkt_add16_le(pkt, index); 451 | pkt_add8(pkt, cch); 452 | pkt_addraw(pkt, (unsigned char *)format, cch); 453 | 454 | bw_append(wbook->biff, pkt->data, pkt->len); 455 | 456 | pkt_free(pkt); 457 | } 458 | 459 | /* Write Excel 1904 record to indicate the date system in use. */ 460 | static void wbook_store_1904(struct wbookctx *wbook) 461 | { 462 | struct pkt *pkt; 463 | 464 | pkt = pkt_init(6, FIXED_PACKET); 465 | 466 | /* Write header */ 467 | pkt_add16_le(pkt, 0x0022); /* Record identifier */ 468 | pkt_add16_le(pkt, 0x0002); 469 | 470 | /* Write data */ 471 | pkt_add16_le(pkt, wbook->epoch1904); /* Flag for 1904 date system */ 472 | 473 | bw_append(wbook->biff, pkt->data, pkt->len); 474 | pkt_free(pkt); 475 | } 476 | 477 | /* Stores the CODEPAGE biff record */ 478 | static void wbook_store_codepage(struct wbookctx *wbook) 479 | { 480 | struct pkt *pkt; 481 | 482 | pkt = pkt_init(6, FIXED_PACKET); 483 | 484 | /* Write header */ 485 | pkt_add16_le(pkt, 0x0042); /* Record identifier */ 486 | pkt_add16_le(pkt, 0x0002); 487 | 488 | /* Write data */ 489 | pkt_add16_le(pkt, wbook->codepage); 490 | 491 | bw_append(wbook->biff, pkt->data, pkt->len); 492 | pkt_free(pkt); 493 | } 494 | -------------------------------------------------------------------------------- /src/worksheet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * Based on early versions of Spreadsheet::WriteExcel 4 | * Copyright (c) 2000-2001 John McNamara 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "formula.h" 24 | #include "worksheet.h" 25 | #include "stream.h" 26 | 27 | #define XLS_ROWMAX 65536 28 | #define XLS_COLMAX 256 29 | #define XLS_STRMAX 255 30 | 31 | int xls_init(struct wsheetctx *xls, char *name, int index, int activesheet, int firstsheet, struct xl_format *url, int store_in_memory); 32 | void wsheet_store_dimensions(struct wsheetctx *xls); 33 | void wsheet_store_window2(struct wsheetctx *xls); 34 | void wsheet_store_selection(struct wsheetctx *xls, int frow, int fcol, int lrow, int lcol); 35 | void wsheet_store_colinfo(struct wsheetctx *wsheet, struct col_info *ci); 36 | void wsheet_store_defcol(struct wsheetctx *wsheet); 37 | void wsheet_append(void *xlsctx, void *data, size_t sz); 38 | 39 | extern int bw_init(struct bwctx *bw); 40 | 41 | #ifdef WIN32 42 | #include 43 | #include 44 | #define tmpfile() _xls_win32_tmpfile() 45 | 46 | FILE *_xls_win32_tmpfile(void) 47 | { 48 | char path_name[MAX_PATH + 1]; 49 | char file_name[MAX_PATH + 1]; 50 | DWORD path_len; 51 | HANDLE handle; 52 | int fd; 53 | FILE *fp; 54 | 55 | 56 | path_len = GetTempPath(MAX_PATH, path_name); 57 | if (path_len <= 0 || path_len >= MAX_PATH) 58 | return NULL; 59 | 60 | if (GetTempFileName(path_name, "xl_", 0, file_name) == 0) 61 | return NULL; 62 | 63 | handle = CreateFile(file_name, GENERIC_READ | GENERIC_WRITE, 64 | 0, NULL, CREATE_ALWAYS, 65 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 66 | NULL); 67 | 68 | if (handle == INVALID_HANDLE_VALUE) { 69 | DeleteFile(file_name); 70 | return NULL; 71 | } 72 | 73 | fd = _open_osfhandle((intptr_t)handle, 0); 74 | if (fd < 0) { 75 | CloseHandle(handle); 76 | return NULL; 77 | } 78 | 79 | fp = fdopen(fd, "w+b"); 80 | if (fp == NULL) { 81 | _close(fd); 82 | return NULL; 83 | } 84 | 85 | return fp; 86 | } 87 | #endif 88 | 89 | struct wsheetctx * wsheet_new(char *name, int index, int activesheet, int firstsheet, struct xl_format *url, int store_in_memory) 90 | { 91 | struct wsheetctx *xls; 92 | 93 | xls = malloc(sizeof(struct wsheetctx)); 94 | bw_init((struct bwctx *)xls); 95 | ((struct bwctx *)xls)->append = wsheet_append; 96 | TAILQ_INIT(&xls->colinfos); 97 | 98 | if (xls_init(xls, name, index, activesheet, firstsheet, url, 99 | store_in_memory) == -1) { 100 | free(xls); 101 | return NULL; 102 | } 103 | 104 | return xls; 105 | } 106 | 107 | void wsheet_destroy(struct wsheetctx *xls) 108 | { 109 | struct col_info *ci; 110 | /* Free the entire tail queue of colinfo records. */ 111 | while ((ci = TAILQ_FIRST(&xls->colinfos))) { 112 | TAILQ_REMOVE(&xls->colinfos, ci, cis); 113 | free(ci); 114 | } 115 | 116 | /* Free up anything else that was allocated */ 117 | free(xls->name); 118 | if (xls->fp) { 119 | fclose(xls->fp); 120 | } 121 | free(((struct bwctx *)xls)->data); 122 | free(xls); 123 | } 124 | 125 | int xls_init(struct wsheetctx *xls, char *name, int index, int activesheet, 126 | int firstsheet, struct xl_format *url, int store_in_memory) 127 | { 128 | int rowmax = 65536; 129 | int colmax = 256; 130 | int strmax = 255; 131 | 132 | xls->name = strdup(name); 133 | xls->index = index; 134 | xls->activesheet = activesheet; 135 | xls->firstsheet = firstsheet; 136 | xls->url_format = url; 137 | xls->using_tmpfile = 1; 138 | 139 | xls->fp = NULL; 140 | xls->fileclosed = 0; 141 | xls->offset = 0; 142 | xls->xls_rowmax = rowmax; 143 | xls->xls_colmax = colmax; 144 | xls->xls_strmax = strmax; 145 | xls->dim_rowmin = rowmax + 1; 146 | xls->dim_rowmax = 0; 147 | xls->dim_colmin = rowmax + 1; 148 | xls->dim_colmax = 0; 149 | xls->sel_frow = 0; 150 | xls->sel_fcol = 0; 151 | xls->sel_lrow = 0; 152 | xls->sel_lcol = 0; 153 | 154 | if (xls->using_tmpfile == 1) { 155 | xls->fp = tmpfile(); 156 | if (xls->fp == NULL) 157 | xls->using_tmpfile = 0; 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | void wsheet_close(struct wsheetctx *xls) 164 | { 165 | /* Prepend in reverse order !! */ 166 | wsheet_store_dimensions(xls); 167 | 168 | /* Prepend the COLINFO records if they exist */ 169 | if (!TAILQ_EMPTY(&xls->colinfos)) { 170 | struct col_info *ci; 171 | TAILQ_FOREACH(ci, &xls->colinfos, cis) { 172 | wsheet_store_colinfo(xls, ci); 173 | } 174 | wsheet_store_defcol(xls); 175 | } 176 | 177 | /* Prepend in reverse order!! */ 178 | bw_store_bof((struct bwctx *)xls, 0x0010); 179 | 180 | /* Append */ 181 | wsheet_store_window2(xls); 182 | wsheet_store_selection(xls, xls->sel_frow, xls->sel_fcol, xls->sel_lrow, xls->sel_lcol); 183 | bw_store_eof((struct bwctx *)xls); 184 | } 185 | 186 | void wsheet_set_selection(struct wsheetctx *xls, int frow, int fcol, int lrow, int lcol) 187 | { 188 | xls->sel_frow = frow; 189 | xls->sel_fcol = fcol; 190 | xls->sel_lrow = lrow; 191 | xls->sel_lcol = lcol; 192 | } 193 | 194 | /**************************************************************************** 195 | * Writes Excel DIMENSIONS to define the area in which there is data. 196 | */ 197 | void wsheet_store_dimensions(struct wsheetctx *xls) 198 | { 199 | uint16_t name = 0x0000; /* Record identifier */ 200 | uint16_t length = 0x000A; /* Number of bytes to follow */ 201 | uint16_t reserved = 0x0000; /* Reserved by Excel */ 202 | struct pkt *pkt; 203 | 204 | pkt = pkt_init(14, FIXED_PACKET); 205 | 206 | /* Write header */ 207 | pkt_add16_le(pkt, name); 208 | pkt_add16_le(pkt, length); 209 | 210 | /* Write data */ 211 | pkt_add16_le(pkt, xls->dim_rowmin); 212 | pkt_add16_le(pkt, xls->dim_rowmax); 213 | pkt_add16_le(pkt, xls->dim_colmin); 214 | pkt_add16_le(pkt, xls->dim_colmax); 215 | pkt_add16_le(pkt, reserved); 216 | bw_prepend((struct bwctx *)xls, pkt->data, pkt->len); 217 | pkt_free(pkt); 218 | } 219 | 220 | /**************************************************************************** 221 | * void wsheet_store_window2(struct xlsctx *xls) 222 | * 223 | * Write BIFF record WinDow2 */ 224 | void wsheet_store_window2(struct wsheetctx *xls) 225 | { 226 | uint16_t name = 0x023E; /* Record identifier */ 227 | uint16_t length = 0x000A; /* Number of bytes to follow */ 228 | 229 | uint16_t grbit = 0x00B6; /* Option flags */ 230 | uint16_t rwTop = 0x0000; /* Top row visible in window */ 231 | uint16_t colLeft = 0x0000; /* Leftmost column visible in window */ 232 | uint32_t rgbHdr = 0x00000000; /* Row/column heading and gridline color */ 233 | struct pkt *pkt; 234 | 235 | pkt = pkt_init(14, FIXED_PACKET); 236 | 237 | if (xls->activesheet == xls->index) { 238 | grbit = 0x06B6; 239 | } 240 | 241 | /* Write header */ 242 | pkt_add16_le(pkt, name); 243 | pkt_add16_le(pkt, length); 244 | 245 | /* Write data */ 246 | pkt_add16_le(pkt, grbit); 247 | pkt_add16_le(pkt, rwTop); 248 | pkt_add16_le(pkt, colLeft); 249 | pkt_add32_le(pkt, rgbHdr); 250 | wsheet_append(xls, pkt->data, pkt->len); 251 | pkt_free(pkt); 252 | } 253 | 254 | /* Retrieves data from memory in one chunk, or from disk in 4096 255 | * sized chunks. */ 256 | unsigned char *wsheet_get_data(struct wsheetctx *ws, size_t *sz) 257 | { 258 | unsigned char *tmp; 259 | struct bwctx *biff = (struct bwctx *)ws; 260 | 261 | /* Return data stored in memory */ 262 | if (biff->data) { 263 | tmp = malloc(biff->_sz); 264 | memcpy(tmp, biff->data, biff->_sz); 265 | *sz = biff->_sz; 266 | free(biff->data); 267 | biff->data = NULL; 268 | if (ws->using_tmpfile == 1) { 269 | fseek(ws->fp, 0, SEEK_SET); 270 | } 271 | return tmp; 272 | } 273 | 274 | if (ws->using_tmpfile == 1) { 275 | size_t bytes_read; 276 | tmp = malloc(4096); 277 | bytes_read = fread(tmp, 1, 4096, ws->fp); 278 | *sz = bytes_read; 279 | if (bytes_read <= 0) { 280 | free(tmp); 281 | return NULL; 282 | } 283 | return tmp; 284 | } 285 | 286 | return NULL; 287 | } 288 | 289 | int wsheet_xf(struct xl_format *fmt) 290 | { 291 | if (fmt) 292 | return fmt->xf_index; 293 | 294 | return 0x0F; 295 | } 296 | 297 | void wsheet_append(void *xlsctx, void *data, size_t sz) 298 | { 299 | struct wsheetctx *xls = (struct wsheetctx *)xlsctx; 300 | 301 | if (!xls->using_tmpfile) { 302 | bw_append((struct bwctx *)xls, data, sz); 303 | } else { 304 | fwrite(data, sz, 1, xls->fp); 305 | /* TODO determine if below line is really needed */ 306 | ((struct bwctx *)xls)->datasize += sz; 307 | } 308 | } 309 | 310 | /* Write a double to the specified row and column (zero indexed). 311 | * An integer can be written as a double. Excel will display an integer. 312 | * This writes the Excel NUMBER record to the worksheet. (BIFF3-BIFF8) */ 313 | int xls_writef_number(struct wsheetctx *xls, int row, int col, double num, struct xl_format *fmt) 314 | { 315 | uint16_t name = 0x0203; /* Record identifier */ 316 | uint16_t length = 0x000E; /* Number of bytes to follow */ 317 | uint16_t xf; /* The cell format */ 318 | unsigned char xl_double[8]; 319 | struct pkt *pkt; 320 | struct bwctx *biff = (struct bwctx *)xls; 321 | 322 | if (row >= xls->xls_rowmax) { return -2; } 323 | if (col >= xls->xls_colmax) { return -2; } 324 | if (row < xls->dim_rowmin) { xls->dim_rowmin = row; } 325 | if (row > xls->dim_rowmax) { xls->dim_rowmax = row; } 326 | if (col < xls->dim_colmin) { xls->dim_colmin = col; } 327 | if (col > xls->dim_colmax) { xls->dim_colmax = col; } 328 | 329 | xf = wsheet_xf(fmt); 330 | 331 | pkt = pkt_init(0, VARIABLE_PACKET); 332 | /* Write header */ 333 | pkt_add16_le(pkt, name); 334 | pkt_add16_le(pkt, length); 335 | 336 | /* Write data */ 337 | pkt_add16_le(pkt, row); 338 | pkt_add16_le(pkt, col); 339 | pkt_add16_le(pkt, xf); 340 | 341 | /* Write the number */ 342 | memcpy(xl_double, &num, sizeof(xl_double)); 343 | if (biff->byte_order) 344 | reverse(xl_double, sizeof(xl_double)); 345 | 346 | pkt_addraw(pkt, xl_double, sizeof(xl_double)); 347 | biff->append(biff, pkt->data, pkt->len); 348 | pkt_free(pkt); 349 | 350 | return 0; 351 | } 352 | 353 | /* Write a double to the specified row and column (zero indexed). 354 | * An integer can be written as a double. Excel will display an integer. 355 | * This writes the Excel NUMBER record to the worksheet. (BIFF3-BIFF8) */ 356 | int wsheet_writef_formula(struct wsheetctx *xls, int row, int col, char *formula, struct xl_format *fmt) 357 | { 358 | uint16_t name = 0x0006; /* Record identifier */ 359 | uint16_t length = 0x0016; /* Number of bytes to follow */ 360 | uint16_t xf; /* The cell format */ 361 | struct pkt *pkt; 362 | struct pkt *formpkt; 363 | struct bwctx *biff = (struct bwctx *)xls; 364 | int formlen; 365 | double zero = 0; 366 | unsigned char xl_double[8]; 367 | 368 | if (row >= xls->xls_rowmax) { return -2; } 369 | if (col >= xls->xls_colmax) { return -2; } 370 | if (row < xls->dim_rowmin) { xls->dim_rowmin = row; } 371 | if (row > xls->dim_rowmax) { xls->dim_rowmax = row; } 372 | if (col < xls->dim_colmin) { xls->dim_colmin = col; } 373 | if (col > xls->dim_colmax) { xls->dim_colmax = col; } 374 | 375 | xf = wsheet_xf(fmt); 376 | 377 | formpkt = pkt_init(0, VARIABLE_PACKET); 378 | process_formula(formula, formpkt); 379 | formlen = formpkt->len; 380 | 381 | pkt = pkt_init(0, VARIABLE_PACKET); 382 | /* Write header */ 383 | pkt_add16_le(pkt, name); 384 | pkt_add16_le(pkt, length + formlen); 385 | 386 | /* Write data */ 387 | pkt_add16_le(pkt, row); 388 | pkt_add16_le(pkt, col); 389 | pkt_add16_le(pkt, xf); 390 | 391 | /* Write the number */ 392 | memcpy(xl_double, &zero, sizeof(xl_double)); 393 | if (biff->byte_order) 394 | reverse(xl_double, sizeof(xl_double)); 395 | 396 | pkt_addraw(pkt, xl_double, sizeof(xl_double)); 397 | pkt_add16_le(pkt, 0x03); /* Option flags */ 398 | pkt_add32_le(pkt, 0); /* Reserved */ 399 | pkt_add16_le(pkt, formlen); 400 | 401 | /* The formula */ 402 | pkt_addraw(pkt, formpkt->data, formpkt->len); 403 | 404 | biff->append(biff, pkt->data, pkt->len); 405 | pkt_free(pkt); 406 | pkt_free(formpkt); 407 | 408 | return 0; 409 | } 410 | 411 | /* Write a string to the specified row and column (zero indexed). 412 | * NOTE: There is an Excel 5 defined limit of 255 characters. 413 | * This writes the Excel LABEL record (BIFF3-BIFF5) */ 414 | int xls_writef_string(struct wsheetctx *xls, int row, int col, char *str, struct xl_format *fmt) 415 | { 416 | uint16_t name = 0x0204; /* Record identifier */ 417 | uint16_t length = 0x0008; /* Number of bytes to follow */ 418 | uint16_t xf; /* The cell format */ 419 | int len; 420 | struct pkt *pkt; 421 | 422 | len = strlen(str); 423 | 424 | /* LABEL must be < 255 chars */ 425 | if (len > xls->xls_strmax) len = xls->xls_strmax; 426 | 427 | length += len; 428 | 429 | if (row >= xls->xls_rowmax) { return -2; } 430 | if (col >= xls->xls_colmax) { return -2; } 431 | if (row < xls->dim_rowmin) { xls->dim_rowmin = row; } 432 | if (row > xls->dim_rowmax) { xls->dim_rowmax = row; } 433 | if (col < xls->dim_colmin) { xls->dim_colmin = col; } 434 | if (col > xls->dim_colmax) { xls->dim_colmax = col; } 435 | 436 | xf = wsheet_xf(fmt); 437 | 438 | pkt = pkt_init(0, VARIABLE_PACKET); 439 | 440 | /* Write header */ 441 | pkt_add16_le(pkt, name); 442 | pkt_add16_le(pkt, length); 443 | 444 | /* Write data */ 445 | pkt_add16_le(pkt, row); 446 | pkt_add16_le(pkt, col); 447 | pkt_add16_le(pkt, xf); 448 | pkt_add16_le(pkt, len); 449 | 450 | pkt_addraw(pkt, (unsigned char *)str, len); 451 | wsheet_append(xls, pkt->data, pkt->len); 452 | pkt_free(pkt); 453 | return 0; 454 | } 455 | 456 | /* Write Worksheet BLANK record (BIFF3-8) */ 457 | int xls_write_blank(struct wsheetctx *xls, int row, int col, struct xl_format *fmt) 458 | { 459 | uint16_t name = 0x0201; /* Record identifier */ 460 | uint16_t length = 0x0006; /* Number of bytes to follow */ 461 | uint16_t xf; /* The cell format */ 462 | struct pkt *pkt; 463 | 464 | if (row >= xls->xls_rowmax) { return -2; } 465 | if (col >= xls->xls_colmax) { return -2; } 466 | if (row < xls->dim_rowmin) { xls->dim_rowmin = row; } 467 | if (row > xls->dim_rowmax) { xls->dim_rowmax = row; } 468 | if (col < xls->dim_colmin) { xls->dim_colmin = col; } 469 | if (col > xls->dim_colmax) { xls->dim_colmax = col; } 470 | 471 | xf = wsheet_xf(fmt); 472 | 473 | pkt = pkt_init(10, FIXED_PACKET); 474 | 475 | /* Write header */ 476 | pkt_add16_le(pkt, name); 477 | pkt_add16_le(pkt, length); 478 | 479 | /* Write data */ 480 | pkt_add16_le(pkt, row); 481 | pkt_add16_le(pkt, col); 482 | pkt_add16_le(pkt, xf); 483 | 484 | wsheet_append(xls, pkt->data, pkt->len); 485 | pkt_free(pkt); 486 | return 0; 487 | } 488 | 489 | int xls_write_string(struct wsheetctx *xls, int row, int col, char *str) 490 | { 491 | return xls_writef_string(xls, row, col, str, NULL); 492 | } 493 | 494 | int xls_write_number(struct wsheetctx *xls, int row, int col, double num) 495 | { 496 | return xls_writef_number(xls, row, col, num, NULL); 497 | } 498 | 499 | void wsheet_set_column(struct wsheetctx *ws, int fcol, int lcol, int width) 500 | { 501 | struct col_info *ci; 502 | 503 | /* First look and see if something like this already exists */ 504 | TAILQ_FOREACH(ci, &ws->colinfos, cis) { 505 | if (ci->first_col == fcol && ci->last_col == lcol) { 506 | /* Found a match, just update the width */ 507 | ci->col_width = width; 508 | return; 509 | } 510 | } 511 | 512 | ci = malloc(sizeof(struct col_info)); 513 | ci->first_col = fcol; 514 | ci->last_col = lcol; 515 | ci->col_width = width; 516 | ci->xf = 0xF; 517 | ci->grbit = 0; 518 | 519 | TAILQ_INSERT_TAIL(&ws->colinfos, ci, cis); 520 | } 521 | 522 | void wsheet_store_selection(struct wsheetctx *xls, int frow, int fcol, int lrow, int lcol) 523 | { 524 | struct pkt *pkt; 525 | int tmp; 526 | 527 | pkt = pkt_init(0, VARIABLE_PACKET); 528 | 529 | /* Swap rows and columns around */ 530 | if (frow > lrow) { 531 | tmp = frow; 532 | frow = lrow; 533 | lrow = tmp; 534 | } 535 | 536 | if (fcol > lcol) { 537 | tmp = fcol; 538 | fcol = lcol; 539 | lcol = fcol; 540 | } 541 | 542 | /* Write header */ 543 | pkt_add16_le(pkt, 0x001D); /* Record identifier */ 544 | pkt_add16_le(pkt, 0x000F); /* Number of bytes to follow */ 545 | 546 | pkt_add8(pkt, 3); /* Pane position */ 547 | pkt_add16_le(pkt, frow); /* Active row */ 548 | pkt_add16_le(pkt, fcol); /* Active column */ 549 | pkt_add16_le(pkt, 0); /* Active cell ref */ 550 | pkt_add16_le(pkt, 1); /* Number of refs */ 551 | pkt_add16_le(pkt, frow); /* First row in reference */ 552 | pkt_add16_le(pkt, lrow); /* Last row in reference */ 553 | pkt_add8(pkt, fcol); /* First col in reference */ 554 | pkt_add8(pkt, lcol); /* Last col in reference */ 555 | 556 | wsheet_append(xls, pkt->data, pkt->len); 557 | pkt_free(pkt); 558 | } 559 | 560 | /* Write BIFF record DEFCOLWIDTH if COLINFO records are in use. */ 561 | void wsheet_store_defcol(struct wsheetctx *wsheet) 562 | { 563 | struct pkt *pkt; 564 | 565 | pkt = pkt_init(6, FIXED_PACKET); 566 | 567 | /* Write header */ 568 | pkt_add16_le(pkt, 0x0055); /* Record identifier */ 569 | pkt_add16_le(pkt, 0x0002); /* Number of bytes to follow */ 570 | 571 | /* Write data */ 572 | pkt_add16_le(pkt, 0x0008); /* Default column width */ 573 | 574 | bw_prepend((struct bwctx *)wsheet, pkt->data, pkt->len); 575 | pkt_free(pkt); 576 | } 577 | 578 | /* Write BIFF record COLINFO to define column widths 579 | * 580 | * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C 581 | * length record */ 582 | void wsheet_store_colinfo(struct wsheetctx *wsheet, struct col_info *ci) 583 | { 584 | struct pkt *pkt; 585 | float tmp; 586 | 587 | pkt = pkt_init(0, VARIABLE_PACKET); 588 | 589 | tmp = (float)ci->col_width + 0.72; /* Fudge. Excel subtracts 0.72 !? */ 590 | tmp *= 256; /* Convert to units of 1/256 of a char */ 591 | 592 | /* Write header */ 593 | pkt_add16_le(pkt, 0x007D); /* Record identifier */ 594 | pkt_add16_le(pkt, 0x000B); /* Number of bytes to follow */ 595 | 596 | /* Write data */ 597 | pkt_add16_le(pkt, ci->first_col); /* First formatted column */ 598 | pkt_add16_le(pkt, ci->last_col); /* Last formatted column */ 599 | pkt_add16_le(pkt, (int)tmp); /* Column width */ 600 | pkt_add16_le(pkt, ci->xf); /* XF */ 601 | pkt_add16_le(pkt, ci->grbit); /* Option flags */ 602 | pkt_add8(pkt, 0x00); /* Reserved */ 603 | 604 | bw_prepend((struct bwctx *)wsheet, pkt->data, pkt->len); 605 | pkt_free(pkt); 606 | } 607 | 608 | /* write_url 609 | * 610 | * Write a hyperlink. This is comprised of two elements: this visible label 611 | * and the invisible link. The visible label is the same as the link unless an 612 | * alternative string is specified. The label is written using the 613 | * write_string function. Therefore the 255 character string limit applies. 614 | */ 615 | int wsheet_write_url(struct wsheetctx *wsheet, int row, int col, char *url, char *string, struct xl_format *fmt) 616 | { 617 | struct pkt *pkt; 618 | int length; 619 | char *str; 620 | unsigned char unknown[40] = 621 | { 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 622 | 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B, 0x02, 0x00, 0x00, 0x00, 623 | 0x03, 0x00, 0x00, 0x00, 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 624 | 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B 625 | }; 626 | 627 | str = string; 628 | if (str == NULL) 629 | str = url; 630 | 631 | xls_writef_string(wsheet, row, col, str, fmt); 632 | 633 | length = 0x0034 + 2 * (1 + strlen(url)); 634 | pkt = pkt_init(0, VARIABLE_PACKET); 635 | 636 | /* Write header */ 637 | pkt_add16_le(pkt, 0x01B8); /* Record identifier */ 638 | pkt_add16_le(pkt, length); /* Number of bytes to follow */ 639 | 640 | pkt_add16_le(pkt, row); /* Row number */ 641 | pkt_add16_le(pkt, row); /* Row number */ 642 | pkt_add16_le(pkt, col); /* Column number */ 643 | pkt_add16_le(pkt, col); /* Column number */ 644 | pkt_addraw(pkt, unknown, sizeof(unknown)); 645 | pkt_add32_le(pkt, strlen(url)); 646 | 647 | pkt_addraw(pkt, (unsigned char *)url, strlen(url)); 648 | wsheet_append(wsheet, pkt->data, pkt->len); 649 | pkt_free(pkt); 650 | 651 | return 0; 652 | } 653 | 654 | /* This method is used to set the height and XF format for a row. 655 | * Writes the BIFF record ROW. */ 656 | void wsheet_set_row(struct wsheetctx *wsheet, int row, int height, struct xl_format *fmt) 657 | { 658 | struct pkt *pkt; 659 | int rowHeight; 660 | uint16_t xf; /* The cell format */ 661 | 662 | rowHeight = height; 663 | /* Use -1 to set a format without setting height */ 664 | if (rowHeight < 0) 665 | rowHeight = 0xff; 666 | else rowHeight *= 20; 667 | 668 | xf = wsheet_xf(fmt); 669 | 670 | pkt = pkt_init(0, VARIABLE_PACKET); 671 | 672 | /* Write header */ 673 | pkt_add16_le(pkt, 0x0208); /* Record identifier */ 674 | pkt_add16_le(pkt, 0x0010); /* Number of bytes to follow */ 675 | 676 | /* Write payload */ 677 | pkt_add16_le(pkt, row); /* Row number */ 678 | pkt_add16_le(pkt, 0x0000); /* First defined column */ 679 | pkt_add16_le(pkt, 0x0000); /* Last defined column */ 680 | pkt_add16_le(pkt, rowHeight); /* Row height */ 681 | pkt_add16_le(pkt, 0x0000); /* Used by Excel to optimise loading */ 682 | pkt_add16_le(pkt, 0x0000); /* Reserved */ 683 | pkt_add16_le(pkt, 0x01C0); /* Option flags. */ 684 | pkt_add16_le(pkt, xf); /* XF index */ 685 | 686 | wsheet_append(wsheet, pkt->data, pkt->len); 687 | pkt_free(pkt); 688 | } 689 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_EXECUTABLE(example1 example1.c) 2 | TARGET_LINK_LIBRARIES(example1 excel) 3 | 4 | ADD_EXECUTABLE(example2 example2.c) 5 | TARGET_LINK_LIBRARIES(example2 excel) 6 | 7 | ADD_EXECUTABLE(merge1 merge1.c) 8 | TARGET_LINK_LIBRARIES(merge1 excel) 9 | 10 | ADD_EXECUTABLE(example3 example3.c) 11 | TARGET_LINK_LIBRARIES(example3 excel) 12 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for libexcel. 2 | 3 | .PHONY: all clean 4 | 5 | SRCS1 = example1.c 6 | OBJS1 = $(SRCS1:.c=.o) 7 | 8 | SRCS2 = example2.c 9 | OBJS2 = $(SRCS2:.c=.o) 10 | 11 | SRCS3 = merge1.c 12 | OBJS3 = $(SRCS3:.c=.o) 13 | 14 | SRCS4 = example3.c 15 | OBJS4 = $(SRCS4:.c=.o) 16 | 17 | CC = gcc 18 | AR = ar 19 | 20 | ifeq ($(OS),Windows_NT) 21 | RM = del /Q /F 22 | else 23 | RM = rm -f 24 | endif 25 | 26 | INTERNAL_CFLAGS = -Wall -I../include 27 | CPPFLAGS += -MMD -MP -MT $@ 28 | CFLAGS= -O2 -pipe 29 | 30 | EXE1 = example1 31 | EXE2 = example2 32 | EXE3 = merge1 33 | EXE4 = example3 34 | 35 | EXES = $(EXE1) $(EXE2) $(EXE3) $(EXE4) 36 | 37 | all: $(EXES) 38 | 39 | debug: CPPFLAGS = 40 | debug: CFLAGS = -O0 -g 41 | debug: $(EXES) 42 | 43 | $(EXE1): $(OBJS1) ../src/libexcel.a 44 | $(CC) $(CFLAGS) -o $(EXE1) $(OBJS1) ../src/libexcel.a 45 | 46 | $(EXE2): $(OBJS2) ../src/libexcel.a 47 | $(CC) $(CFLAGS) -o $(EXE2) $(OBJS2) ../src/libexcel.a 48 | 49 | $(EXE3): $(OBJS3) ../src/libexcel.a 50 | $(CC) $(CFLAGS) -o $(EXE3) $(OBJS3) ../src/libexcel.a 51 | 52 | $(EXE4): $(OBJS4) ../src/libexcel.a 53 | $(CC) $(CFLAGS) -o $(EXE4) $(OBJS4) ../src/libexcel.a 54 | 55 | clean: 56 | $(RM) *.o $(EXES) 57 | $(RM) *.d 58 | 59 | .c.o: 60 | $(CC) $(INTERNAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 61 | 62 | # Include automatically generated dependency files 63 | -include $(wildcard *.d) 64 | -------------------------------------------------------------------------------- /tests/Makefile.mingw: -------------------------------------------------------------------------------- 1 | # Makefile for libexcel (mingw32) 2 | 3 | .PHONY: all clean 4 | 5 | SRCS1 = example1.c 6 | OBJS1 = $(SRCS1:.c=.o) 7 | 8 | SRCS2 = example2.c 9 | OBJS2 = $(SRCS2:.c=.o) 10 | 11 | SRCS3 = merge1.c 12 | OBJS3 = $(SRCS3:.c=.o) 13 | 14 | SRCS4 = example3.c 15 | OBJS4 = $(SRCS4:.c=.o) 16 | 17 | CC = gcc 18 | AR = ar 19 | 20 | INTERNAL_CFLAGS = -Wall -I../include 21 | CPPFLAGS += -MMD -MP -MT $@ 22 | CFLAGS= -O2 -pipe 23 | 24 | EXE1 = example1.exe 25 | EXE2 = example2.exe 26 | EXE3 = merge1.exe 27 | EXE4 = example3.exe 28 | 29 | EXES = $(EXE1) $(EXE2) $(EXE3) $(EXE4) 30 | 31 | all: $(EXES) 32 | 33 | $(EXE1): $(OBJS1) ../src/libexcel.a 34 | $(CC) -O2 -o $(EXE1) $(OBJS1) ../src/libexcel.a 35 | 36 | $(EXE2): $(OBJS2) ../src/libexcel.a 37 | $(CC) -O2 -o $(EXE2) $(OBJS2) ../src/libexcel.a 38 | 39 | $(EXE3): $(OBJS3) ../src/libexcel.a 40 | $(CC) -O2 -o $(EXE3) $(OBJS3) ../src/libexcel.a 41 | 42 | $(EXE4): $(OBJS4) ../src/libexcel.a 43 | $(CC) -O2 -o $(EXE4) $(OBJS4) ../src/libexcel.a 44 | 45 | clean: 46 | del *.o $(EXES) 47 | del *.d 48 | 49 | .c.o: 50 | $(CC) $(INTERNAL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 51 | 52 | # Include automatically generated dependency files 53 | -include $(wildcard *.d) 54 | -------------------------------------------------------------------------------- /tests/example1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "excel.h" 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | struct wbookctx *wbook; 26 | struct wsheetctx *one, *two; 27 | struct xl_format *fmt; 28 | 29 | /* Create a new Excel Workbook */ 30 | wbook = wbook_new("example1.xls", 0); 31 | one = wbook_addworksheet(wbook, "North"); 32 | 33 | fmt = wbook_addformat(wbook); 34 | fmt_set_bold(fmt, 1); 35 | fmt_set_color(fmt, "blue"); 36 | 37 | xls_writef_string(one, 1, 0, "Hello, Excel!", fmt); 38 | xls_write_number(one, 1, 1, 2.0); 39 | xls_write_number(one, 0, 0, 3.14); 40 | wsheet_set_column(one, 0, 0, 20); 41 | 42 | two = wbook_addworksheet(wbook, "South"); 43 | xls_write_number(two, 0, 0, 3.3333); 44 | //wbook_addworksheet(wbook, "East"); 45 | //wbook_addworksheet(wbook, "West"); 46 | wbook_close(wbook); 47 | wbook_destroy(wbook); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /tests/example2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "excel.h" 22 | 23 | struct wbookctx *gwbook; 24 | struct xl_format *gheading, *gcenter; 25 | 26 | void intro(void) 27 | { 28 | struct wsheetctx *one; 29 | struct xl_format *fmt; 30 | 31 | /* Create a new Excel Workbook */ 32 | one = wbook_addworksheet(gwbook, "Introduction"); 33 | wsheet_set_column(one, 0, 0, 60); 34 | 35 | fmt = wbook_addformat(gwbook); 36 | fmt_set_bold(fmt, 1); 37 | fmt_set_color(fmt, "blue"); 38 | fmt_set_align(fmt, "center"); 39 | 40 | xls_writef_string(one, 2, 0, "This workbook demonstrates some of", fmt); 41 | xls_writef_string(one, 3, 0, "the formatting options provided by", fmt); 42 | xls_writef_string(one, 4, 0, "the libexcel library.", fmt); 43 | } 44 | 45 | struct fsfv { 46 | int size; 47 | char *name; 48 | }; 49 | 50 | void fonts(void) 51 | { 52 | struct wsheetctx *sheet; 53 | struct fsfv fonts[] = { 54 | {10, "Arial"}, 55 | {12, "Arial"}, 56 | {14, "Arial"}, 57 | {12, "Arial Black"}, 58 | {12, "Arial Narrow"}, 59 | {12, "Century Schoolbook"}, 60 | {12, "Courier"}, 61 | {12, "Courier New"}, 62 | {12, "Garamond"}, 63 | {12, "Impact"}, 64 | {12, "Lucida Handwriting"}, 65 | {12, "Times New Roman"}, 66 | {12, "Symbol"}, 67 | {12, "Wingdings"}, 68 | {12, "Calibri"}, 69 | {12, "A font that does not exist"} 70 | }; 71 | int i; 72 | int nfs; 73 | 74 | sheet = wbook_addworksheet(gwbook, "Fonts"); 75 | wsheet_set_column(sheet, 0, 0, 30); 76 | wsheet_set_column(sheet, 1, 1, 10); 77 | 78 | xls_writef_string(sheet, 0, 0, "Font name", gheading); 79 | xls_writef_string(sheet, 0, 1, "Font size", gheading); 80 | 81 | nfs = sizeof(fonts) / (sizeof(struct fsfv)); 82 | for (i = 0; i < nfs; i++) { 83 | struct xl_format *fmt; 84 | 85 | fmt = wbook_addformat(gwbook); 86 | fmt_set_size(fmt, fonts[i].size); 87 | fmt_set_font(fmt, fonts[i].name); 88 | xls_writef_string(sheet, i+1, 0, fonts[i].name, fmt); 89 | xls_writef_number(sheet, i+1, 1, fonts[i].size, fmt); 90 | } 91 | } 92 | 93 | void named_colors(void) 94 | { 95 | struct wsheetctx *sheet; 96 | int i; 97 | 98 | char *colors[] = { "aqua", "black", "blue", "fuchsia", "gray", "green", 99 | "lime", "navy", "orange", "purple", "red", "silver", "white", "yellow" }; 100 | int indices[] = { 0x0F, 0x08, 0x0C, 0x0E, 0x17, 0x11, 0x0B, 0x12, 0x1D, 101 | 0x24, 0x0A, 0x16, 0x09, 0x0D }; 102 | 103 | sheet = wbook_addworksheet(gwbook, "Named colors"); 104 | wsheet_set_column(sheet, 0, 3, 15); 105 | xls_writef_string(sheet, 0, 0, "Index", gheading); 106 | xls_writef_string(sheet, 0, 1, "Index", gheading); 107 | xls_writef_string(sheet, 0, 2, "Name", gheading); 108 | xls_writef_string(sheet, 0, 3, "Color", gheading); 109 | 110 | for (i = 0; i < 14; i++) { 111 | struct xl_format *fmt; 112 | char fmt_name[12]; 113 | 114 | fmt = wbook_addformat(gwbook); 115 | fmt_set_color(fmt, colors[i]); 116 | fmt_set_align(fmt, "center"); 117 | 118 | snprintf(fmt_name, sizeof(fmt_name), "0x%02X", indices[i]); 119 | 120 | xls_writef_number(sheet, i+1, 0, indices[i], gcenter); 121 | xls_writef_string(sheet, i+1, 1, fmt_name, gcenter); 122 | xls_writef_string(sheet, i+1, 2, colors[i], gcenter); 123 | xls_writef_string(sheet, i+1, 3, colors[i], fmt); 124 | } 125 | } 126 | 127 | void standard_colors(void) 128 | { 129 | struct wsheetctx *sheet; 130 | int i; 131 | 132 | sheet = wbook_addworksheet(gwbook, "Standard colors"); 133 | wsheet_set_column(sheet, 0, 3, 15); 134 | xls_writef_string(sheet, 0, 0, "Index", gheading); 135 | xls_writef_string(sheet, 0, 1, "Index", gheading); 136 | xls_writef_string(sheet, 0, 2, "Color", gheading); 137 | 138 | for (i = 8; i < 64; i++) { 139 | struct xl_format *fmt; 140 | char fmt_name[12]; 141 | 142 | fmt = wbook_addformat(gwbook); 143 | fmt_set_colori(fmt, i); 144 | fmt_set_align(fmt, "center"); 145 | 146 | snprintf(fmt_name, sizeof(fmt_name), "0x%02X", i); 147 | xls_writef_number(sheet, i - 7, 0, i, gcenter); 148 | xls_writef_string(sheet, i - 7, 1, fmt_name, gcenter); 149 | xls_writef_string(sheet, i - 7, 2, "COLOR", fmt); 150 | } 151 | } 152 | 153 | struct numfmt { 154 | int index; 155 | double val; 156 | double nval; 157 | char *desc; 158 | }; 159 | 160 | void numeric_formats(void) 161 | { 162 | struct wsheetctx *sheet; 163 | int i, nfs; 164 | struct numfmt numfmts[] = { 165 | { 0x00, 1234.567, 0, "General" }, 166 | { 0x01, 1234.567, 0, "0" }, 167 | { 0x02, 1234.567, 0, "0.00" }, 168 | { 0x03, 1234.567, 0, "#,##0" }, 169 | { 0x04, 1234.567, 0, "#,##0.00" }, 170 | { 0x05, 1234.567, -1234.567, "($#,##0_);($#,##0)" }, 171 | { 0x06, 1234.567, -1234.567, "($#,##0_);[Red]($#,##0)" }, 172 | { 0x07, 1234.567, -1234.567, "($#,##0.00_);($#,##0.00)" }, 173 | { 0x08, 1234.567, -1234.567, "($#,##0.00_);[Red]($#,##0.00)" }, 174 | { 0x09, 0.567, 0, "0%" }, 175 | { 0x0A, 0.567, 0, "0.00%" }, 176 | { 0x0B, 1234.567, 0, "0.00E+00" }, 177 | { 0x0C, 0.75, 0, "# ?/?" }, 178 | { 0x0D, 0.3125, 0, "# \?\?/??" }, 179 | { 0x0E, 36870.016, 0, "m/d/yy" }, 180 | { 0x0F, 36870.016, 0, "d-mmm-yy" }, 181 | { 0x10, 36870.016, 0, "d-mmm" }, 182 | { 0x11, 36870.016, 0, "mmm-yy" }, 183 | { 0x12, 36870.016, 0, "h:mm AM/PM" }, 184 | { 0x13, 36870.016, 0, "h:mm:ss AM/PM" }, 185 | { 0x14, 36870.016, 0, "h:mm" }, 186 | { 0x15, 36870.016, 0, "h:mm:ss" }, 187 | { 0x16, 36870.016, 0, "m/d/yy h:mm" }, 188 | { 0x25, 1234.567, -1234.567, "(#,##0_);(#,##0)" }, 189 | { 0x26, 1234.567, -1234.567, "(#,##0_);[Red](#,##0)" }, 190 | { 0x27, 1234.567, -1234.567, "(#,##0.00_);(#,##0.00)" }, 191 | { 0x28, 1234.567, -1234.567, "(#,##0.00_);[Red](#,##0.00)" }, 192 | { 0x29, 1234.567, -1234.567, "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)" }, 193 | { 0x2A, 1234.567, -1234.567, "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)" }, 194 | { 0x2B, 1234.567, -1234.567, "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"\?\?_);_(@_)" }, 195 | { 0x2C, 1234.567, -1234.567, "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"\?\?_);_(@_)" }, 196 | { 0x2D, 36870.016, 0, "mm:ss" }, 197 | { 0x2E, 3.0153, 0, "[h]:mm:ss" }, 198 | { 0x2F, 36870.016, 0, "mm:ss.0" }, 199 | { 0x30, 1234.567, 0, "##0.0E+0" }, 200 | { 0x31, 1234.567, 0, "@" } 201 | }; 202 | 203 | sheet = wbook_addworksheet(gwbook, "Numeric formats"); 204 | wsheet_set_column(sheet, 0, 4, 15); 205 | wsheet_set_column(sheet, 5, 5, 45); 206 | 207 | xls_writef_string(sheet, 0, 0, "Index", gheading); 208 | xls_writef_string(sheet, 0, 1, "Index", gheading); 209 | xls_writef_string(sheet, 0, 2, "Unformatted", gheading); 210 | xls_writef_string(sheet, 0, 3, "Formatted", gheading); 211 | xls_writef_string(sheet, 0, 4, "Negative", gheading); 212 | xls_writef_string(sheet, 0, 5, "Format", gheading); 213 | 214 | nfs = sizeof(numfmts) / sizeof(struct numfmt); 215 | for (i = 0; i < nfs; i++) { 216 | struct xl_format *fmt; 217 | char fmt_name[12]; 218 | 219 | fmt = wbook_addformat(gwbook); 220 | fmt_set_num_format(fmt, numfmts[i].index); 221 | 222 | snprintf(fmt_name, sizeof(fmt_name), "0x%02X", numfmts[i].index); 223 | xls_writef_number(sheet, i + 1, 0, numfmts[i].index, gcenter); 224 | xls_writef_string(sheet, i + 1, 1, fmt_name, gcenter); 225 | xls_writef_number(sheet, i + 1, 2, numfmts[i].val, gcenter); 226 | xls_writef_number(sheet, i + 1, 3, numfmts[i].val, fmt); 227 | 228 | if (numfmts[i].nval) 229 | xls_writef_number(sheet, i + 1, 4, numfmts[i].nval, fmt); 230 | 231 | xls_write_string(sheet, i + 1, 5, numfmts[i].desc); 232 | } 233 | } 234 | 235 | void borders(void) 236 | { 237 | struct wsheetctx *sheet; 238 | int i; 239 | 240 | sheet = wbook_addworksheet(gwbook, "Borders"); 241 | 242 | wsheet_set_column(sheet, 0, 4, 10); 243 | wsheet_set_column(sheet, 5, 5, 40); 244 | 245 | xls_writef_string(sheet, 0, 0, "Index", gheading); 246 | xls_writef_string(sheet, 0, 1, "Index", gheading); 247 | xls_writef_string(sheet, 0, 3, "Style", gheading); 248 | xls_writef_string(sheet, 0, 5, "The style is highlighted in red for ", gheading); 249 | xls_writef_string(sheet, 1, 5, "emphasis, the default color is black.", gheading); 250 | 251 | for (i = 0; i < 8; i++) { 252 | struct xl_format *fmt; 253 | char fmt_name[12]; 254 | 255 | fmt = wbook_addformat(gwbook); 256 | fmt_set_border(fmt, i); 257 | fmt_set_border_color(fmt, "red"); 258 | fmt_set_align(fmt, "center"); 259 | 260 | snprintf(fmt_name, sizeof(fmt_name), "0x%02X", i); 261 | xls_writef_number(sheet, 2 * (i + 1), 0, i, gcenter); 262 | xls_writef_string(sheet, 2 * (i + 1), 1, fmt_name, gcenter); 263 | xls_writef_string(sheet, 2 * (i + 1), 3, "Border", fmt); 264 | } 265 | } 266 | 267 | void patterns(void) 268 | { 269 | struct wsheetctx *sheet; 270 | int i; 271 | 272 | sheet = wbook_addworksheet(gwbook, "Patterns"); 273 | 274 | wsheet_set_column(sheet, 0, 4, 10); 275 | wsheet_set_column(sheet, 5, 5, 50); 276 | 277 | xls_writef_string(sheet, 0, 0, "Index", gheading); 278 | xls_writef_string(sheet, 0, 1, "Index", gheading); 279 | xls_writef_string(sheet, 0, 3, "Pattern", gheading); 280 | xls_writef_string(sheet, 0, 5, "The background color has been set to silver.", gheading); 281 | xls_writef_string(sheet, 1, 5, "The foreground color has been set to green.", gheading); 282 | 283 | for (i = 0; i < 32; i++) { 284 | struct xl_format *fmt; 285 | char fmt_name[12]; 286 | 287 | fmt = wbook_addformat(gwbook); 288 | fmt_set_pattern(fmt, i); 289 | fmt_set_bg_color(fmt, "silver"); 290 | fmt_set_fg_color(fmt, "green"); 291 | fmt_set_align(fmt, "center"); 292 | 293 | snprintf(fmt_name, sizeof(fmt_name), "0x%02X", i); 294 | xls_writef_number(sheet, 2 * (i + 1), 0, i, gcenter); 295 | xls_writef_string(sheet, 2 * (i + 1), 1, fmt_name, gcenter); 296 | xls_writef_string(sheet, 2 * (i + 1), 3, "Pattern", fmt); 297 | 298 | if (i == 1) { 299 | xls_writef_string(sheet, 2 * (i + 1), 5, "This is solid color, the most useful pattern", gheading); 300 | 301 | } 302 | } 303 | } 304 | 305 | void alignment(void) 306 | { 307 | struct wsheetctx *sheet; 308 | struct xl_format *fmt[15]; 309 | int i; 310 | 311 | sheet = wbook_addworksheet(gwbook, "Alignment"); 312 | 313 | wsheet_set_column(sheet, 0, 7, 12); 314 | //wsheet_set_row(sheet, 0, 40, NULL); 315 | wsheet_set_selection(sheet, 7, 0, 0, 0); 316 | 317 | for (i = 0; i < 15; i++) { 318 | fmt[i] = wbook_addformat(gwbook); 319 | } 320 | 321 | fmt_set_align(fmt[1], "top"); 322 | fmt_set_align(fmt[2], "bottom"); 323 | fmt_set_align(fmt[3], "vcenter"); 324 | fmt_set_align(fmt[4], "vjustify"); 325 | fmt_set_text_wrap(fmt[5], 1); 326 | 327 | fmt_set_align(fmt[6], "left"); 328 | fmt_set_align(fmt[7], "right"); 329 | fmt_set_align(fmt[8], "center"); 330 | fmt_set_align(fmt[9], "fill"); 331 | fmt_set_align(fmt[10], "justify"); 332 | fmt_set_merge(fmt[11]); 333 | 334 | fmt_set_rotation(fmt[12], 1); 335 | fmt_set_rotation(fmt[13], 2); 336 | fmt_set_rotation(fmt[14], 3); 337 | 338 | xls_writef_string(sheet, 0, 0, "Vertical", gheading); 339 | xls_writef_string(sheet, 0, 1, "top", fmt[1]); 340 | xls_writef_string(sheet, 0, 2, "bottom", fmt[2]); 341 | xls_writef_string(sheet, 0, 3, "vcenter", fmt[3]); 342 | xls_writef_string(sheet, 0, 4, "vjustify", fmt[4]); 343 | xls_writef_string(sheet, 0, 5, "text\nwrap", fmt[5]); 344 | 345 | xls_writef_string(sheet, 2, 0, "Horizontal", gheading); 346 | xls_writef_string(sheet, 2, 1, "left", fmt[6]); 347 | xls_writef_string(sheet, 2, 2, "right", fmt[7]); 348 | xls_writef_string(sheet, 2, 3, "center", fmt[8]); 349 | xls_writef_string(sheet, 2, 4, "fill", fmt[9]); 350 | xls_writef_string(sheet, 2, 5, "justify", fmt[10]); 351 | 352 | xls_writef_string(sheet, 2, 6, "merge", fmt[11]); 353 | xls_write_blank(sheet, 2, 7, fmt[11]); 354 | 355 | xls_writef_string(sheet, 4, 0, "Rotation", gheading); 356 | xls_writef_string(sheet, 4, 1, "Rotate 1", fmt[12]); 357 | xls_writef_string(sheet, 4, 2, "Rotate 2", fmt[13]); 358 | xls_writef_string(sheet, 4, 3, "Rotate 3", fmt[14]); 359 | } 360 | 361 | int main(int argc, char *argv[]) 362 | { 363 | /* Create a new Excel Workbook */ 364 | gwbook = wbook_new("example2.xls", 0); 365 | 366 | /* Some common formats */ 367 | gheading = wbook_addformat(gwbook); 368 | gcenter = wbook_addformat(gwbook); 369 | fmt_set_align(gcenter, "center"); 370 | fmt_set_align(gheading, "center"); 371 | fmt_set_bold(gheading, 1); 372 | 373 | intro(); 374 | fonts(); 375 | named_colors(); 376 | standard_colors(); 377 | numeric_formats(); 378 | borders(); 379 | patterns(); 380 | alignment(); 381 | 382 | /* This is required */ 383 | wbook_close(gwbook); 384 | wbook_destroy(gwbook); 385 | 386 | return 0; 387 | } 388 | -------------------------------------------------------------------------------- /tests/example3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "excel.h" 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | struct wbookctx *wbook; 26 | struct wsheetctx *one; 27 | struct xl_format *fmt; 28 | 29 | /* Create a new Excel Workbook */ 30 | wbook = wbook_new("example3.xls", 0); 31 | one = wbook_addworksheet(wbook, "Formula"); 32 | 33 | fmt = wbook_addformat(wbook); 34 | fmt_set_bold(fmt, 1); 35 | fmt_set_color(fmt, "blue"); 36 | 37 | xls_writef_string(one, 0, 0, "Formula examples", fmt); 38 | wsheet_writef_formula(one, 1, 1, "=2+3*4", NULL); 39 | wsheet_writef_formula(one, 1, 2, "=SUM(2,9)", NULL); 40 | 41 | wbook_close(wbook); 42 | wbook_destroy(wbook); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /tests/merge1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Devin Smith 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "excel.h" 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | struct wbookctx *wbook; 26 | struct wsheetctx *sheet; 27 | struct xl_format *fmt; 28 | 29 | /* Create a new Excel Workbook */ 30 | wbook = wbook_new("merge1.xls", 0); 31 | sheet = wbook_addworksheet(wbook, NULL); 32 | 33 | /* Set the column width for columns 2 and 3 */ 34 | wsheet_set_column(sheet, 1, 3, 20); 35 | /* Set the row height for row 2 */ 36 | wsheet_set_row(sheet, 2, 30, NULL); 37 | 38 | fmt = wbook_addformat(wbook); 39 | fmt_set_merge(fmt); 40 | 41 | xls_writef_string(sheet, 2, 1, "Merged Cells", fmt); 42 | xls_write_blank(sheet, 2, 2, fmt); 43 | xls_write_blank(sheet, 2, 3, fmt); 44 | 45 | wbook_close(wbook); 46 | wbook_destroy(wbook); 47 | 48 | return 0; 49 | } 50 | --------------------------------------------------------------------------------