xlsxwriter 0.0.5 → 0.0.6

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter.h +1 -1
  3. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chart.h +55 -5
  4. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
  5. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/common.h +6 -0
  6. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/content_types.h +2 -0
  7. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/drawing.h +1 -0
  8. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/format.h +1 -1
  9. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/shared_strings.h +3 -1
  10. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/styles.h +7 -2
  11. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/utility.h +16 -0
  12. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/workbook.h +122 -24
  13. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/worksheet.h +236 -48
  14. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/xmlwriter.h +2 -0
  15. data/ext/xlsxwriter/libxlsxwriter/src/chart.c +40 -4
  16. data/ext/xlsxwriter/libxlsxwriter/src/chartsheet.c +508 -0
  17. data/ext/xlsxwriter/libxlsxwriter/src/content_types.c +10 -0
  18. data/ext/xlsxwriter/libxlsxwriter/src/drawing.c +100 -3
  19. data/ext/xlsxwriter/libxlsxwriter/src/packager.c +252 -30
  20. data/ext/xlsxwriter/libxlsxwriter/src/shared_strings.c +16 -2
  21. data/ext/xlsxwriter/libxlsxwriter/src/styles.c +54 -7
  22. data/ext/xlsxwriter/libxlsxwriter/src/utility.c +43 -1
  23. data/ext/xlsxwriter/libxlsxwriter/src/workbook.c +254 -41
  24. data/ext/xlsxwriter/libxlsxwriter/src/worksheet.c +381 -65
  25. data/ext/xlsxwriter/libxlsxwriter/src/xmlwriter.c +16 -7
  26. data/ext/xlsxwriter/libxlsxwriter/third_party/minizip/ioapi.c +10 -0
  27. data/ext/xlsxwriter/libxlsxwriter/third_party/minizip/zip.c +2 -0
  28. data/ext/xlsxwriter/libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c +2 -2
  29. data/ext/xlsxwriter/workbook.c +9 -6
  30. data/lib/xlsxwriter/version.rb +1 -1
  31. metadata +5 -4
@@ -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
 
@@ -538,6 +537,26 @@ _new_inline_string_cell(lxw_row_t row_num,
538
537
  return cell;
539
538
  }
540
539
 
540
+ /*
541
+ * Create a new worksheet inline_string cell object for rich strings.
542
+ */
543
+ STATIC lxw_cell *
544
+ _new_inline_rich_string_cell(lxw_row_t row_num,
545
+ lxw_col_t col_num, char *string,
546
+ lxw_format *format)
547
+ {
548
+ lxw_cell *cell = calloc(1, sizeof(lxw_cell));
549
+ RETURN_ON_MEM_ERROR(cell, cell);
550
+
551
+ cell->row_num = row_num;
552
+ cell->col_num = col_num;
553
+ cell->type = INLINE_RICH_STRING_CELL;
554
+ cell->format = format;
555
+ cell->u.string = string;
556
+
557
+ return cell;
558
+ }
559
+
541
560
  /*
542
561
  * Create a new worksheet formula cell object.
543
562
  */
@@ -841,38 +860,6 @@ _cell_cmp(lxw_cell *cell1, lxw_cell *cell2)
841
860
  return 0;
842
861
  }
843
862
 
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
863
  /*
877
864
  * Simple replacement for libgen.h basename() for compatibility with MSVC. It
878
865
  * handles forward and back slashes. It doesn't copy exactly the return
@@ -2027,7 +2014,7 @@ lxw_worksheet_prepare_image(lxw_worksheet *self,
2027
2014
 
2028
2015
  drawing_object->anchor_type = LXW_ANCHOR_TYPE_IMAGE;
2029
2016
  drawing_object->edit_as = LXW_ANCHOR_EDIT_AS_ONE_CELL;
2030
- drawing_object->description = lxw_strdup(image_data->short_name);
2017
+ drawing_object->description = lxw_strdup(image_data->description);
2031
2018
 
2032
2019
  /* Scale to user scale. */
2033
2020
  width = image_data->width * image_data->x_scale;
