fast_excel 0.2.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +2 -0
  3. data/.gitignore +3 -0
  4. data/.travis.yml +18 -6
  5. data/CHANGELOG.md +14 -1
  6. data/Dockerfile.test +16 -0
  7. data/Gemfile +1 -1
  8. data/Gemfile.lock +21 -21
  9. data/Makefile +13 -2
  10. data/README.md +148 -38
  11. data/Rakefile +2 -0
  12. data/examples/example.rb +3 -3
  13. data/examples/example_filters.rb +36 -0
  14. data/examples/example_formula.rb +1 -3
  15. data/examples/example_hyperlink.rb +20 -0
  16. data/fast_excel.gemspec +1 -1
  17. data/lib/fast_excel.rb +36 -12
  18. data/lib/fast_excel/binding.rb +31 -21
  19. data/lib/fast_excel/binding/chart.rb +20 -1
  20. data/lib/fast_excel/binding/workbook.rb +10 -2
  21. data/lib/fast_excel/binding/worksheet.rb +44 -27
  22. data/libxlsxwriter/.gitignore +1 -0
  23. data/libxlsxwriter/.indent.pro +5 -0
  24. data/libxlsxwriter/CMakeLists.txt +1 -11
  25. data/libxlsxwriter/CONTRIBUTING.md +1 -1
  26. data/libxlsxwriter/Changes.txt +84 -0
  27. data/libxlsxwriter/LICENSE.txt +1 -1
  28. data/libxlsxwriter/Makefile +7 -5
  29. data/libxlsxwriter/Readme.md +1 -1
  30. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +1 -0
  31. data/libxlsxwriter/include/xlsxwriter.h +2 -2
  32. data/libxlsxwriter/include/xlsxwriter/app.h +2 -2
  33. data/libxlsxwriter/include/xlsxwriter/chart.h +56 -6
  34. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
  35. data/libxlsxwriter/include/xlsxwriter/common.h +27 -6
  36. data/libxlsxwriter/include/xlsxwriter/content_types.h +5 -2
  37. data/libxlsxwriter/include/xlsxwriter/core.h +2 -2
  38. data/libxlsxwriter/include/xlsxwriter/custom.h +2 -2
  39. data/libxlsxwriter/include/xlsxwriter/drawing.h +3 -2
  40. data/libxlsxwriter/include/xlsxwriter/format.h +3 -3
  41. data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  42. data/libxlsxwriter/include/xlsxwriter/packager.h +13 -8
  43. data/libxlsxwriter/include/xlsxwriter/relationships.h +2 -2
  44. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +5 -3
  45. data/libxlsxwriter/include/xlsxwriter/styles.h +9 -4
  46. data/libxlsxwriter/include/xlsxwriter/theme.h +2 -2
  47. data/libxlsxwriter/include/xlsxwriter/utility.h +26 -2
  48. data/libxlsxwriter/include/xlsxwriter/workbook.h +232 -55
  49. data/libxlsxwriter/include/xlsxwriter/worksheet.h +264 -53
  50. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +3 -1
  51. data/libxlsxwriter/libxlsxwriter.podspec +1 -1
  52. data/libxlsxwriter/src/Makefile +3 -3
  53. data/libxlsxwriter/src/app.c +2 -2
  54. data/libxlsxwriter/src/chart.c +41 -5
  55. data/libxlsxwriter/src/chartsheet.c +508 -0
  56. data/libxlsxwriter/src/content_types.c +12 -4
  57. data/libxlsxwriter/src/core.c +2 -2
  58. data/libxlsxwriter/src/custom.c +2 -2
  59. data/libxlsxwriter/src/drawing.c +114 -17
  60. data/libxlsxwriter/src/format.c +3 -3
  61. data/libxlsxwriter/src/hash_table.c +1 -1
  62. data/libxlsxwriter/src/packager.c +369 -65
  63. data/libxlsxwriter/src/relationships.c +2 -2
  64. data/libxlsxwriter/src/shared_strings.c +18 -4
  65. data/libxlsxwriter/src/styles.c +56 -9
  66. data/libxlsxwriter/src/theme.c +2 -2
  67. data/libxlsxwriter/src/utility.c +53 -6
  68. data/libxlsxwriter/src/workbook.c +372 -56
  69. data/libxlsxwriter/src/worksheet.c +425 -76
  70. data/libxlsxwriter/src/xmlwriter.c +17 -8
  71. data/libxlsxwriter/third_party/minizip/ioapi.c +10 -0
  72. data/libxlsxwriter/third_party/minizip/zip.c +2 -0
  73. data/libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c +2 -2
  74. data/libxlsxwriter/version.txt +1 -1
  75. data/test/tmpfile_test.rb +1 -0
  76. data/test/validations_test.rb +26 -6
  77. data/test/worksheet_test.rb +43 -0
  78. metadata +9 -6
  79. data/libxlsxwriter/.drone.yml +0 -27
  80. data/libxlsxwriter/appveyor.yml +0 -65
  81. data/libxlsxwriter/cmake/FindZLIB.cmake +0 -123
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
@@ -17,8 +17,6 @@
17
17
 
