Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 2004--2020 Han-Wen Nienhuys <hanwen@xs4all.nl> | 4 Copyright (C) 2004--2020 Han-Wen Nienhuys <hanwen@xs4all.nl> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 6 LilyPond is free software: you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
8 the Free Software Foundation, either version 3 of the License, or | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
373 | 373 |
374 // Skip `checkSum`, `offset` and `length` | 374 // Skip `checkSum`, `offset` and `length` |
375 fseek (fp, 12, SEEK_CUR); | 375 fseek (fp, 12, SEEK_CUR); |
376 } | 376 } |
377 | 377 |
378 fclose (fp); | 378 fclose (fp); |
379 warning (_f ("font `%s' index %d does not have `CFF' table", | 379 warning (_f ("font `%s' index %d does not have `CFF' table", |
380 file_name.c_str (), i)); | 380 file_name.c_str (), i)); |
381 return SCM_BOOL_F; | 381 return SCM_BOOL_F; |
382 } | 382 } |
383 | |
384 LY_DEFINE (ly_extract_subfont_from_collection, | |
385 "ly:extract-subfont-from-collection", | |
386 3, 0, 0, (SCM collection_file_name, SCM idx, SCM subfont_file_name), | |
387 "Extract the subfont of index @var{idx} in" | |
388 " TrueType collection (TTC) or OpenType/CFF collection (OTC) file" | |
389 " @var{collection_file_name} and write it to file" | |
390 " @var{subfont_file_name}.") | |
391 { | |
392 LY_ASSERT_TYPE (scm_is_string, collection_file_name, 1); | |
393 LY_ASSERT_TYPE (scm_is_integer, idx, 2); | |
394 LY_ASSERT_TYPE (scm_is_string, subfont_file_name, 3); | |
395 | |
396 int i = scm_to_int (idx); | |
397 if (i < 0) | |
398 { | |
399 warning (_ ("font index must be non-negative, using index 0")); | |
400 i = 0; | |
401 } | |
402 | |
403 std::string collection = ly_scm2string (collection_file_name); | |
404 std::string subfont = ly_scm2string (subfont_file_name); | |
405 | |
406 FILE *fi = fopen (collection.c_str (), "rb"); | |
407 if (!fi) | |
408 { | |
409 warning (_f ("font `%s': cannot open for reading", | |
410 collection.c_str ())); | |
411 return SCM_BOOL_F; | |
412 } | |
413 | |
414 char buff[4]; | |
415 | |
416 // Read `ttcTag` | |
417 if (fread (buff, 4, 1, fi) != 1) | |
418 { | |
419 fclose (fi); | |
420 warning (_f ("font `%s': cannot read `%s' field", | |
421 collection.c_str (), "ttcTag")); | |
422 return SCM_BOOL_F; | |
423 } | |
424 | |
425 if (!(buff[0] == 't' && buff[1] == 't' && buff[2] == 'c' && buff[3] == 'f')) | |
426 { | |
427 fclose (fi); | |
428 warning (_f ("font `%s': not a font collection", | |
429 collection.c_str ())); | |
430 return SCM_BOOL_F; | |
431 } | |
432 | |
433 // Read `majorVersion` and `minorVersion` | |
434 if (fread (buff, 4, 1, fi) != 1) | |
435 { | |
436 fclose (fi); | |
437 warning (_f ("font `%s': cannot read `%s' field", | |
438 collection.c_str (), "majorVersion/minorVersion")); | |
439 return SCM_BOOL_F; | |
440 } | |
441 | |
442 if (!(buff[0] == 0 && buff[2] == 0 && buff[3] == 0 | |
443 && (buff[1] == 1 || buff[1] == 2))) | |
444 { | |
445 fclose (fi); | |
446 warning (_f ("font `%s': invalid TTC header version", | |
447 collection.c_str ())); | |
448 return SCM_BOOL_F; | |
449 } | |
450 | |
451 // Read `numFonts` | |
452 if (fread (buff, 4, 1, fi) != 1) | |
453 { | |
454 fclose (fi); | |
455 warning (_f ("font `%s': cannot read `%s' field", | |
456 collection.c_str (), "numFonts")); | |
457 return SCM_BOOL_F; | |
458 } | |
459 int numfonts | |
460 = static_cast<unsigned char>(buff[0]) << 24 | |
461 | static_cast<unsigned char>(buff[1]) << 16 | |
462 | static_cast<unsigned char>(buff[2]) << 8 | |
463 | static_cast<unsigned char>(buff[3]); | |
464 | |
465 if ( i > numfonts) | |
466 { | |
467 warning (_f ("font index %d too large for font `%s', using index 0", | |
lemzwerg
2020/05/04 04:33:59
Maybe it makes sense to use a format like
font
trueroad
2020/05/04 05:45:22
Done.
| |
468 i, collection.c_str ())); | |
469 i = 0; | |
470 } | |
471 | |
472 // Read `offsetTable[i]` | |
473 if (i) | |
474 fseek (fi, i * 4, SEEK_CUR); | |
475 if (fread (buff, 4, 1, fi) != 1) | |
476 { | |
477 fclose (fi); | |
478 warning (_f ("font `%s': cannot read offset of subfont %d", | |
479 collection.c_str (), i)); | |
480 return SCM_BOOL_F; | |
481 } | |
482 unsigned int offset | |
483 = static_cast<unsigned char>(buff[0]) << 24 | |
484 | static_cast<unsigned char>(buff[1]) << 16 | |
485 | static_cast<unsigned char>(buff[2]) << 8 | |
486 | static_cast<unsigned char>(buff[3]); | |
487 | |
488 // Seek to subfont | |
489 fseek (fi, offset, SEEK_SET); | |
490 | |
491 // Read `sfntVersion` | |
492 if (fread (buff, 4, 1, fi) != 1) | |
493 { | |
494 fclose (fi); | |
495 warning (_f ("font `%s': cannot read `%s' field of subfont %d", | |
lemzwerg
2020/05/04 04:33:59
Shall we do
s/`%s' field/field `%s'/
here and
trueroad
2020/05/04 05:45:22
Done.
| |
496 collection.c_str (), "sfntVersion", i)); | |
497 return SCM_BOOL_F; | |
498 } | |
499 | |
500 if (!(buff[0] == 0 && buff[1] == 1 && buff[2] == 0 && buff[3] == 0) && | |
501 !(buff[0] == 'O' && buff[1] == 'T' && buff[2] == 'T' && buff[3] == 'O')) | |
502 { | |
503 fclose (fi); | |
504 warning (_f ("font `%s': invalid `sfntVersion' field in subfont %d", | |
505 collection.c_str (), i)); | |
506 return SCM_BOOL_F; | |
507 } | |
508 | |
509 FILE *fo = fopen (subfont.c_str (), "wb"); | |
510 if (!fo) | |
511 { | |
512 fclose (fi); | |
513 warning (_f ("font `%s': cannot open for writing", | |
lemzwerg
2020/05/04 04:33:59
Shall we replace `font' with `subfont' here and in
trueroad
2020/05/04 05:45:23
Done.
| |
514 subfont.c_str ())); | |
515 return SCM_BOOL_F; | |
516 } | |
517 | |
518 // Write `sfntVersion` | |
519 if (fwrite (buff, 4, 1, fo) != 1) | |
520 { | |
521 fclose (fi); | |
522 fclose (fo); | |
523 warning (_f ("font `%s': cannot write `%s' field", | |
524 subfont.c_str (), "sfntVersion")); | |
525 return SCM_BOOL_F; | |
526 } | |
527 | |
528 // Read `numTables` and `searchRange` | |
529 if (fread (buff, 4, 1, fi) != 1) | |
530 { | |
531 fclose (fi); | |
532 fclose (fo); | |
533 warning (_f ("font `%s': cannot read `%s' field of subfont %d", | |
534 collection.c_str (), "numTables/searchRange", i)); | |
535 return SCM_BOOL_F; | |
536 } | |
537 unsigned int numtables | |
538 = static_cast<unsigned char>(buff[0]) << 8 | |
539 | static_cast<unsigned char>(buff[1]); | |
540 | |
541 // Write `numTables` and `searchRange` | |
542 if (fwrite (buff, 4, 1, fo) != 1) | |
543 { | |
544 fclose (fi); | |
545 fclose (fo); | |
546 warning (_f ("font `%s': cannot write `%s' field", | |
547 subfont.c_str (), "numTables/searchRange")); | |
548 return SCM_BOOL_F; | |
549 } | |
550 | |
551 // Read `entrySelector` and `rangeShift` | |
552 if (fread (buff, 4, 1, fi) != 1) | |
553 { | |
554 fclose (fi); | |
555 fclose (fo); | |
556 warning (_f ("font `%s': cannot read `%s' field of subfont %d", | |
557 collection.c_str (), "entrySelector/rangeShift", i)); | |
558 return SCM_BOOL_F; | |
559 } | |
560 | |
561 // Write `entrySelector` and `rangeShift` | |
562 if (fwrite (buff, 4, 1, fo) != 1) | |
563 { | |
564 fclose (fi); | |
565 fclose (fo); | |
566 warning (_f ("font `%s': cannot write `%s' field", | |
567 subfont.c_str (), "entrySelector/rangeShift")); | |
568 return SCM_BOOL_F; | |
569 } | |
570 | |
571 struct tables | |
572 { | |
573 char tag[5]; | |
574 unsigned int offset; | |
575 unsigned int length; | |
576 unsigned int new_offset; | |
577 }; | |
578 std::vector<struct tables> ttcotc_tables; | |
579 | |
580 unsigned int next_offset = static_cast<unsigned int> (ftell (fo)) | |
581 + numtables * 16; | |
582 | |
583 // Copy and modify table records | |
584 for (unsigned int t = 0; t < numtables; t++) | |
585 { | |
586 struct tables tbl; | |
587 | |
588 // Read `tableTag` | |
589 if (fread (buff, 4, 1, fi) != 1) | |
590 { | |
591 fclose (fi); | |
592 fclose (fo); | |
593 warning (_f ("font `%s': cannot read `%s' field for" | |
594 " table no. %u of subfont %d", | |
lemzwerg
2020/05/04 04:33:59
s/table no. %u/table %u/
trueroad
2020/05/04 05:45:22
Done.
| |
595 collection.c_str (), "tableTag", t + 1, i)); | |
596 return SCM_BOOL_F; | |
597 } | |
598 tbl.tag[0]=buff[0]; | |
599 tbl.tag[1]=buff[1]; | |
600 tbl.tag[2]=buff[2]; | |
601 tbl.tag[3]=buff[3]; | |
602 tbl.tag[4]=0; | |
603 // Write `tableTag` | |
604 if (fwrite (buff, 4, 1, fo) != 1) | |
605 { | |
606 fclose (fi); | |
607 fclose (fo); | |
608 warning (_f ("font `%s': cannot write `%s' field for `%s' table", | |
609 subfont.c_str (), "tableTag", tbl.tag)); | |
610 return SCM_BOOL_F; | |
611 } | |
612 | |
613 // Read `checkSum` | |
614 if (fread (buff, 4, 1, fi) != 1) | |
615 { | |
616 fclose (fi); | |
617 fclose (fo); | |
618 warning (_f ("font `%s': cannot read `%s' field for" | |
619 " `%s' table of subfont %d", | |
620 collection.c_str (), "checkSum", tbl.tag, i)); | |
621 return SCM_BOOL_F; | |
622 } | |
623 // Write `checkSum` | |
624 if (fwrite (buff, 4, 1, fo) != 1) | |
625 { | |
626 fclose (fi); | |
627 fclose (fo); | |
628 warning (_f ("font `%s': cannot write `%s' field for `%s' table", | |
629 subfont.c_str (), "checkSum", tbl.tag)); | |
630 return SCM_BOOL_F; | |
631 } | |
632 | |
633 // Read `offset` | |
634 if (fread (buff, 4, 1, fi) != 1) | |
635 { | |
636 fclose (fi); | |
637 fclose (fo); | |
638 warning (_f ("font `%s': cannot read `%s' field for" | |
639 " `%s' table of subfont %d", | |
640 collection.c_str (), "offset", tbl.tag, i)); | |
641 return SCM_BOOL_F; | |
642 } | |
643 tbl.offset | |
644 = static_cast<unsigned char>(buff[0]) << 24 | |
645 | static_cast<unsigned char>(buff[1]) << 16 | |
646 | static_cast<unsigned char>(buff[2]) << 8 | |
647 | static_cast<unsigned char>(buff[3]); | |
648 tbl.new_offset = next_offset; | |
649 buff[0] = static_cast<char> ((tbl.new_offset >> 24) & 0xff); | |
650 buff[1] = static_cast<char> ((tbl.new_offset >> 16) & 0xff); | |
651 buff[2] = static_cast<char> ((tbl.new_offset >> 8) & 0xff); | |
652 buff[3] = static_cast<char> (tbl.new_offset & 0xff); | |
653 // Write `offset` | |
654 if (fwrite (buff, 4, 1, fo) != 1) | |
655 { | |
656 fclose (fi); | |
657 fclose (fo); | |
658 warning (_f ("font `%s': cannot write `%s' field for `%s' table", | |
659 subfont.c_str (), "offset", tbl.tag)); | |
660 return SCM_BOOL_F; | |
661 } | |
662 | |
663 // Read `length` | |
664 if (fread (buff, 4, 1, fi) != 1) | |
665 { | |
666 fclose (fi); | |
667 fclose (fo); | |
668 warning (_f ("font `%s': cannot read `%s' field for" | |
669 " `%s' table of subfont %d", | |
670 collection.c_str (), "length", tbl.tag, i)); | |
671 return SCM_BOOL_F; | |
672 } | |
673 tbl.length | |
674 = static_cast<unsigned char>(buff[0]) << 24 | |
675 | static_cast<unsigned char>(buff[1]) << 16 | |
676 | static_cast<unsigned char>(buff[2]) << 8 | |
677 | static_cast<unsigned char>(buff[3]); | |
678 // Write `length` | |
679 if (fwrite (buff, 4, 1, fo) != 1) | |
680 { | |
681 fclose (fi); | |
682 fclose (fo); | |
683 warning (_f ("font `%s': cannot write `%s' field for `%s' table", | |
684 subfont.c_str (), "length", tbl.tag)); | |
685 return SCM_BOOL_F; | |
686 } | |
687 | |
688 next_offset += tbl.length; | |
689 | |
690 // Align table | |
691 if (next_offset & 0x3) | |
692 next_offset = (next_offset + 0x3) & 0xfffffffc; | |
693 | |
694 ttcotc_tables.push_back (tbl); | |
695 } | |
696 | |
697 // Copy tables | |
698 for (const auto &tbl: ttcotc_tables) | |
699 { | |
700 auto table_buffer = std::vector<char> (tbl.length, 0); | |
701 fseek (fi, tbl.offset, SEEK_SET); | |
702 fseek (fo, tbl.new_offset, SEEK_SET); | |
703 | |
704 // Read table | |
705 if (fread (table_buffer.data (), tbl.length, 1, fi) != 1) | |
706 { | |
707 fclose (fi); | |
708 fclose (fo); | |
709 warning (_f ("font `%s': cannot read `%s' table of subfont %d", | |
710 collection.c_str (), tbl.tag, i)); | |
711 return SCM_BOOL_F; | |
712 } | |
713 // Write table | |
714 if (fwrite (table_buffer.data (), tbl.length, 1, fo) != 1) | |
715 { | |
716 fclose (fi); | |
717 fclose (fo); | |
718 warning (_f ("font `%s': cannot write `%s' table", | |
719 subfont.c_str (), tbl.tag)); | |
720 return SCM_BOOL_F; | |
721 } | |
722 } | |
723 | |
724 fclose (fi); | |
725 fclose (fo); | |
726 | |
727 return SCM_BOOL_T; | |
728 } | |
OLD | NEW |