@@ -2079,8 +2066,10 @@ mem_error:
2079
2066
  */
2080
2067
  void
2081
2068
  lxw_worksheet_prepare_chart(lxw_worksheet *self,
2082
- uint16_t chart_ref_id, uint16_t drawing_id,
2083
- lxw_image_options *image_data)
2069
+ uint16_t chart_ref_id,
2070
+ uint16_t drawing_id,
2071
+ lxw_image_options *image_data,
2072
+ uint8_t is_chartsheet)
2084
2073
  {
2085
2074
  lxw_drawing_object *drawing_object;
2086
2075
  lxw_rel_tuple *relationship;
@@ -2090,9 +2079,16 @@ lxw_worksheet_prepare_chart(lxw_worksheet *self,
2090
2079
 
2091
2080
  if (!self->drawing) {
2092
2081
  self->drawing = lxw_drawing_new();
2093
- self->drawing->embedded = LXW_TRUE;
2094
2082
  RETURN_VOID_ON_MEM_ERROR(self->drawing);
2095
2083
 
2084
+ if (is_chartsheet) {
2085
+ self->drawing->embedded = LXW_FALSE;
2086
+ self->drawing->orientation = self->orientation;
2087
+ }
2088
+ else {
2089
+ self->drawing->embedded = LXW_TRUE;
2090
+ }
2091
+
2096
2092
  relationship = calloc(1, sizeof(lxw_rel_tuple));
2097
2093
  GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
2098
2094
 
@@ -2259,8 +2255,7 @@ _process_png(lxw_image_options *image_options)
2259
2255
 
2260
2256
  file_error:
2261
2257
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2262
- "no size data found in file: %s.",
2263
- image_options->filename);
2258
+ "no size data found in: %s.", image_options->filename);
2264
2259
 
2265
2260
  return LXW_ERROR_IMAGE_DIMENSIONS;
2266
2261
  }
@@ -2386,8 +2381,7 @@ _process_jpeg(lxw_image_options *image_options)
2386
2381
 
2387
2382
  file_error:
2388
2383
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2389
- "no size data found in file: %s.",
2390
- image_options->filename);
2384
+ "no size data found in: %s.", image_options->filename);
2391
2385
 
2392
2386
  return LXW_ERROR_IMAGE_DIMENSIONS;
2393
2387
  }
@@ -2436,8 +2430,7 @@ _process_bmp(lxw_image_options *image_options)
2436
2430
 
2437
2431
  file_error:
2438
2432
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2439
- "no size data found in file: %s.",
2440
- image_options->filename);
2433
+ "no size data found in: %s.", image_options->filename);
2441
2434
 
2442
2435
  return LXW_ERROR_IMAGE_DIMENSIONS;
2443
2436
  }
@@ -2454,7 +2447,7 @@ _get_image_properties(lxw_image_options *image_options)
2454
2447
  /* Read 4 bytes to look for the file header/signature. */
2455
2448
  if (fread(signature, 1, 4, image_options->stream) < 4) {
2456
2449
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2457
- "couldn't read file type for file: %s.",
2450
+ "couldn't read image type for: %s.",
2458
2451
  image_options->filename);
2459
2452
  return LXW_ERROR_IMAGE_DIMENSIONS;
2460
2453
  }
@@ -2473,7 +2466,7 @@ _get_image_properties(lxw_image_options *image_options)
2473
2466
  }
2474
2467
  else {
2475
2468
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
2476
- "unsupported image format for file: %s.",
2469
+ "unsupported image format for: %s.",
2477
2470
  image_options->filename);
2478
2471
  return LXW_ERROR_IMAGE_DIMENSIONS;
2479
2472
  }
@@ -2576,6 +2569,41 @@ _write_inline_string_cell(lxw_worksheet *self, char *range,
2576
2569
  free(string);
2577
2570
  }
2578
2571
 