18
18
  #define LXW_STR_MAX 32767
19
19
  #define LXW_BUFFER_SIZE 4096
20
- #define LXW_PORTRAIT 1
21
- #define LXW_LANDSCAPE 0
22
20
  #define LXW_PRINT_ACROSS 1
23
21
  #define LXW_VALIDATION_MAX_TITLE_LENGTH 32
24
22
  #define LXW_VALIDATION_MAX_STRING_LENGTH 255
@@ -271,10 +269,11 @@ _free_image_options(lxw_image_options *image)
271
269
  return;
272
270
 
273
271
  free(image->filename);
274
- free(image->short_name);
272
+ free(image->description);
275
273
  free(image->extension);
276
274
  free(image->url);
277
275
  free(image->tip);
276
+ free(image->image_buffer);
278
277
  free(image);
279
278
  }
280
279
 
@@ -449,6 +448,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
449
448
  free(worksheet->vbreaks);
450
449
  free(worksheet->name);
451
450
  free(worksheet->quoted_name);
451
+ free(worksheet->vba_codename);
452
452
 
453
453
  free(worksheet);
454
454
  worksheet = NULL;
@@ -538,6 +538,26 @@ _new_inline_string_cell(lxw_row_t row_num,
538
538
  return cell;
539
539
  }
540
540
 
541
+ /*
542
+ * Create a new worksheet inline_string cell object for rich strings.
543
+ */
544
+ STATIC lxw_cell *
545
+ _new_inline_rich_string_cell(lxw_row_t row_num,
546
+ lxw_col_t col_num, char *string,
547
+ lxw_format *format)
548
+ {
549
+ lxw_cell *cell = calloc(1, sizeof(lxw_cell));
550
+ RETURN_ON_MEM_ERROR(cell, cell);
551
+
552
+ cell->row_num = row_num;
553
+ cell->col_num = col_num;
554
+ cell->type = INLINE_RICH_STRING_CELL;
555
+ cell->format = format;
556
+ cell->u.string = string;
557
+
558
+ return cell;
559
+ }
560
+
541
561
  /*
542
562
  * Create a new worksheet formula cell object.
543
563
  */
@@ -841,38 +861,6 @@ _cell_cmp(lxw_cell *cell1, lxw_cell *cell2)
841
861
  return 0;
842
862
  }
843
863
 
844
- /*
845
- * Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
846
- * of OpenOffice.
847
- */
848
- STATIC uint16_t
849
- _hash_password(const char *password)
850
- {
851
- size_t count;
852
- uint8_t i;
853
- uint16_t hash = 0x0000;
854
-
855
- count = strlen(password);
856
-
857
- for (i = 0; i < count; i++) {
858
- uint32_t low_15;
859
- uint32_t high_15;
860
- uint32_t letter = password[i] << (i + 1);
861
-
862
- low_15 = letter & 0x7fff;
863
- high_15 = letter & (0x7fff << 15);
864
- high_15 = high_15 >> 15;
865
- letter = low_15 | high_15;
866
-
867
- hash ^= letter;
868
- }
869
-
870
- hash ^= count;
871
- hash ^= 0xCE4B;
872
-
873
- return hash;
874
- }
875
-
876
864
  /*
877
865
  * Simple replacement for libgen.h basename() for compatibility with MSVC. It
878
866
  * handles forward and back slashes. It doesn't copy exactly the return
@@ -1753,6 +1741,9 @@ _worksheet_size_col(lxw_worksheet *self, lxw_col_t col_num)
1753
1741
  }
1754
1742
 
1755
1743
  if (col_opt) {
1744
+ if (col_opt->hidden)
1745
+ return 0;
1746
+
1756
1747
  width = col_opt->width;
1757
1748
 
1758
1749
  /* Convert to pixels. */
@@ -1788,6 +1779,9 @@ _worksheet_size_row(lxw_worksheet *self, lxw_row_t row_num)
1788
1779
  row = lxw_worksheet_find_row(self, row_num);
1789
1780
 