2572
+ /*
2573
+ * Write out an inline rich string. Doesn't use the xml functions as an
2574
+ * optimization in the inner cell writing loop.
2575
+ */
2576
+ STATIC void
2577
+ _write_inline_rich_string_cell(lxw_worksheet *self, char *range,
2578
+ int32_t style_index, lxw_cell *cell)
2579
+ {
2580
+ char *string = cell->u.string;
2581
+
2582
+ /* Add attribute to preserve leading or trailing whitespace. */
2583
+ if (isspace((unsigned char) string[0])
2584
+ || isspace((unsigned char) string[strlen(string) - 1])) {
2585
+
2586
+ if (style_index)
2587
+ fprintf(self->file,
2588
+ "<c r=\"%s\" s=\"%d\" t=\"inlineStr\"><is>%s</is></c>",
2589
+ range, style_index, string);
2590
+ else
2591
+ fprintf(self->file,
2592
+ "<c r=\"%s\" t=\"inlineStr\"><is>%s</is></c>",
2593
+ range, string);
2594
+ }
2595
+ else {
2596
+ if (style_index)
2597
+ fprintf(self->file,
2598
+ "<c r=\"%s\" s=\"%d\" t=\"inlineStr\">"
2599
+ "<is>%s</is></c>", range, style_index, string);
2600
+ else
2601
+ fprintf(self->file,
2602
+ "<c r=\"%s\" t=\"inlineStr\">"
2603
+ "<is>%s</is></c>", range, string);
2604
+ }
2605
+ }
2606
+
2579
2607
  /*
2580
2608
  * Write out a formula worksheet cell with a numeric result.
2581
2609
  */
@@ -2712,6 +2740,11 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
2712
2740
  return;
2713
2741
  }
2714
2742
 
2743
+ if (cell->type == INLINE_RICH_STRING_CELL) {
2744
+ _write_inline_rich_string_cell(self, range, style_index, cell);
2745
+ return;
2746
+ }
2747
+
2715
2748
  /* For other cell types use the general functions. */
2716
2749
  LXW_INIT_ATTRIBUTES();
2717
2750
  LXW_PUSH_ATTRIBUTES_STR("r", range);
@@ -3093,7 +3126,8 @@ _worksheet_write_sheet_pr(lxw_worksheet *self)
3093
3126
  if (!self->fit_page
3094
3127
  && !self->filter_on
3095
3128
  && self->tab_color == LXW_COLOR_UNSET
3096
- && !self->outline_changed && !self->vba_codename) {
3129
+ && !self->outline_changed
3130
+ && !self->vba_codename && !self->is_chartsheet) {
3097
3131
  return;
3098
3132
  }
3099
3133
 
@@ -3364,13 +3398,12 @@ mem_error:
3364
3398
  * Write the <sheetProtection> element.
3365
3399
  */
3366
3400
  STATIC void
3367
- _worksheet_write_sheet_protection(lxw_worksheet *self)
3401
+ _worksheet_write_sheet_protection(lxw_worksheet *self,
3402
+ lxw_protection *protect)
3368
3403
  {
3369
3404
  struct xml_attribute_list attributes;
3370
3405
  struct xml_attribute *attribute;
3371
3406
 
3372
- struct lxw_protection *protect = &self->protection;
3373
-
3374
3407
  if (!protect->is_configured)
3375
3408
  return;
3376
3409
 
@@ -3382,7 +3415,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
3382
3415
  if (!protect->no_sheet)
3383
3416
  LXW_PUSH_ATTRIBUTES_INT("sheet", 1);
3384
3417
 
3385
- if (protect->content)
3418
+ if (!protect->no_content)
3386
3419
  LXW_PUSH_ATTRIBUTES_INT("content", 1);
3387
3420
 
3388
3421
  if (!protect->objects)
@@ -3439,7 +3472,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
3439
3472
  * Write the <drawing> element.
3440
3473
  */
3441
3474
  STATIC void
3442
- _write_drawing(lxw_worksheet *self, uint16_t id)
3475
+ _worksheet_write_drawing(lxw_worksheet *self, uint16_t id)
3443
3476
  {
3444
3477
  struct xml_attribute_list attributes;
3445
3478
  struct xml_attribute *attribute;
@@ -3461,14 +3494,14 @@ _write_drawing(lxw_worksheet *self, uint16_t id)
3461
3494
  * Write the <drawing> elements.
3462
3495
  */
3463
3496
  STATIC void
3464
- _write_drawings(lxw_worksheet *self)
3497
+ _worksheet_write_drawings(lxw_worksheet *self)
3465
3498
  {
3466
3499
  if (!self->drawing)
3467
3500
  return;
3468
3501
 
3469
3502
  self->rel_count++;
3470
3503
 
3471
- _write_drawing(self, self->rel_count);
3504
+ _worksheet_write_drawing(self, self->rel_count);
3472
3505
  }
3473
3506
 
3474
3507
  /*
@@ -3689,6 +3722,52 @@ _worksheet_write_data_validations(lxw_worksheet *self)
3689
3722
  LXW_FREE_ATTRIBUTES();
3690
3723
  }
3691
3724
 
3725
+ /*
3726
+ * External functions to call intern XML methods shared with chartsheet.
3727
+ */
3728
+ void
3729
+ lxw_worksheet_write_sheet_views(lxw_worksheet *self)
3730
+ {
3731
+ _worksheet_write_sheet_views(self);
3732
+ }
3733
+
3734
+ void
3735
+ lxw_worksheet_write_page_margins(lxw_worksheet *self)
3736
+ {
3737
+ _worksheet_write_page_margins(self);
3738
+ }
3739
+
3740
+ void
3741
+ lxw_worksheet_write_drawings(lxw_worksheet *self)
3742
+ {
3743
+ _worksheet_write_drawings(self);
3744
+ }
3745
+
3746
+ void
3747
+ lxw_worksheet_write_sheet_protection(lxw_worksheet *self,
3748
+ lxw_protection *protect)
3749
+ {
3750
+ _worksheet_write_sheet_protection(self, protect);
3751
+ }
3752
+
3753
+ void
3754
+ lxw_worksheet_write_sheet_pr(lxw_worksheet *self)
3755
+ {
3756
+ _worksheet_write_sheet_pr(self);
3757
+ }
3758
+
3759
+ void
3760
+ lxw_worksheet_write_page_setup(lxw_worksheet *self)
3761
+ {
3762
+ _worksheet_write_page_setup(self);
3763
+ }
3764
+
3765
+ void
3766
+ lxw_worksheet_write_header_footer(lxw_worksheet *self)
3767
+ {
3768
+ _worksheet_write_header_footer(self);
3769
+ }
3770
+
3692
3771
  /*
3693
3772
  * Assemble and write the XML file.
3694
3773
  */
@@ -3723,7 +3802,7 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
3723
3802
  _worksheet_write_optimized_sheet_data(self);
3724
3803
 
3725
3804
  /* Write the sheetProtection element. */
3726
- _worksheet_write_sheet_protection(self);
3805
+ _worksheet_write_sheet_protection(self, &self->protection);
3727
3806
 
3728
3807
  /* Write the autoFilter element. */
3729
3808
  _worksheet_write_auto_filter(self);
@@ -3756,7 +3835,7 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
3756
3835
  _worksheet_write_col_breaks(self);
3757
3836
 
3758
3837
  /* Write the drawing element. */
3759
- _write_drawings(self);
3838
+ _worksheet_write_drawings(self);
3760
3839
 
3761
3840
  /* Close the worksheet tag. */
3762
3841
  lxw_xml_end_tag(self->file, "worksheet");
@@ -3823,7 +3902,7 @@ worksheet_write_string(lxw_worksheet *self,
3823
3902
 
3824
3903
  if (!self->optimize) {
3825
3904
  /* Get the SST element and string id. */
3826
- sst_element = lxw_get_sst_index(self->sst, string);
3905
+ sst_element = lxw_get_sst_index(self->sst, string, LXW_FALSE);
3827
3906
 
3828
3907
  if (!sst_element)
3829
3908
  return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
@@ -4298,6 +4377,156 @@ worksheet_write_url(lxw_worksheet *self,
4298
4377
  NULL);
4299
4378
  }
4300
4379
 
4380
+ /*
4381
+ * Write a rich string to an Excel file.
4382
+ *
4383
+ * Rather than duplicate several of the styles.c font xml methods of styles.c
4384
+ * and write the data to a memory buffer this function creates a temporary
4385
+ * styles object and uses it to write the data to a file. It then reads that
4386
+ * data back into memory and closes the file.
4387
+ */
4388
+ lxw_error
4389
+ worksheet_write_rich_string(lxw_worksheet *self,
4390
+ lxw_row_t row_num,
4391
+ lxw_col_t col_num,
4392
+ lxw_rich_string_tuple *rich_strings[],
4393
+ lxw_format *format)
4394
+ {
4395
+ lxw_cell *cell;
4396
+ int32_t string_id;
4397
+ struct sst_element *sst_element;
4398
+ lxw_error err;
4399
+ uint8_t i;
4400
+ long file_size;
4401
+ char *rich_string = NULL;
4402
+ char *string_copy = NULL;
4403
+ lxw_styles *styles = NULL;
4404
+ lxw_format *default_format = NULL;
4405
+ lxw_rich_string_tuple *rich_string_tuple = NULL;
4406
+ FILE *tmpfile;
4407
+
4408
+ err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
4409
+ if (err)
4410
+ return err;
4411
+
4412
+ /* Iterate through rich string fragments to check for input errors. */
4413
+ i = 0;
4414
+ err = LXW_NO_ERROR;
4415
+ while ((rich_string_tuple = rich_strings[i++]) != NULL) {
4416
+
4417
+ /* Check for NULL or empty strings. */
4418
+ if (!rich_string_tuple->string || !*rich_string_tuple->string) {
4419
+ err = LXW_ERROR_PARAMETER_VALIDATION;
4420
+ }
4421
+ }
4422
+
4423
+ /* If there are less than 2 fragments it isn't a rich string. */
4424
+ if (i <= 2)
4425
+ err = LXW_ERROR_PARAMETER_VALIDATION;
4426
+
4427
+ if (err)
4428
+ return err;
4429
+
4430
+ /* Create a tmp file for the styles object. */
4431
+ tmpfile = lxw_tmpfile(self->tmpdir);
4432
+ if (!tmpfile)
4433
+ return LXW_ERROR_CREATING_TMPFILE;
4434
+
4435
+ /* Create a temp styles object for writing the font data. */
4436
+ styles = lxw_styles_new();
4437
+ GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
4438
+ styles->file = tmpfile;
4439
+
4440
+ /* Create a default format for non-formatted text. */
4441
+ default_format = lxw_format_new();
4442
+ GOTO_LABEL_ON_MEM_ERROR(default_format, mem_error);
4443
+
4444
+ /* Iterate through the rich string fragments and write each one out. */
4445
+ i = 0;
4446
+ while ((rich_string_tuple = rich_strings[i++]) != NULL) {
4447
+ lxw_xml_start_tag(tmpfile, "r", NULL);
4448
+
4449
+ if (rich_string_tuple->format) {
4450
+ /* Write the user defined font format. */
4451
+ lxw_styles_write_rich_font(styles, rich_string_tuple->format);
4452
+ }
4453
+ else {
4454
+ /* Write a default font format. Except for the first fragment. */
4455
+ if (i > 1)
4456
+ lxw_styles_write_rich_font(styles, default_format);
4457
+ }
4458
+
4459
+ lxw_styles_write_string_fragment(styles, rich_string_tuple->string);
4460
+ lxw_xml_end_tag(tmpfile, "r");
4461
+ }
4462
+
4463
+ /* Free the temp objects. */
4464
+ lxw_styles_free(styles);
4465
+ lxw_format_free(default_format);
4466
+
4467
+ /* Flush the file and read the size to calculate the required memory. */
4468
+ fflush(tmpfile);
4469
+ file_size = ftell(tmpfile);
4470
+
4471
+ /* Allocate a buffer for the rich string xml data. */
4472
+ rich_string = calloc(file_size + 1, 1);
4473
+ GOTO_LABEL_ON_MEM_ERROR(rich_string, mem_error);
4474
+
4475
+ /* Rewind the file and read the data into the memory buffer. */
4476
+ rewind(tmpfile);
4477
+ if (fread(rich_string, file_size, 1, tmpfile) < 1) {
4478
+ fclose(tmpfile);
4479
+ free(rich_string);
4480
+ return LXW_ERROR_READING_TMPFILE;
4481
+ }
4482
+
4483
+ /* Close the temp file. */
4484
+ fclose(tmpfile);
4485
+
4486
+ if (lxw_utf8_strlen(rich_string) > LXW_STR_MAX) {
4487
+ free(rich_string);
4488
+ return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;
4489
+ }
4490
+
4491
+ if (!self->optimize) {
4492
+ /* Get the SST element and string id. */
4493
+ sst_element = lxw_get_sst_index(self->sst, rich_string, LXW_TRUE);
4494
+ free(rich_string);
4495
+
4496
+ if (!sst_element)
4497
+ return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
4498
+
4499
+ string_id = sst_element->index;
4500
+ cell = _new_string_cell(row_num, col_num, string_id,
4501
+ sst_element->string, format);
4502
+ }
4503
+ else {
4504
+ /* Look for and escape control chars in the string. */
4505
+ if (strpbrk(rich_string, "\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C"
4506
+ "\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"
4507
+ "\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")) {
4508
+ string_copy = lxw_escape_control_characters(rich_string);
4509
+ free(rich_string);
4510
+ }
4511
+ else {
4512
+ string_copy = rich_string;
4513
+ }
4514
+ cell = _new_inline_rich_string_cell(row_num, col_num, string_copy,
4515
+ format);
4516
+ }
4517
+
4518
+ _insert_cell(self, row_num, col_num, cell);
4519
+
4520
+ return LXW_NO_ERROR;
4521
+
4522
+ mem_error:
4523
+ lxw_styles_free(styles);
4524
+ lxw_format_free(default_format);
4525
+ fclose(tmpfile);
4526
+
4527
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
4528
+ }
4529
+
4301
4530
  /*
4302
4531
  * Set the properties of a single column or a range of columns with options.
4303
4532
  */
@@ -5234,10 +5463,11 @@ worksheet_protect(lxw_worksheet *self, const char *password,
5234
5463
  }
5235
5464
 
5236
5465
  if (password) {
5237
- uint16_t hash = _hash_password(password);
5466
+ uint16_t hash = lxw_hash_password(password);
5238
5467
  lxw_snprintf(protect->hash, 5, "%X", hash);
5239
5468
  }
5240
5469
 
5470
+ protect->no_content = LXW_TRUE;
5241
5471
  protect->is_configured = LXW_TRUE;
5242
5472
  }
5243
5473
 
@@ -5289,7 +5519,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5289
5519
  lxw_image_options *user_options)
5290
5520
  {
5291
5521
  FILE *image_stream;
5292
- char *short_name;
5522
+ char *description;
5293
5523
  lxw_image_options *options;
5294
5524
 
5295
5525
  if (!filename) {
@@ -5307,9 +5537,9 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5307
5537
  return LXW_ERROR_PARAMETER_VALIDATION;
5308
5538
  }
5309
5539
 
5310
- /* Get the filename from the full path to add to the Drawing object. */
5311
- short_name = lxw_basename(filename);
5312
- if (!short_name) {
5540
+ /* Use the filename as the default description, like Excel. */
5541
+ description = lxw_basename(filename);
5542
+ if (!description) {
5313
5543
  LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
5314
5544
  "couldn't get basename for file: %s.", filename);
5315
5545
  fclose(image_stream);
@@ -5332,7 +5562,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5332
5562
 
5333
5563
  /* Copy other options or set defaults. */
5334
5564
  options->filename = lxw_strdup(filename);
5335
- options->short_name = lxw_strdup(short_name);
5565
+ options->description = lxw_strdup(description);
5336
5566
  options->stream = image_stream;
5337
5567
  options->row = row_num;
5338
5568
  options->col = col_num;
@@ -5349,7 +5579,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
5349
5579
  return LXW_NO_ERROR;
5350
5580
  }
5351
5581
  else {
5352
- free(options);
5582
+ _free_image_options(options);
5353
5583
  fclose(image_stream);
5354
5584
  return LXW_ERROR_IMAGE_DIMENSIONS;
5355
5585
  }
@@ -5366,6 +5596,92 @@ worksheet_insert_image(lxw_worksheet *self,
5366
5596
  return worksheet_insert_image_opt(self, row_num, col_num, filename, NULL);
5367
5597
  }
5368
5598
 
5599
+ lxw_error
5600
+ worksheet_insert_image_buffer_opt(lxw_worksheet *self,
5601
+ lxw_row_t row_num,
5602
+ lxw_col_t col_num,
5603
+ const unsigned char *image_buffer,
5604
+ size_t image_size,
5605
+ lxw_image_options *user_options)
5606
+ {
5607
+ FILE *image_stream;
5608
+ lxw_image_options *options;
5609
+
5610
+ if (!image_size) {
5611
+ LXW_WARN("worksheet_insert_image_buffer()/_opt(): "
5612
+ "size must be non-zero.");
5613
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
5614
+ }
5615
+
5616
+ /* Write the image buffer to a temporary file so we can read the
5617
+ * dimensions like an ordinary file. */
5618
+ image_stream = lxw_tmpfile(self->tmpdir);
5619
+ fwrite(image_buffer, 1, image_size, image_stream);
5620
+ rewind(image_stream);
5621
+
5622
+ /* Create a new object to hold the image options. */
5623
+ options = calloc(1, sizeof(lxw_image_options));
5624
+ if (!options) {
5625
+ fclose(image_stream);
5626
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
5627
+ }
5628
+
5629
+ /* Store the image data in the options structure. */
5630
+ options->image_buffer = calloc(1, image_size);
5631
+ if (!options->image_buffer) {
5632
+ _free_image_options(options);
5633
+ fclose(image_stream);
5634
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
5635
+ }
5636
+ else {
5637
+ memcpy(options->image_buffer, image_buffer, image_size);
5638
+ options->image_buffer_size = image_size;
5639
+ options->is_image_buffer = LXW_TRUE;
5640
+ }
5641
+
5642
+ if (user_options) {
5643
+ options->x_offset = user_options->x_offset;
5644
+ options->y_offset = user_options->y_offset;
5645
+ options->x_scale = user_options->x_scale;
5646
+ options->y_scale = user_options->y_scale;
5647
+ options->description = lxw_strdup(user_options->description);
5648
+ }
5649
+
5650
+ /* Copy other options or set defaults. */
5651
+ options->filename = lxw_strdup("image_buffer");
5652
+ options->stream = image_stream;
5653
+ options->row = row_num;
5654
+ options->col = col_num;
5655
+
5656
+ if (!options->x_scale)
5657
+ options->x_scale = 1;
5658
+
5659
+ if (!options->y_scale)
5660
+ options->y_scale = 1;
5661
+
5662
+ if (_get_image_properties(options) == LXW_NO_ERROR) {
5663
+ STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
5664
+ fclose(image_stream);
5665
+ return LXW_NO_ERROR;
5666
+ }
5667
+ else {
5668
+ _free_image_options(options);
5669
+ fclose(image_stream);
5670
+ return LXW_ERROR_IMAGE_DIMENSIONS;
5671
+ }
5672
+ }
5673
+
5674
+ lxw_error
5675
+ worksheet_insert_image_buffer(lxw_worksheet *self,
5676
+ lxw_row_t row_num,
5677
+ lxw_col_t col_num,
5678
+ const unsigned char *image_buffer,
5679
+ size_t image_size)
5680
+ {
5681
+ return worksheet_insert_image_buffer_opt(self, row_num, col_num,
5682
+ image_buffer, image_size, NULL);
5683
+ }
5684
+
5369
5685
  /*
5370
5686
  * Insert an chart into the worksheet.
5371
5687
  */