1790
1781
  if (row) {
1782
+ if (row->hidden)
1783
+ return 0;
1784
+
1791
1785
  height = row->height;
1792
1786
 
1793
1787
  if (height == 0)
@@ -1914,23 +1908,30 @@ _worksheet_position_object_pixels(lxw_worksheet *self,
1914
1908
  y_abs += y1;
1915
1909
 
1916
1910
  /* Adjust start col for offsets that are greater than the col width. */
1917
- while (x1 >= _worksheet_size_col(self, col_start)) {
1918
- x1 -= _worksheet_size_col(self, col_start);
1919
- col_start++;
1911
+ if (_worksheet_size_col(self, col_start) > 0) {
1912
+ while (x1 >= _worksheet_size_col(self, col_start)) {
1913
+ x1 -= _worksheet_size_col(self, col_start);
1914
+ col_start++;
1915
+ }
1920
1916
  }
1921
1917
 
1922
1918
  /* Adjust start row for offsets that are greater than the row height. */
1923
- while (y1 >= _worksheet_size_row(self, row_start)) {
1924
- y1 -= _worksheet_size_row(self, row_start);
1925
- row_start++;
1919
+ if (_worksheet_size_row(self, row_start) > 0) {
1920
+ while (y1 >= _worksheet_size_row(self, row_start)) {
1921
+ y1 -= _worksheet_size_row(self, row_start);
1922
+ row_start++;
1923
+ }
1926
1924
  }
1927
1925
 
1928
1926
  /* Initialize end cell to the same as the start cell. */
1929
1927
  col_end = col_start;
1930
1928
  row_end = row_start;
1931
1929
 
1932
- width = width + x1;
1933
- height = height + y1;
1930
+ /* Only offset the image in the cell if the row/col isn't hidden. */
1931
+ if (_worksheet_size_col(self, col_start) > 0)
1932
+ width = width + x1;
1933
+ if (_worksheet_size_row(self, row_start) > 0)
1934
+ height = height + y1;
1934
1935
 
1935
1936
  /* Subtract the underlying cell widths to find the end cell. */
1936
1937
  while (width >= _worksheet_size_col(self, col_end)) {
@@ -1992,7 +1993,7 @@ _worksheet_position_object_emus(lxw_worksheet *self,
1992
1993
  */
1993
1994
  void
1994
1995
  lxw_worksheet_prepare_image(lxw_worksheet *self,
1995
- uint16_t image_ref_id, uint16_t drawing_id,
1996
+ uint32_t image_ref_id, uint32_t drawing_id,
1996
1997
  lxw_image_options *image_data)
1997
1998
  {
1998
1999
  lxw_drawing_object *drawing_object;
@@ -2027,7 +2028,7 @@ lxw_worksheet_prepare_image(lxw_worksheet *self,
2027
2028
 
2028
2029
  drawing_object->anchor_type = LXW_ANCHOR_TYPE_IMAGE;
2029
2030
  drawing_object->edit_as = LXW_ANCHOR_EDIT_AS_ONE_CELL;
2030
- drawing_object->description = lxw_strdup(image_data->short_name);
2031
+ drawing_object->description = lxw_strdup(image_data->description);
2031
2032
 
2032
2033
  /* Scale to user scale. */
2033
2034
  width = image_data->width * image_data->x_scale;
@@ -2079,8 +2080,10 @@ mem_error:
2079
2080
  */
2080
2081
  void
2081
2082
  lxw_worksheet_prepare_chart(lxw_worksheet *self,
2082
- uint16_t chart_ref_id, uint16_t drawing_id,
2083
- lxw_image_options *image_data)
2083
+ uint32_t chart_ref_id,
2084
+ uint32_t drawing_id,
2085
+ lxw_image_options *image_data,
2086
+ uint8_t is_chartsheet)
2084
2087
  {
2085
2088
  lxw_drawing_object *drawing_object;
2086
2089
  lxw_rel_tuple *relationship;
@@ -2090,9 +2093,16 @@ lxw_worksheet_prepare_chart(lxw_worksheet *self,
2090
2093
 
2091
2094
  if (!self->drawing) {
2092
2095
  self->drawing = lxw_drawing_new();
2093
- self->drawing->embedded = LXW_TRUE;
2094
2096
  RETURN_VOID_ON_MEM_ERROR(self->drawing);
2095
2097
 
2098
+ if (is_chartsheet) {
2099
+ self->drawing->embedded = LXW_FALSE;
2100
+ self->drawing->orientation = self->orientation;
2101
+ }
2102
+ else {
2103
+ self->drawing->embedded = LXW_TRUE;
2104
+ }
2105
+
2096
2106
  relationship = calloc(1, sizeof(lxw_rel_tuple));
2097
2107
  GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
2098
2108
 
@@ -2259,8 +2269,7 @@ _process_png(lxw_image_options *image_options)
2259
2269
 
2260
2270
  file_error:
2261
2271
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2262
- "no size data found in file: %s.",
2263
- image_options->filename);
2272
+ "no size data found in: %s.", image_options->filename);
2264
2273
 
2265
2274
  return LXW_ERROR_IMAGE_DIMENSIONS;
2266
2275
  }
@@ -2386,8 +2395,7 @@ _process_jpeg(lxw_image_options *image_options)
2386
2395
 
2387
2396
  file_error:
2388
2397
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2389
- "no size data found in file: %s.",
2390
- image_options->filename);
2398
+ "no size data found in: %s.", image_options->filename);
2391
2399
 
2392
2400
  return LXW_ERROR_IMAGE_DIMENSIONS;
2393
2401
  }
@@ -2436,8 +2444,7 @@ _process_bmp(lxw_image_options *image_options)
2436
2444
 
2437
2445
  file_error:
2438
2446
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2439
- "no size data found in file: %s.",
2440
- image_options->filename);
2447
+ "no size data found in: %s.", image_options->filename);
2441
2448
 
2442
2449
  return LXW_ERROR_IMAGE_DIMENSIONS;
2443
2450
  }
@@ -2454,7 +2461,7 @@ _get_image_properties(lxw_image_options *image_options)
2454
2461
  /* Read 4 bytes to look for the file header/signature. */
2455
2462
  if (fread(signature, 1, 4, image_options->stream) < 4) {
2456
2463
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2457
- "couldn't read file type for file: %s.",
2464
+ "couldn't read image type for: %s.",
2458
2465
  image_options->filename);
2459
2466
  return LXW_ERROR_IMAGE_DIMENSIONS;
2460
2467
  }
@@ -2473,7 +2480,7 @@ _get_image_properties(lxw_image_options *image_options)
2473
2480
  }
2474
2481
  else {
2475
2482
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2476
- "unsupported image format for file: %s.",
2483
+ "unsupported image format for: %s.",
2477
2484
  image_options->filename);
2478
2485
  return LXW_ERROR_IMAGE_DIMENSIONS;
2479
2486
  }
@@ -2576,6 +2583,41 @@ _write_inline_string_cell(lxw_worksheet *self, char *range,
2576
2583
  free(string);
2577
2584
  }
2578
2585
 
2586
+ /*
2587
+ * Write out an inline rich string. Doesn't use the xml functions as an
2588
+ * optimization in the inner cell writing loop.
2589
+ */
2590
+ STATIC void
2591
+ _write_inline_rich_string_cell(lxw_worksheet *self, char *range,
2592
+ int32_t style_index, lxw_cell *cell)
2593
+ {
2594
+ char *string = cell->u.string;
2595
+
2596
+ /* Add attribute to preserve leading or trailing whitespace. */
2597
+ if (isspace((unsigned char) string[0])
2598
+ || isspace((unsigned char) string[strlen(string) - 1])) {
2599
+
2600
+ if (style_index)
2601
+ fprintf(self->file,
2602
+ "<c r=\"%s\" s=\"%d\" t=\"inlineStr\"><is>%s</is></c>",
2603
+ range, style_index, string);
2604
+ else
2605
+ fprintf(self->file,
2606
+ "<c r=\"%s\" t=\"inlineStr\"><is>%s</is></c>",
2607
+ range, string);
2608
+ }
2609
+ else {
2610
+ if (style_index)
2611
+ fprintf(self->file,
2612
+ "<c r=\"%s\" s=\"%d\" t=\"inlineStr\">"
2613
+ "<is>%s</is></c>", range, style_index, string);
2614
+ else
2615
+ fprintf(self->file,
2616
+ "<c r=\"%s\" t=\"inlineStr\">"
2617
+ "<is>%s</is></c>", range, string);
2618
+ }
2619
+ }
2620
+
2579
2621
  /*
2580
2622
  * Write out a formula worksheet cell with a numeric result.
2581
2623
  */
@@ -2712,6 +2754,11 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
2712
2754
  return;
2713
2755
  }
2714
2756
 
2757
+ if (cell->type == INLINE_RICH_STRING_CELL) {
2758
+ _write_inline_rich_string_cell(self, range, style_index, cell);
2759
+ return;
2760
+ }
2761
+
2715
2762
  /* For other cell types use the general functions. */
2716
2763
  LXW_INIT_ATTRIBUTES();
2717
2764
  LXW_PUSH_ATTRIBUTES_STR("r", range);
@@ -3093,14 +3140,15 @@ _worksheet_write_sheet_pr(lxw_worksheet *self)
3093
3140
  if (!self->fit_page
3094
3141
  && !self->filter_on
3095
3142
  && self->tab_color == LXW_COLOR_UNSET
3096
- && !self->outline_changed && !self->vba_codename) {
3143
+ && !self->outline_changed
3144
+ && !self->vba_codename && !self->is_chartsheet) {
3097
3145
  return;
3098
3146
  }
3099
3147
 
3100
3148
  LXW_INIT_ATTRIBUTES();
3101
3149
 
3102
3150
  if (self->vba_codename)
3103
- LXW_PUSH_ATTRIBUTES_INT("codeName", self->vba_codename);
3151
+ LXW_PUSH_ATTRIBUTES_STR("codeName", self->vba_codename);
3104
3152
 
3105
3153
  if (self->filter_on)
3106
3154
  LXW_PUSH_ATTRIBUTES_STR("filterMode", "1");
@@ -3364,13 +3412,12 @@ mem_error:
3364
3412
  * Write the <sheetProtection> element.
3365
3413
  */
3366
3414
  STATIC void
3367
- _worksheet_write_sheet_protection(lxw_worksheet *self)
3415
+ _worksheet_write_sheet_protection(lxw_worksheet *self,
3416
+ lxw_protection *protect)
3368
3417
  {
3369
3418
  struct xml_attribute_list attributes;
3370
3419
  struct xml_attribute *attribute;
3371
3420
 
3372
- struct lxw_protection *protect = &self->protection;
3373
-
3374
3421
  if (!protect->is_configured)
3375
3422
  return;
3376
3423
 
@@ -3382,7 +3429,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
3382
3429
  if (!protect->no_sheet)
3383
3430
  LXW_PUSH_ATTRIBUTES_INT("sheet", 1);
3384
3431
 
3385
- if (protect->content)
3432
+ if (!protect->no_content)
3386
3433
  LXW_PUSH_ATTRIBUTES_INT("content", 1);
3387
3434
 
3388
3435
  if (!protect->objects)
@@ -3439,7 +3486,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
3439
3486
  * Write the <drawing> element.
3440
3487
  */
3441
3488
  STATIC void
3442
- _write_drawing(lxw_worksheet *self, uint16_t id)
3489
+ _worksheet_write_drawing(lxw_worksheet *self, uint16_t id)
3443
3490
  {
3444
3491
  struct xml_attribute_list attributes;
3445
3492
  struct xml_attribute *attribute;
@@ -3461,14 +3508,14 @@ _write_drawing(lxw_worksheet *self, uint16_t id)
3461
3508
  * Write the <drawing> elements.
3462
3509
  */
3463
3510
  STATIC void
3464
- _write_drawings(lxw_worksheet *self)
3511
+ _worksheet_write_drawings(lxw_worksheet *self)
3465
3512
  {
3466
3513
  if (!self->drawing)
3467
3514
  return;
3468
3515
 
3469
3516
  self->rel_count++;
3470
3517
 
3471
- _write_drawing(self, self->rel_count);
3518
+ _worksheet_write_drawing(self, self->rel_count);
3472
3519
  }
3473
3520
 
3474
3521
  /*
@@ -3689,6 +3736,52 @@ _worksheet_write_data_validations(lxw_worksheet *self)
3689
3736
  LXW_FREE_ATTRIBUTES();
3690
3737
  }
3691
3738
 
3739
+ /*
3740
+ * External functions to call intern XML methods shared with chartsheet.
3741
+ */
3742
+ void
3743
+ lxw_worksheet_write_sheet_views(lxw_worksheet *self)
3744
+ {
3745
+ _worksheet_write_sheet_views(self);
3746
+ }
3747
+
3748
+ void
3749
+ lxw_worksheet_write_page_margins(lxw_worksheet *self)
3750
+ {
3751
+ _worksheet_write_page_margins(self);
3752
+ }
3753
+
3754
+ void
3755
+ lxw_worksheet_write_drawings(lxw_worksheet *self)
3756
+ {
3757
+ _worksheet_write_drawings(self);
3758
+ }
3759
+
3760
+ void
3761
+ lxw_worksheet_write_sheet_protection(lxw_worksheet *self,
3762
+ lxw_protection *protect)
3763
+ {
3764
+ _worksheet_write_sheet_protection(self, protect);
3765
+ }
3766
+
3767
+ void
3768
+ lxw_worksheet_write_sheet_pr(lxw_worksheet *self)
3769
+ {
3770
+ _worksheet_write_sheet_pr(self);
3771
+ }
3772
+
3773
+ void
3774
+ lxw_worksheet_write_page_setup(lxw_worksheet *self)
3775
+ {
3776
+ _worksheet_write_page_setup(self);
3777
+ }
3778
+
3779
+ void
3780
+ lxw_worksheet_write_header_footer(lxw_worksheet *self)
3781
+ {
3782
+ _worksheet_write_header_footer(self);
3783
+ }
3784
+
3692
3785
  /*
3693
3786
  * Assemble and write the XML file.
3694
3787
  */
@@ -3723,7 +3816,7 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
3723
3816
  _worksheet_write_optimized_sheet_data(self);
3724
3817
 
3725
3818
  /* Write the sheetProtection element. */
3726
- _worksheet_write_sheet_protection(self);
3819
+ _worksheet_write_sheet_protection(self, &self->protection);
3727
3820
 
3728
3821
  /* Write the autoFilter element. */
3729
3822
  _worksheet_write_auto_filter(self);
@@ -3756,7 +3849,7 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
3756
3849
  _worksheet_write_col_breaks(self);
3757
3850
 
3758
3851
  /* Write the drawing element. */
3759
- _write_drawings(self);
3852
+ _worksheet_write_drawings(self);
3760
3853
 
3761
3854
  /* Close the worksheet tag. */
3762
3855
  lxw_xml_end_tag(self->file, "worksheet");
@@ -3823,7 +3916,7 @@ worksheet_write_string(lxw_worksheet *self,
3823
3916
 
3824
3917
  if (!self->optimize) {
3825
3918
  /* Get the SST element and string id. */
3826
- sst_element = lxw_get_sst_index(self->sst, string);
3919
+ sst_element = lxw_get_sst_index(self->sst, string, LXW_FALSE);
3827
3920
 
3828
3921
  if (!sst_element)
3829
3922
  return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
@@ -4298,6 +4391,156 @@ worksheet_write_url(lxw_worksheet *self,
4298
4391
  NULL);
4299
4392
  }
4300
4393
 
4394
+ /*
4395
+ * Write a rich string to an Excel file.
4396
+ *
4397
+ * Rather than duplicate several of the styles.c font xml methods of styles.c
4398
+ * and write the data to a memory buffer this function creates a temporary
4399
+ * styles object and uses it to write the data to a file. It then reads that
4400
+ * data back into memory and closes the file.
4401
+ */
4402
+ lxw_error
4403
+ worksheet_write_rich_string(lxw_worksheet *self,
4404
+ lxw_row_t row_num,
4405
+ lxw_col_t col_num,
4406
+ lxw_rich_string_tuple *rich_strings[],
4407
+ lxw_format *format)
4408
+ {
4409
+ lxw_cell *cell;
4410
+ int32_t string_id;
4411
+ struct sst_element *sst_element;
4412
+ lxw_error err;
4413
+ uint8_t i;
4414
+ long file_size;
4415
+ char *rich_string = NULL;
4416
+ char *string_copy = NULL;
4417
+ lxw_styles *styles = NULL;
4418
+ lxw_format *default_format = NULL;
4419
+ lxw_rich_string_tuple *rich_string_tuple = NULL;
4420
+ FILE *tmpfile;
4421
+
4422
+ err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
4423
+ if (err)
4424
+ return err;
4425
+
4426
+ /* Iterate through rich string fragments to check for input errors. */
4427
+ i = 0;
4428
+ err = LXW_NO_ERROR;
4429
+ while ((rich_string_tuple = rich_strings[i++]) != NULL) {
4430
+
4431
+ /* Check for NULL or empty strings. */
4432
+ if (!rich_string_tuple->string || !*rich_string_tuple->string) {
4433
+ err = LXW_ERROR_PARAMETER_VALIDATION;
4434
+ }
4435
+ }
4436
+
4437
+ /* If there are less than 2 fragments it isn't a rich string. */
4438
+ if (i <= 2)
4439
+ err = LXW_ERROR_PARAMETER_VALIDATION;
4440
+
4441
+ if (err)
4442
+ return err;
4443
+
4444
+ /* Create a tmp file for the styles object. */
4445
+ tmpfile = lxw_tmpfile(self->tmpdir);
4446
+ if (!tmpfile)
4447
+ return LXW_ERROR_CREATING_TMPFILE;
4448
+
4449
+ /* Create a temp styles object for writing the font data. */
4450
+ styles = lxw_styles_new();
4451
+ GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
4452
+ styles->file = tmpfile;
4453
+
4454
+ /* Create a default format for non-formatted text. */
4455
+ default_format = lxw_format_new();
4456
+ GOTO_LABEL_ON_MEM_ERROR(default_format, mem_error);
4457
+
4458
+ /* Iterate through the rich string fragments and write each one out. */
4459
+ i = 0;
4460
+ while ((rich_string_tuple = rich_strings[i++]) != NULL) {
4461
+ lxw_xml_start_tag(tmpfile, "r", NULL);
4462
+
4463
+ if (rich_string_tuple->format) {
4464
+ /* Write the user defined font format. */
4465
+ lxw_styles_write_rich_font(styles, rich_string_tuple->format);
4466
+ }
4467
+ else {
4468
+ /* Write a default font format. Except for the first fragment. */
4469
+ if (i > 1)
4470
+ lxw_styles_write_rich_font(styles, default_format);
4471
+ }
4472
+
4473
+ lxw_styles_write_string_fragment(styles, rich_string_tuple->string);
4474
+ lxw_xml_end_tag(tmpfile, "r");
4475
+ }
4476
+
4477
+ /* Free the temp objects. */
4478
+ lxw_styles_free(styles);
4479
+ lxw_format_free(default_format);
4480
+
4481
+ /* Flush the file and read the size to calculate the required memory. */
4482
+ fflush(tmpfile);
4483
+ file_size = ftell(tmpfile);
4484
+
4485
+ /* Allocate a buffer for the rich string xml data. */
4486
+ rich_string = calloc(file_size + 1, 1);
4487
+ GOTO_LABEL_ON_MEM_ERROR(rich_string, mem_error);
4488
+
4489
+ /* Rewind the file and read the data into the memory buffer. */
4490
+ rewind(tmpfile);
4491
+ if (fread(rich_string, file_size, 1, tmpfile) < 1) {
4492
+ fclose(tmpfile);
4493
+ free(rich_string);
4494
+ return LXW_ERROR_READING_TMPFILE;
4495
+ }
4496
+
4497
+ /* Close the temp file. */
4498
+ fclose(tmpfile);
4499
+
4500
+ if (lxw_utf8_strlen(rich_string) > LXW_STR_MAX) {
4501
+ free(rich_string);
4502
+ return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;
4503
+ }
4504
+
4505
+ if (!self->optimize) {
4506
+ /* Get the SST element and string id. */
4507
+ sst_element = lxw_get_sst_index(self->sst, rich_string, LXW_TRUE);
4508
+ free(rich_string);
4509
+
4510
+ if (!sst_element)
4511
+ return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
4512
+
4513
+ string_id = sst_element->index;
4514
+ cell = _new_string_cell(row_num, col_num, string_id,
4515
+ sst_element->string, format);
4516
+ }
4517
+ else {
4518
+ /* Look for and escape control chars in the string. */
4519
+ if (strpbrk(rich_string, "\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C"
4520
+ "\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"
4521
+ "\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")) {
4522
+ string_copy = lxw_escape_control_characters(rich_string);
4523
+ free(rich_string);
4524
+ }
4525
+ else {
4526
+ string_copy = rich_string;
4527
+ }
4528
+ cell = _new_inline_rich_string_cell(row_num, col_num, string_copy,
4529
+ format);
4530
+ }
4531
+
4532
+ _insert_cell(self, row_num, col_num, cell);
4533
+
4534
+ return LXW_NO_ERROR;
4535
+
4536
+ mem_error:
4537
+ lxw_styles_free(styles);
4538
+ lxw_format_free(default_format);
4539
+ fclose(tmpfile);
4540
+
4541
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
4542
+ }
4543
+
4301
4544
  /*
4302
4545
  * Set the properties of a single column or a range of columns with options.
4303
4546
  */
@@ -5234,10 +5477,11 @@ worksheet_protect(lxw_worksheet *self, const char *password,
5234
5477
  }
5235
5478
 
5236
5479
  if (password) {
5237
- uint16_t hash = _hash_password(password);
5480
+ uint16_t hash = lxw_hash_password(password);
5238
5481
  lxw_snprintf(protect->hash, 5, "%X", hash);
5239
5482
  }
5240
5483
 
5484
+ protect->no_content = LXW_TRUE;
5241
5485
  protect->is_configured = LXW_TRUE;
5242
5486
  }
5243
5487
 
@@ -5289,7 +5533,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5289
5533
  lxw_image_options *user_options)
5290
5534
  {
5291
5535
  FILE *image_stream;
5292
- char *short_name;
5536
+ char *description;
5293
5537
  lxw_image_options *options;
5294
5538
 
5295
5539
  if (!filename) {
@@ -5307,9 +5551,9 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5307
5551
  return LXW_ERROR_PARAMETER_VALIDATION;
5308
5552
  }
5309
5553
 
5310
- /* Get the filename from the full path to add to the Drawing object. */
5311
- short_name = lxw_basename(filename);
5312
- if (!short_name) {
5554
+ /* Use the filename as the default description, like Excel. */
5555
+ description = lxw_basename(filename);
5556
+ if (!description) {
5313
5557
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
5314
5558
  "couldn't get basename for file: %s.", filename);
5315
5559
  fclose(image_stream);
@@ -5332,7 +5576,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5332
5576
 
5333
5577
  /* Copy other options or set defaults. */
5334
5578
  options->filename = lxw_strdup(filename);
5335
- options->short_name = lxw_strdup(short_name);
5579
+ options->description = lxw_strdup(description);
5336
5580
  options->stream = image_stream;
5337
5581
  options->row = row_num;
5338
5582
  options->col = col_num;
@@ -5349,7 +5593,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5349
5593
  return LXW_NO_ERROR;
5350
5594
  }
5351
5595
  else {
5352
- free(options);
5596
+ _free_image_options(options);
5353
5597
  fclose(image_stream);
5354
5598
  return LXW_ERROR_IMAGE_DIMENSIONS;
5355
5599
  }
@@ -5366,6 +5610,95 @@ worksheet_insert_image(lxw_worksheet *self,
5366
5610
  return worksheet_insert_image_opt(self, row_num, col_num, filename, NULL);
5367
5611
  }
5368
5612
 
5613
+ lxw_error
5614
+ worksheet_insert_image_buffer_opt(lxw_worksheet *self,
5615
+ lxw_row_t row_num,
5616
+ lxw_col_t col_num,
5617
+ const unsigned char *image_buffer,
5618
+ size_t image_size,
5619
+ lxw_image_options *user_options)
5620
+ {
5621
+ FILE *image_stream;
5622
+ lxw_image_options *options;
5623
+
5624
+ if (!image_size) {
5625
+ LXW_WARN("worksheet_insert_image_buffer()/_opt(): "
5626
+ "size must be non-zero.");
5627
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
5628
+ }
5629
+
5630
+ /* Write the image buffer to a temporary file so we can read the
5631
+ * dimensions like an ordinary file. */
5632
+ image_stream = lxw_tmpfile(self->tmpdir);
5633
+ if (!image_stream)
5634
+ return LXW_ERROR_CREATING_TMPFILE;
5635
+
5636
+ fwrite(image_buffer, 1, image_size, image_stream);
5637
+ rewind(image_stream);
5638
+
5639
+ /* Create a new object to hold the image options. */
5640
+ options = calloc(1, sizeof(lxw_image_options));
5641
+ if (!options) {
5642
+ fclose(image_stream);
5643
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
5644
+ }
5645
+
5646
+ /* Store the image data in the options structure. */
5647
+ options->image_buffer = calloc(1, image_size);
5648
+ if (!options->image_buffer) {
5649
+ _free_image_options(options);
5650
+ fclose(image_stream);
5651
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
5652
+ }
5653
+ else {
5654
+ memcpy(options->image_buffer, image_buffer, image_size);
5655
+ options->image_buffer_size = image_size;
5656
+ options->is_image_buffer = LXW_TRUE;
5657
+ }
5658
+
5659
+ if (user_options) {
5660
+ options->x_offset = user_options->x_offset;
5661
+ options->y_offset = user_options->y_offset;
5662
+ options->x_scale = user_options->x_scale;
5663
+ options->y_scale = user_options->y_scale;
5664
+ options->description = lxw_strdup(user_options->description);
5665
+ }
5666
+
5667
+ /* Copy other options or set defaults. */
5668
+ options->filename = lxw_strdup("image_buffer");
5669
+ options->stream = image_stream;
5670
+ options->row = row_num;
5671
+ options->col = col_num;
5672
+
5673
+ if (!options->x_scale)
5674
+ options->x_scale = 1;
5675
+
5676
+ if (!options->y_scale)
5677
+ options->y_scale = 1;
5678
+
5679
+ if (_get_image_properties(options) == LXW_NO_ERROR) {
5680
+ STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
5681
+ fclose(image_stream);
5682
+ return LXW_NO_ERROR;
5683
+ }
5684
+ else {
5685
+ _free_image_options(options);
5686
+ fclose(image_stream);
5687
+ return LXW_ERROR_IMAGE_DIMENSIONS;
5688
+ }
5689
+ }
5690
+
5691
+ lxw_error
5692
+ worksheet_insert_image_buffer(lxw_worksheet *self,
5693
+ lxw_row_t row_num,
5694
+ lxw_col_t col_num,
5695
+ const unsigned char *image_buffer,
5696
+ size_t image_size)
5697
+ {
5698
+ return worksheet_insert_image_buffer_opt(self, row_num, col_num,
5699
+ image_buffer, image_size, NULL);
5700
+ }
5701
+
5369
5702
  /*
5370
5703
  * Insert an chart into the worksheet.
5371
5704
  */
@@ -5737,3 +6070,19 @@ worksheet_data_validation_cell(lxw_worksheet *self, lxw_row_t row,
5737
6070
  return worksheet_data_validation_range(self, row, col,
5738
6071
  row, col, validation);
5739
6072
  }
6073
+
6074
+ /*
6075
+ * Set the VBA name for the worksheet.
6076
+ */
6077
+ lxw_error
6078
+ worksheet_set_vba_name(lxw_worksheet *self, const char *name)
6079
+ {
6080
+ if (!name) {
6081
+ LXW_WARN("worksheet_set_vba_name(): " "name must be specified.");
6082
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
6083
+ }
6084
+
6085
+ self->vba_codename = lxw_strdup(name);
6086
+
6087
+ return LXW_NO_ERROR;
6088
+ }