1#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
10pub enum CodeError {
11 #[error("The length of the data ({actual}) does not match the advertised expected ({expected}) length")]
13 LengthMismatch {
14 expected: usize,
16 actual: usize,
18 },
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
23pub enum Ext1 {
25 TransparentSpace,
26 NonBreakingTransparentSpace,
27 HorizontalElipses,
28 LatinCapitalSWithCaron,
29 LatinCapitalLigatureOE,
30 FullBlock,
31 SingleOpenQuote,
32 SingleCloseQuote,
33 DoubleOpenQuote,
34 DoubleCloseQuote,
35 SolidDot,
36 TradeMarkSign,
37 LatinLowerSWithCaron,
38 LatinLowerLigatureOE,
39 LatinCapitalYWithDiaeresis,
40 Fraction18,
41 Fraction38,
42 Fraction58,
43 Fraction78,
44 VerticalBorder,
45 UpperRightBorder,
46 LowerLeftBorder,
47 HorizontalBorder,
48 LowerRightBorder,
49 UpperLeftBorder,
50 ClosedCaptionSign,
51
52 Unknown(Vec<u8>),
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
57pub enum Code {
59 NUL,
60 ETX,
61 BS,
62 FF,
63 CR,
64 HCR,
65 Ext1(Ext1),
66 P16(u16),
67 Space, ExclamationMark,
70 QuotationMark,
71 NumberSign,
72 DollarSign,
73 PercentSign,
74 Ampersand,
75 Apostrophe,
76 LeftParenthesis,
77 RightParenthesis,
78 Asterisk,
79 PlusSign,
80 Comma,
81 HyphenMinus,
82 FullStop,
83 Solidus,
84 Zero,
85 One,
86 Two,
87 Three,
88 Four,
89 Five,
90 Six,
91 Seven,
92 Eight,
93 Nine,
94 Colon,
95 SemiColon,
96 LessThan,
97 Equals,
98 GreaterThan,
99 QuestionMark,
100 CommercialAt,
101 LatinCapitalA,
102 LatinCapitalB,
103 LatinCapitalC,
104 LatinCapitalD,
105 LatinCapitalE,
106 LatinCapitalF,
107 LatinCapitalG,
108 LatinCapitalH,
109 LatinCapitalI,
110 LatinCapitalJ,
111 LatinCapitalK,
112 LatinCapitalL,
113 LatinCapitalM,
114 LatinCapitalN,
115 LatinCapitalO,
116 LatinCapitalP,
117 LatinCapitalQ,
118 LatinCapitalR,
119 LatinCapitalS,
120 LatinCapitalT,
121 LatinCapitalU,
122 LatinCapitalV,
123 LatinCapitalW,
124 LatinCapitalX,
125 LatinCapitalY,
126 LatinCapitalZ,
127 LeftSquareBracket,
128 ReverseSolidus,
129 RightSquareBracket,
130 CircumflexAccent,
131 LowLine,
132 GraveAccent,
133 LatinLowerA,
134 LatinLowerB,
135 LatinLowerC,
136 LatinLowerD,
137 LatinLowerE,
138 LatinLowerF,
139 LatinLowerG,
140 LatinLowerH,
141 LatinLowerI,
142 LatinLowerJ,
143 LatinLowerK,
144 LatinLowerL,
145 LatinLowerM,
146 LatinLowerN,
147 LatinLowerO,
148 LatinLowerP,
149 LatinLowerQ,
150 LatinLowerR,
151 LatinLowerS,
152 LatinLowerT,
153 LatinLowerU,
154 LatinLowerV,
155 LatinLowerW,
156 LatinLowerX,
157 LatinLowerY,
158 LatinLowerZ,
159 LeftCurlyBracket,
160 VerticalLine,
161 RightCurlyBracket,
162 Tilde,
163 MusicalSymbolEighthNote, SetCurrentWindow0, SetCurrentWindow1,
168 SetCurrentWindow2,
169 SetCurrentWindow3,
170 SetCurrentWindow4,
171 SetCurrentWindow5,
172 SetCurrentWindow6,
173 SetCurrentWindow7,
174 ClearWindows(WindowBits), DisplayWindows(WindowBits),
176 HideWindows(WindowBits),
177 ToggleWindows(WindowBits),
178 DeleteWindows(WindowBits),
179 Delay(u8),
180 DelayCancel,
181 Reset,
182 SetPenAttributes(SetPenAttributesArgs),
183 SetPenColor(SetPenColorArgs),
184 SetPenLocation(SetPenLocationArgs), SetWindowAttributes(SetWindowAttributesArgs), DefineWindow(DefineWindowArgs), NonBreakingSpace, InvertedExclamationMark,
192 CentSign,
193 PoundSign,
194 GeneralCurrencySign,
195 YenSign,
196 BrokenVerticalBar,
197 SectionSign,
198 Umlaut,
199 CopyrightSign,
200 FeminineOrdinalSign,
201 LeftDoubleAngleQuote,
202 LogicalNotSign,
203 SoftHyphen,
204 RegisteredTrademarkSign,
205 SpacingMacronLongAccent,
206 DegreeSign,
207 PlusOrMinusSign,
208 Superscript2,
209 Superscript3,
210 SpacingAccuteAccent,
211 MicroSign,
212 ParagraphSign,
213 MiddleDot,
214 SpacingCedilla,
215 Superscript1,
216 MasculineOrdinalSign,
217 RightDoubleAngleQuote,
218 Fraction14,
219 Fraction12,
220 Fraction34,
221 InvertedQuestionMark,
222 LatinCapitalAWithGrave,
223 LatinCapitalAWithAcute,
224 LatinCapitalAWithCircumflex,
225 LatinCapitalAWithTilde,
226 LatinCapitalAWithDiaeresis,
227 LatinCapitalAWithRingAbove,
228 LatinCapitalAe,
229 LatinCapitalCWithCedilla,
230 LatinCapitalEWithGrave,
231 LatinCapitalEWithAcute,
232 LatinCapitalEWithCircumflex,
233 LatinCapitalEWithDiaeseris,
234 LatinCapitalIWithGrave,
235 LatinCapitalIWithAcute,
236 LatinCapitalIWithCircumflex,
237 LatinCapitalIWithDiaeseris,
238 LatinCapitalEth,
239 LatinCapitalNWithTilde,
240 LatinCapitalOWithGrave,
241 LatinCapitalOWithAcute,
242 LatinCapitalOWithCircumflex,
243 LatinCapitalOWithTilde,
244 LatinCapitalOWithDiaeresis,
245 MultiplicationSign,
246 LatinCapitalOWithStroke,
247 LatinCapitalUWithGrave,
248 LatinCapitalUWithAcute,
249 LatinCapitalUWithCircumflex,
250 LatinCapitalUWithDiaeresis,
251 LatinCapitalYWithAcute,
252 LatinCapitalThorn,
253 LatinLowerSharpS,
254 LatinLowerAWithGrave,
255 LatinLowerAWithAcute,
256 LatinLowerAWithCircumflex,
257 LatinLowerAWithTilde,
258 LatinLowerAWithDiaeresis,
259 LatinLowerAWithRingAbove,
260 LatinLowerAe,
261 LatinLowerCWithCedilla,
262 LatinLowerEWithGrave,
263 LatinLowerEWithAcute,
264 LatinLowerEWithCircumflex,
265 LatinLowerEWithDiaeseris,
266 LatinLowerIWithGrave,
267 LatinLowerIWithAcute,
268 LatinLowerIWithCircumflex,
269 LatinLowerIWithDiaeseris,
270 LatinLowerEth,
271 LatinLowerNWithTilde,
272 LatinLowerOWithGrave,
273 LatinLowerOWithAcute,
274 LatinLowerOWithCircumflex,
275 LatinLowerOWithTilde,
276 LatinLowerOWithDiaeresis,
277 DivisionSign,
278 LatinLowerOWithStroke,
279 LatinLowerUWithGrave,
280 LatinLowerUWithAcute,
281 LatinLowerUWithCircumflex,
282 LatinLowerUWithDiaeresis,
283 LatinLowerYWithAcute,
284 LatinLowerThorn,
285 LatinLowerYWithDiaeresis,
286 Unknown(Vec<u8>),
287}
288
289#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
291pub struct WindowBits(u8);
292
293impl From<u8> for WindowBits {
294 fn from(bits: u8) -> Self {
295 Self(bits)
296 }
297}
298
299impl From<[u8; 1]> for WindowBits {
300 fn from(bits: [u8; 1]) -> Self {
301 Self(bits[0])
302 }
303}
304
305impl From<WindowBits> for u8 {
306 fn from(bits: WindowBits) -> Self {
307 bits.0
308 }
309}
310
311impl From<WindowBits> for [u8; 1] {
312 fn from(bits: WindowBits) -> Self {
313 [bits.0]
314 }
315}
316
317impl WindowBits {
318 pub const NONE: WindowBits = WindowBits(0x0);
319 pub const ZERO: WindowBits = WindowBits(0x01);
320 pub const ONE: WindowBits = WindowBits(0x02);
321 pub const TWO: WindowBits = WindowBits(0x04);
322 pub const THREE: WindowBits = WindowBits(0x08);
323 pub const FOUR: WindowBits = WindowBits(0x10);
324 pub const FIVE: WindowBits = WindowBits(0x20);
325 pub const SIX: WindowBits = WindowBits(0x40);
326 pub const SEVEN: WindowBits = WindowBits(0x80);
327
328 pub const fn or(self, rhs: Self) -> Self {
329 Self(self.0 | rhs.0)
330 }
331
332 pub const fn and(self, rhs: Self) -> Self {
333 Self(self.0 & rhs.0)
334 }
335
336 pub const fn not(self) -> Self {
337 Self(!self.0)
338 }
339
340 pub const fn from_window_id(window_id: u8) -> Self {
344 assert!(window_id < 8);
345 Self(1 << window_id)
346 }
347}
348
349impl std::ops::BitOr for WindowBits {
350 type Output = Self;
351
352 fn bitor(self, rhs: Self) -> Self::Output {
353 Self(self.0 | rhs.0)
354 }
355}
356
357impl std::ops::BitAnd for WindowBits {
358 type Output = Self;
359
360 fn bitand(self, rhs: Self) -> Self::Output {
361 Self(self.0 & rhs.0)
362 }
363}
364
365impl std::ops::Not for WindowBits {
366 type Output = Self;
367
368 fn not(self) -> Self::Output {
369 Self(!self.0)
370 }
371}
372
373impl std::fmt::Debug for WindowBits {
374 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
375 write!(f, "WindowBits(b{:0>8b})", self.0)
376 }
377}
378
379#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
381pub enum Anchor {
382 TopLeft,
383 TopMiddle,
384 TopRight,
385 CenterLeft,
386 CenterMiddle,
387 CenterRight,
388 BottomLeft,
389 BottomMiddle,
390 BottomRight,
391 Undefined9,
392 Undefined10,
393 Undefined11,
394 Undefined12,
395 Undefined13,
396 Undefined14,
397 Undefined15,
398}
399
400impl From<u8> for Anchor {
401 fn from(a: u8) -> Self {
402 match a {
403 0 => Anchor::TopLeft,
404 1 => Anchor::TopMiddle,
405 2 => Anchor::TopRight,
406 3 => Anchor::CenterLeft,
407 4 => Anchor::CenterMiddle,
408 5 => Anchor::CenterRight,
409 6 => Anchor::BottomLeft,
410 7 => Anchor::BottomMiddle,
411 8 => Anchor::BottomRight,
412 9 => Anchor::Undefined9,
413 10 => Anchor::Undefined10,
414 11 => Anchor::Undefined11,
415 12 => Anchor::Undefined12,
416 13 => Anchor::Undefined13,
417 14 => Anchor::Undefined14,
418 15 => Anchor::Undefined15,
419 _ => unreachable!(),
420 }
421 }
422}
423
424impl From<Anchor> for u8 {
425 fn from(a: Anchor) -> u8 {
426 match a {
427 Anchor::TopLeft => 0,
428 Anchor::TopMiddle => 1,
429 Anchor::TopRight => 2,
430 Anchor::CenterLeft => 3,
431 Anchor::CenterMiddle => 4,
432 Anchor::CenterRight => 5,
433 Anchor::BottomLeft => 6,
434 Anchor::BottomMiddle => 7,
435 Anchor::BottomRight => 8,
436 Anchor::Undefined9 => 9,
437 Anchor::Undefined10 => 10,
438 Anchor::Undefined11 => 11,
439 Anchor::Undefined12 => 12,
440 Anchor::Undefined13 => 13,
441 Anchor::Undefined14 => 14,
442 Anchor::Undefined15 => 15,
443 }
444 }
445}
446
447#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
449pub struct DefineWindowArgs {
450 pub window_id: u8, pub priority: u8, pub anchor_point: Anchor,
453 pub relative_positioning: bool,
454 pub anchor_vertical: u8, pub anchor_horizontal: u8, pub row_count: u8, pub column_count: u8, pub row_lock: bool,
459 pub column_lock: bool,
460 pub visible: bool,
461 pub window_style_id: u8, pub pen_style_id: u8, }
464
465impl From<[u8; 6]> for DefineWindowArgs {
466 fn from(args: [u8; 6]) -> Self {
467 Self {
468 window_id: 0, priority: args[0] & 0x7,
470 anchor_point: ((args[3] & 0xF0) >> 4).into(),
471 relative_positioning: (args[1] & 0x80) > 0,
472 anchor_vertical: args[1] & 0x7F,
473 anchor_horizontal: args[2],
474 row_count: args[3] & 0x0F,
475 column_count: args[4] & 0x3F,
476 row_lock: (args[0] & 0x10) > 0,
477 column_lock: (args[0] & 0x08) > 0,
478 visible: (args[0] & 0x20) > 0,
479 window_style_id: (args[5] & 0x38) >> 3,
480 pen_style_id: args[5] & 0x07,
481 }
482 }
483}
484
485impl From<DefineWindowArgs> for [u8; 6] {
486 fn from(args: DefineWindowArgs) -> Self {
487 [
488 args.priority & 0x7
489 | u8::from(args.column_lock) << 3
490 | u8::from(args.row_lock) << 4
491 | u8::from(args.visible) << 5,
492 args.anchor_vertical & 0x7F | u8::from(args.relative_positioning) << 7,
493 args.anchor_horizontal,
494 (args.row_count & 0x0F) | u8::from(args.anchor_point) << 4,
495 args.column_count & 0x3F,
496 args.pen_style_id & 0x07 | (args.window_style_id & 0x7) << 3,
497 ]
498 }
499}
500
501impl DefineWindowArgs {
502 #[allow(clippy::too_many_arguments)]
503 pub const fn new(
504 window_id: u8,
505 priority: u8,
506 anchor_point: Anchor,
507 relative_positioning: bool,
508 anchor_vertical: u8,
509 anchor_horizontal: u8,
510 row_count: u8,
511 column_count: u8,
512 row_lock: bool,
513 column_lock: bool,
514 visible: bool,
515 window_style_id: u8,
516 pen_style_id: u8,
517 ) -> Self {
518 Self {
519 window_id,
520 priority,
521 anchor_point,
522 relative_positioning,
523 anchor_vertical,
524 anchor_horizontal,
525 row_count,
526 column_count,
527 row_lock,
528 column_lock,
529 visible,
530 window_style_id,
531 pen_style_id,
532 }
533 }
534
535 pub fn window_attributes(&self) -> SetWindowAttributesArgs {
537 PREDEFINED_WINDOW_STYLES[self.window_style_id.max(1) as usize - 1]
538 }
539
540 pub fn pen_attributes(&self) -> SetPenAttributesArgs {
542 PREDEFINED_PEN_STYLES_ATTRIBUTES[self.pen_style_id.max(1) as usize - 1]
543 }
544
545 pub fn pen_color(&self) -> SetPenColorArgs {
547 PREDEFINED_PEN_STYLES_COLOR[self.pen_style_id.max(1) as usize - 1]
548 }
549}
550
551static PREDEFINED_WINDOW_STYLES: [SetWindowAttributesArgs; 7] = [
552 SetWindowAttributesArgs {
554 justify: Justify::Left,
555 print_direction: Direction::LeftToRight,
556 scroll_direction: Direction::BottomToTop,
557 wordwrap: false,
558 display_effect: DisplayEffect::Snap,
559 effect_direction: Direction::LeftToRight,
560 effect_speed: 1,
561 fill_color: Color::BLACK,
562 fill_opacity: Opacity::Solid,
563 border_type: BorderType::None,
564 border_color: Color::BLACK,
565 },
566 SetWindowAttributesArgs {
568 justify: Justify::Left,
569 print_direction: Direction::LeftToRight,
570 scroll_direction: Direction::BottomToTop,
571 wordwrap: false,
572 display_effect: DisplayEffect::Snap,
573 effect_direction: Direction::LeftToRight,
574 effect_speed: 1,
575 fill_color: Color::BLACK,
576 fill_opacity: Opacity::Transparent,
577 border_type: BorderType::None,
578 border_color: Color::BLACK,
579 },
580 SetWindowAttributesArgs {
582 justify: Justify::Center,
583 print_direction: Direction::LeftToRight,
584 scroll_direction: Direction::BottomToTop,
585 wordwrap: false,
586 display_effect: DisplayEffect::Snap,
587 effect_direction: Direction::LeftToRight,
588 effect_speed: 1,
589 fill_color: Color::BLACK,
590 fill_opacity: Opacity::Solid,
591 border_type: BorderType::None,
592 border_color: Color::BLACK,
593 },
594 SetWindowAttributesArgs {
596 justify: Justify::Left,
597 print_direction: Direction::LeftToRight,
598 scroll_direction: Direction::BottomToTop,
599 wordwrap: true,
600 display_effect: DisplayEffect::Snap,
601 effect_direction: Direction::LeftToRight,
602 effect_speed: 1,
603 fill_color: Color::BLACK,
604 fill_opacity: Opacity::Solid,
605 border_type: BorderType::None,
606 border_color: Color::BLACK,
607 },
608 SetWindowAttributesArgs {
610 justify: Justify::Left,
611 print_direction: Direction::LeftToRight,
612 scroll_direction: Direction::BottomToTop,
613 wordwrap: true,
614 display_effect: DisplayEffect::Snap,
615 effect_direction: Direction::LeftToRight,
616 effect_speed: 1,
617 fill_color: Color::BLACK,
618 fill_opacity: Opacity::Transparent,
619 border_type: BorderType::None,
620 border_color: Color::BLACK,
621 },
622 SetWindowAttributesArgs {
624 justify: Justify::Center,
625 print_direction: Direction::LeftToRight,
626 scroll_direction: Direction::BottomToTop,
627 wordwrap: true,
628 display_effect: DisplayEffect::Snap,
629 effect_direction: Direction::LeftToRight,
630 effect_speed: 1,
631 fill_color: Color::BLACK,
632 fill_opacity: Opacity::Solid,
633 border_type: BorderType::None,
634 border_color: Color::BLACK,
635 },
636 SetWindowAttributesArgs {
638 justify: Justify::Left,
639 print_direction: Direction::TopToBottom,
640 scroll_direction: Direction::RightToLeft,
641 wordwrap: false,
642 display_effect: DisplayEffect::Snap,
643 effect_direction: Direction::LeftToRight,
644 effect_speed: 1,
645 fill_color: Color::BLACK,
646 fill_opacity: Opacity::Solid,
647 border_type: BorderType::None,
648 border_color: Color::BLACK,
649 },
650];
651
652static PREDEFINED_PEN_STYLES_ATTRIBUTES: [SetPenAttributesArgs; 7] = [
653 SetPenAttributesArgs {
655 pen_size: PenSize::Standard,
656 font_style: FontStyle::Default,
657 text_tag: TextTag::Dialog,
658 offset: TextOffset::Normal,
659 italics: false,
660 underline: false,
661 edge_type: EdgeType::None,
662 },
663 SetPenAttributesArgs {
665 pen_size: PenSize::Standard,
666 font_style: FontStyle::MonospacedWithSerifs,
667 text_tag: TextTag::Dialog,
668 offset: TextOffset::Normal,
669 italics: false,
670 underline: false,
671 edge_type: EdgeType::None,
672 },
673 SetPenAttributesArgs {
675 pen_size: PenSize::Standard,
676 font_style: FontStyle::ProportionallySpacedWithSerifs,
677 text_tag: TextTag::Dialog,
678 offset: TextOffset::Normal,
679 italics: false,
680 underline: false,
681 edge_type: EdgeType::None,
682 },
683 SetPenAttributesArgs {
685 pen_size: PenSize::Standard,
686 font_style: FontStyle::MonospacedWithoutSerifs,
687 text_tag: TextTag::Dialog,
688 offset: TextOffset::Normal,
689 italics: false,
690 underline: false,
691 edge_type: EdgeType::None,
692 },
693 SetPenAttributesArgs {
695 pen_size: PenSize::Standard,
696 font_style: FontStyle::ProportionallySpacedWithoutSerifs,
697 text_tag: TextTag::Dialog,
698 offset: TextOffset::Normal,
699 italics: false,
700 underline: false,
701 edge_type: EdgeType::None,
702 },
703 SetPenAttributesArgs {
705 pen_size: PenSize::Standard,
706 font_style: FontStyle::MonospacedWithoutSerifs,
707 text_tag: TextTag::Dialog,
708 offset: TextOffset::Normal,
709 italics: false,
710 underline: false,
711 edge_type: EdgeType::Uniform,
712 },
713 SetPenAttributesArgs {
715 pen_size: PenSize::Standard,
716 font_style: FontStyle::ProportionallySpacedWithoutSerifs,
717 text_tag: TextTag::Dialog,
718 offset: TextOffset::Normal,
719 italics: false,
720 underline: false,
721 edge_type: EdgeType::Uniform,
722 },
723];
724
725static PREDEFINED_PEN_STYLES_COLOR: [SetPenColorArgs; 7] = [
726 SetPenColorArgs {
728 foreground_color: Color::WHITE,
729 foreground_opacity: Opacity::Solid,
730 background_color: Color::BLACK,
731 background_opacity: Opacity::Solid,
732 edge_color: Color::BLACK,
733 },
734 SetPenColorArgs {
736 foreground_color: Color::WHITE,
737 foreground_opacity: Opacity::Solid,
738 background_color: Color::BLACK,
739 background_opacity: Opacity::Solid,
740 edge_color: Color::BLACK,
741 },
742 SetPenColorArgs {
744 foreground_color: Color::WHITE,
745 foreground_opacity: Opacity::Solid,
746 background_color: Color::BLACK,
747 background_opacity: Opacity::Solid,
748 edge_color: Color::BLACK,
749 },
750 SetPenColorArgs {
752 foreground_color: Color::WHITE,
753 foreground_opacity: Opacity::Solid,
754 background_color: Color::BLACK,
755 background_opacity: Opacity::Solid,
756 edge_color: Color::BLACK,
757 },
758 SetPenColorArgs {
760 foreground_color: Color::WHITE,
761 foreground_opacity: Opacity::Solid,
762 background_color: Color::BLACK,
763 background_opacity: Opacity::Solid,
764 edge_color: Color::BLACK,
765 },
766 SetPenColorArgs {
768 foreground_color: Color::WHITE,
769 foreground_opacity: Opacity::Solid,
770 background_color: Color::BLACK,
771 background_opacity: Opacity::Transparent,
772 edge_color: Color::BLACK,
773 },
774 SetPenColorArgs {
776 foreground_color: Color::WHITE,
777 foreground_opacity: Opacity::Solid,
778 background_color: Color::BLACK,
779 background_opacity: Opacity::Transparent,
780 edge_color: Color::BLACK,
781 },
782];
783
784#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
786pub enum Justify {
787 Left,
788 Right,
789 Center,
790 Full,
791}
792
793impl From<u8> for Justify {
794 fn from(j: u8) -> Self {
795 match j {
796 0 => Justify::Left,
797 1 => Justify::Right,
798 2 => Justify::Center,
799 3 => Justify::Full,
800 _ => unreachable!(),
801 }
802 }
803}
804
805impl From<Justify> for u8 {
806 fn from(j: Justify) -> u8 {
807 match j {
808 Justify::Left => 0,
809 Justify::Right => 1,
810 Justify::Center => 2,
811 Justify::Full => 3,
812 }
813 }
814}
815
816#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
818pub enum Direction {
819 LeftToRight,
820 RightToLeft,
821 TopToBottom,
822 BottomToTop,
823}
824
825impl From<u8> for Direction {
826 fn from(d: u8) -> Self {
827 match d {
828 0 => Direction::LeftToRight,
829 1 => Direction::RightToLeft,
830 2 => Direction::TopToBottom,
831 3 => Direction::BottomToTop,
832 _ => unreachable!(),
833 }
834 }
835}
836
837impl From<Direction> for u8 {
838 fn from(j: Direction) -> u8 {
839 match j {
840 Direction::LeftToRight => 0,
841 Direction::RightToLeft => 1,
842 Direction::TopToBottom => 2,
843 Direction::BottomToTop => 3,
844 }
845 }
846}
847
848#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
850pub enum DisplayEffect {
851 Snap,
852 Fade,
853 Wipe,
854 Undefined,
855}
856
857impl From<u8> for DisplayEffect {
858 fn from(d: u8) -> Self {
859 match d {
860 0 => DisplayEffect::Snap,
861 1 => DisplayEffect::Fade,
862 2 => DisplayEffect::Wipe,
863 3 => DisplayEffect::Undefined,
864 _ => unreachable!(),
865 }
866 }
867}
868
869impl From<DisplayEffect> for u8 {
870 fn from(de: DisplayEffect) -> u8 {
871 match de {
872 DisplayEffect::Snap => 0,
873 DisplayEffect::Fade => 1,
874 DisplayEffect::Wipe => 2,
875 DisplayEffect::Undefined => 3,
876 }
877 }
878}
879
880#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
882pub enum Opacity {
883 Solid,
884 Flash,
885 Translucent,
886 Transparent,
887}
888
889impl From<u8> for Opacity {
890 fn from(op: u8) -> Opacity {
891 match op {
892 0 => Opacity::Solid,
893 1 => Opacity::Flash,
894 2 => Opacity::Translucent,
895 3 => Opacity::Transparent,
896 _ => unreachable!(),
897 }
898 }
899}
900
901impl From<Opacity> for u8 {
902 fn from(op: Opacity) -> u8 {
903 match op {
904 Opacity::Solid => 0,
905 Opacity::Flash => 1,
906 Opacity::Translucent => 2,
907 Opacity::Transparent => 3,
908 }
909 }
910}
911
912#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
914pub enum ColorValue {
915 None,
916 OneThird,
917 TwoThirds,
918 Full,
919}
920
921impl From<u8> for ColorValue {
922 fn from(val: u8) -> ColorValue {
923 match val {
924 0 => ColorValue::None,
925 1 => ColorValue::OneThird,
926 2 => ColorValue::TwoThirds,
927 3 => ColorValue::Full,
928 _ => unreachable!(),
929 }
930 }
931}
932
933impl From<ColorValue> for u8 {
934 fn from(cv: ColorValue) -> u8 {
935 match cv {
936 ColorValue::None => 0,
937 ColorValue::OneThird => 1,
938 ColorValue::TwoThirds => 2,
939 ColorValue::Full => 3,
940 }
941 }
942}
943
944#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
946pub struct Color {
947 pub r: ColorValue,
948 pub g: ColorValue,
949 pub b: ColorValue,
950}
951
952impl From<Color> for u8 {
953 fn from(c: Color) -> Self {
954 u8::from(c.r) << 4 | u8::from(c.g) << 2 | u8::from(c.b)
955 }
956}
957
958impl From<u8> for Color {
959 fn from(c: u8) -> Color {
960 Color {
961 r: ((c & 0x30) >> 4).into(),
962 g: ((c & 0x0C) >> 2).into(),
963 b: (c & 0x03).into(),
964 }
965 }
966}
967
968impl Color {
969 pub const BLACK: Color = Color::new(ColorValue::None, ColorValue::None, ColorValue::None);
970 pub const WHITE: Color = Color::new(ColorValue::Full, ColorValue::Full, ColorValue::Full);
971 pub const RED: Color = Color::new(ColorValue::Full, ColorValue::None, ColorValue::None);
972 pub const GREEN: Color = Color::new(ColorValue::None, ColorValue::Full, ColorValue::None);
973 pub const BLUE: Color = Color::new(ColorValue::None, ColorValue::None, ColorValue::Full);
974
975 pub const fn new(r: ColorValue, g: ColorValue, b: ColorValue) -> Self {
976 Self { r, g, b }
977 }
978}
979
980struct ColorOpacity(Color, Opacity);
981
982impl From<ColorOpacity> for u8 {
983 fn from(c_o: ColorOpacity) -> Self {
984 u8::from(c_o.1) << 6 | u8::from(c_o.0)
985 }
986}
987
988impl From<u8> for ColorOpacity {
989 fn from(c_o: u8) -> Self {
990 Self((c_o & 0x3F).into(), ((c_o & 0xC0) >> 6).into())
991 }
992}
993
994#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
996pub enum BorderType {
997 None,
998 Raised,
999 Depressed,
1000 Uniform,
1001 ShadowLeft,
1002 ShadowRight,
1003 Undefined6,
1004 Undefined7,
1005}
1006
1007impl From<BorderType> for u8 {
1008 fn from(bt: BorderType) -> Self {
1009 match bt {
1010 BorderType::None => 0,
1011 BorderType::Raised => 1,
1012 BorderType::Depressed => 2,
1013 BorderType::Uniform => 3,
1014 BorderType::ShadowLeft => 4,
1015 BorderType::ShadowRight => 5,
1016 BorderType::Undefined6 => 6,
1017 BorderType::Undefined7 => 7,
1018 }
1019 }
1020}
1021
1022impl From<u8> for BorderType {
1023 fn from(bt: u8) -> Self {
1024 match bt {
1025 0 => BorderType::None,
1026 1 => BorderType::Raised,
1027 2 => BorderType::Depressed,
1028 3 => BorderType::Uniform,
1029 4 => BorderType::ShadowLeft,
1030 5 => BorderType::ShadowRight,
1031 6 => BorderType::Undefined6,
1032 7 => BorderType::Undefined7,
1033 _ => unreachable!(),
1034 }
1035 }
1036}
1037
1038#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1040pub struct SetWindowAttributesArgs {
1041 pub justify: Justify,
1042 pub print_direction: Direction,
1043 pub scroll_direction: Direction,
1044 pub wordwrap: bool,
1045 pub display_effect: DisplayEffect,
1046 pub effect_direction: Direction,
1047 pub effect_speed: u8, pub fill_color: Color,
1049 pub fill_opacity: Opacity,
1050 pub border_type: BorderType,
1051 pub border_color: Color,
1052}
1053
1054impl From<SetWindowAttributesArgs> for [u8; 4] {
1055 fn from(args: SetWindowAttributesArgs) -> Self {
1056 let bt = u8::from(args.border_type);
1057 [
1058 ColorOpacity(args.fill_color, args.fill_opacity).into(),
1059 (bt & 0x3) << 6 | u8::from(args.border_color),
1060 (bt & 0x4) << 5
1061 | u8::from(args.wordwrap) << 6
1062 | u8::from(args.print_direction) << 4
1063 | u8::from(args.scroll_direction) << 2
1064 | u8::from(args.justify),
1065 args.effect_speed << 4
1066 | u8::from(args.effect_direction) << 2
1067 | u8::from(args.display_effect),
1068 ]
1069 }
1070}
1071
1072impl From<[u8; 4]> for SetWindowAttributesArgs {
1073 fn from(args: [u8; 4]) -> Self {
1074 let fill: ColorOpacity = args[0].into();
1075 let border_type = (args[1] & 0xC0) >> 6 | (args[2] & 0x80) >> 5;
1076 Self {
1077 justify: (args[2] & 0x03).into(),
1078 print_direction: ((args[2] & 0x30) >> 4).into(),
1079 scroll_direction: ((args[2] & 0x0C) >> 2).into(),
1080 wordwrap: (args[2] & 0x40) > 0,
1081 display_effect: (args[3] & 0x03).into(),
1082 effect_direction: ((args[3] & 0x0C) >> 2).into(),
1083 effect_speed: (args[3] & 0xF0) >> 4,
1084 fill_color: fill.0,
1085 fill_opacity: fill.1,
1086 border_type: border_type.into(),
1087 border_color: args[1].into(),
1088 }
1089 }
1090}
1091
1092impl SetWindowAttributesArgs {
1093 #[allow(clippy::too_many_arguments)]
1094 pub const fn new(
1095 justify: Justify,
1096 print_direction: Direction,
1097 scroll_direction: Direction,
1098 wordwrap: bool,
1099 display_effect: DisplayEffect,
1100 effect_direction: Direction,
1101 effect_speed: u8,
1102 fill_color: Color,
1103 fill_opacity: Opacity,
1104 border_type: BorderType,
1105 border_color: Color,
1106 ) -> Self {
1107 Self {
1108 justify,
1109 print_direction,
1110 scroll_direction,
1111 wordwrap,
1112 display_effect,
1113 effect_direction,
1114 effect_speed,
1115 fill_color,
1116 fill_opacity,
1117 border_type,
1118 border_color,
1119 }
1120 }
1121}
1122
1123#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1125pub enum PenSize {
1126 Small,
1127 Standard,
1128 Large,
1129 Undefined,
1130}
1131
1132impl From<PenSize> for u8 {
1133 fn from(pen_size: PenSize) -> Self {
1134 match pen_size {
1135 PenSize::Small => 0,
1136 PenSize::Standard => 1,
1137 PenSize::Large => 2,
1138 PenSize::Undefined => 3,
1139 }
1140 }
1141}
1142
1143impl From<u8> for PenSize {
1144 fn from(pen_size: u8) -> Self {
1145 match pen_size {
1146 0 => PenSize::Small,
1147 1 => PenSize::Standard,
1148 2 => PenSize::Large,
1149 3 => PenSize::Undefined,
1150 _ => unreachable!(),
1151 }
1152 }
1153}
1154
1155#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1157pub enum FontStyle {
1158 Default,
1159 MonospacedWithSerifs,
1160 ProportionallySpacedWithSerifs,
1161 MonospacedWithoutSerifs,
1162 ProportionallySpacedWithoutSerifs,
1163 CasualFontType,
1164 CursiveFontType,
1165 SmallCapitals,
1166}
1167
1168impl From<FontStyle> for u8 {
1169 fn from(font_style: FontStyle) -> Self {
1170 match font_style {
1171 FontStyle::Default => 0,
1172 FontStyle::MonospacedWithSerifs => 1,
1173 FontStyle::ProportionallySpacedWithSerifs => 2,
1174 FontStyle::MonospacedWithoutSerifs => 3,
1175 FontStyle::ProportionallySpacedWithoutSerifs => 4,
1176 FontStyle::CasualFontType => 5,
1177 FontStyle::CursiveFontType => 6,
1178 FontStyle::SmallCapitals => 7,
1179 }
1180 }
1181}
1182
1183impl From<u8> for FontStyle {
1184 fn from(font_style: u8) -> Self {
1185 match font_style {
1186 0 => FontStyle::Default,
1187 1 => FontStyle::MonospacedWithSerifs,
1188 2 => FontStyle::ProportionallySpacedWithSerifs,
1189 3 => FontStyle::MonospacedWithoutSerifs,
1190 4 => FontStyle::ProportionallySpacedWithoutSerifs,
1191 5 => FontStyle::CasualFontType,
1192 6 => FontStyle::CursiveFontType,
1193 7 => FontStyle::SmallCapitals,
1194 _ => unreachable!(),
1195 }
1196 }
1197}
1198
1199#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1201pub enum TextTag {
1202 Dialog,
1203 SourceOrSpeakerId,
1204 ElectronicallyReproducedVoice,
1205 DialogInNonPrimaryLanguage,
1206 Voiceover,
1207 AudibleTranslation,
1208 SubtitleTranslation,
1209 VoiceQualityDescription,
1210 SongLyrics,
1211 SoundEffectDescription,
1212 MusicalScoreDescription,
1213 Expletive,
1214 Undefined12,
1215 Undefined13,
1216 Undefined14,
1217 TextNotToBeDisplayed,
1218}
1219
1220impl From<TextTag> for u8 {
1221 fn from(text_tag: TextTag) -> Self {
1222 match text_tag {
1223 TextTag::Dialog => 0,
1224 TextTag::SourceOrSpeakerId => 1,
1225 TextTag::ElectronicallyReproducedVoice => 2,
1226 TextTag::DialogInNonPrimaryLanguage => 3,
1227 TextTag::Voiceover => 4,
1228 TextTag::AudibleTranslation => 5,
1229 TextTag::SubtitleTranslation => 6,
1230 TextTag::VoiceQualityDescription => 7,
1231 TextTag::SongLyrics => 8,
1232 TextTag::SoundEffectDescription => 9,
1233 TextTag::MusicalScoreDescription => 10,
1234 TextTag::Expletive => 11,
1235 TextTag::Undefined12 => 12,
1236 TextTag::Undefined13 => 13,
1237 TextTag::Undefined14 => 14,
1238 TextTag::TextNotToBeDisplayed => 15,
1239 }
1240 }
1241}
1242
1243impl From<u8> for TextTag {
1244 fn from(text_tag: u8) -> Self {
1245 match text_tag {
1246 0 => TextTag::Dialog,
1247 1 => TextTag::SourceOrSpeakerId,
1248 2 => TextTag::ElectronicallyReproducedVoice,
1249 3 => TextTag::DialogInNonPrimaryLanguage,
1250 4 => TextTag::Voiceover,
1251 5 => TextTag::AudibleTranslation,
1252 6 => TextTag::SubtitleTranslation,
1253 7 => TextTag::VoiceQualityDescription,
1254 8 => TextTag::SongLyrics,
1255 9 => TextTag::SoundEffectDescription,
1256 10 => TextTag::MusicalScoreDescription,
1257 11 => TextTag::Expletive,
1258 12 => TextTag::Undefined12,
1259 13 => TextTag::Undefined13,
1260 14 => TextTag::Undefined14,
1261 15 => TextTag::TextNotToBeDisplayed,
1262 _ => unreachable!(),
1263 }
1264 }
1265}
1266
1267#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1269pub enum TextOffset {
1270 Subscript,
1271 Normal,
1272 Superscript,
1273 Undefined,
1274}
1275
1276impl From<TextOffset> for u8 {
1277 fn from(text_offset: TextOffset) -> Self {
1278 match text_offset {
1279 TextOffset::Subscript => 0,
1280 TextOffset::Normal => 1,
1281 TextOffset::Superscript => 2,
1282 TextOffset::Undefined => 3,
1283 }
1284 }
1285}
1286
1287impl From<u8> for TextOffset {
1288 fn from(text_offset: u8) -> Self {
1289 match text_offset {
1290 0 => TextOffset::Subscript,
1291 1 => TextOffset::Normal,
1292 2 => TextOffset::Superscript,
1293 3 => TextOffset::Undefined,
1294 _ => unreachable!(),
1295 }
1296 }
1297}
1298
1299#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1301pub enum EdgeType {
1302 None,
1303 Raised,
1304 Depressed,
1305 Uniform,
1306 LeftDropShadow,
1307 RightDropShadow,
1308 Undefined6,
1309 Undefined7,
1310}
1311
1312impl From<u8> for EdgeType {
1313 fn from(edge_type: u8) -> Self {
1314 match edge_type {
1315 0 => EdgeType::None,
1316 1 => EdgeType::Raised,
1317 2 => EdgeType::Depressed,
1318 3 => EdgeType::Uniform,
1319 4 => EdgeType::LeftDropShadow,
1320 5 => EdgeType::RightDropShadow,
1321 6 => EdgeType::Undefined6,
1322 7 => EdgeType::Undefined7,
1323 _ => unreachable!(),
1324 }
1325 }
1326}
1327
1328impl From<EdgeType> for u8 {
1329 fn from(edge_type: EdgeType) -> Self {
1330 match edge_type {
1331 EdgeType::None => 0,
1332 EdgeType::Raised => 1,
1333 EdgeType::Depressed => 2,
1334 EdgeType::Uniform => 3,
1335 EdgeType::LeftDropShadow => 4,
1336 EdgeType::RightDropShadow => 5,
1337 EdgeType::Undefined6 => 6,
1338 EdgeType::Undefined7 => 7,
1339 }
1340 }
1341}
1342
1343#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1345pub struct SetPenAttributesArgs {
1346 pub pen_size: PenSize,
1347 pub font_style: FontStyle,
1348 pub text_tag: TextTag,
1349 pub offset: TextOffset,
1350 pub italics: bool,
1351 pub underline: bool,
1352 pub edge_type: EdgeType,
1353}
1354
1355impl From<SetPenAttributesArgs> for [u8; 2] {
1356 fn from(args: SetPenAttributesArgs) -> Self {
1357 [
1358 u8::from(args.pen_size) | u8::from(args.offset) << 2 | u8::from(args.text_tag) << 4,
1359 u8::from(args.font_style)
1360 | u8::from(args.edge_type) << 3
1361 | u8::from(args.underline) << 6
1362 | u8::from(args.italics) << 7,
1363 ]
1364 }
1365}
1366
1367impl From<[u8; 2]> for SetPenAttributesArgs {
1368 fn from(args: [u8; 2]) -> Self {
1369 Self {
1370 pen_size: (args[0] & 0x3).into(),
1371 font_style: (args[1] & 0x07).into(),
1372 text_tag: ((args[0] & 0xF0) >> 4).into(),
1373 offset: ((args[0] & 0x0C) >> 2).into(),
1374 italics: (args[1] & 0x80) > 0,
1375 underline: (args[1] & 0x40) > 0,
1376 edge_type: ((args[1] & 0x38) >> 3).into(),
1377 }
1378 }
1379}
1380
1381impl SetPenAttributesArgs {
1382 pub const fn new(
1383 pen_size: PenSize,
1384 font_style: FontStyle,
1385 text_tag: TextTag,
1386 text_offset: TextOffset,
1387 italics: bool,
1388 underline: bool,
1389 edge_type: EdgeType,
1390 ) -> Self {
1391 Self {
1392 pen_size,
1393 font_style,
1394 text_tag,
1395 offset: text_offset,
1396 italics,
1397 underline,
1398 edge_type,
1399 }
1400 }
1401}
1402
1403#[derive(Debug, Clone)]
1404struct CodeMap<'a> {
1405 pub cea708_bytes: &'a [u8],
1406 pub code: Code,
1407 pub utf8: Option<char>,
1408}
1409
1410#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1412pub struct SetPenColorArgs {
1413 pub foreground_color: Color,
1414 pub foreground_opacity: Opacity,
1415 pub background_color: Color,
1416 pub background_opacity: Opacity,
1417 pub edge_color: Color,
1418}
1419
1420impl SetPenColorArgs {
1421 pub const fn new(
1422 foreground_color: Color,
1423 foreground_opacity: Opacity,
1424 background_color: Color,
1425 background_opacity: Opacity,
1426 edge_color: Color,
1427 ) -> Self {
1428 Self {
1429 foreground_color,
1430 foreground_opacity,
1431 background_color,
1432 background_opacity,
1433 edge_color,
1434 }
1435 }
1436}
1437
1438impl From<[u8; 3]> for SetPenColorArgs {
1439 fn from(data: [u8; 3]) -> Self {
1440 let foreground: ColorOpacity = data[0].into();
1441 let background: ColorOpacity = data[1].into();
1442 let edge: Color = data[2].into();
1443 Self {
1444 foreground_color: foreground.0,
1445 foreground_opacity: foreground.1,
1446 background_color: background.0,
1447 background_opacity: background.1,
1448 edge_color: edge,
1449 }
1450 }
1451}
1452
1453impl From<SetPenColorArgs> for [u8; 3] {
1454 fn from(data: SetPenColorArgs) -> Self {
1455 [
1456 ColorOpacity(data.foreground_color, data.foreground_opacity).into(),
1457 ColorOpacity(data.background_color, data.background_opacity).into(),
1458 data.edge_color.into(),
1459 ]
1460 }
1461}
1462
1463#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
1465pub struct SetPenLocationArgs {
1466 pub row: u8, pub column: u8, }
1469
1470impl SetPenLocationArgs {
1471 pub const fn new(row: u8, column: u8) -> Self {
1472 Self { row, column }
1473 }
1474}
1475
1476impl From<[u8; 2]> for SetPenLocationArgs {
1477 fn from(data: [u8; 2]) -> Self {
1478 Self {
1479 row: data[0] & 0x0F,
1480 column: data[1] & 0x3F,
1481 }
1482 }
1483}
1484
1485impl From<SetPenLocationArgs> for [u8; 2] {
1486 fn from(data: SetPenLocationArgs) -> Self {
1487 [data.row & 0x0F, data.column & 0x3F]
1488 }
1489}
1490
1491macro_rules! code_map_bytes {
1492 ($bytes:expr, $code:expr, $utf8:expr) => {
1493 CodeMap {
1494 cea708_bytes: &$bytes,
1495 code: $code,
1496 utf8: $utf8,
1497 }
1498 };
1499}
1500
1501macro_rules! code_map_single_byte {
1502 ($byte:expr, $code:expr, $utf8:expr) => {
1503 code_map_bytes!([$byte], $code, $utf8)
1504 };
1505}
1506
1507static CODE_MAP_TABLE: [CodeMap; 234] = [
1509 code_map_single_byte!(0x00, Code::NUL, None),
1510 code_map_single_byte!(0x03, Code::ETX, None),
1511 code_map_single_byte!(0x08, Code::BS, None),
1512 code_map_single_byte!(0x0C, Code::FF, None),
1513 code_map_single_byte!(0x0D, Code::CR, None),
1514 code_map_single_byte!(0x0E, Code::HCR, None),
1515 code_map_bytes!([0x10, 0x20], Code::Ext1(Ext1::TransparentSpace), None),
1516 code_map_bytes!(
1517 [0x10, 0x21],
1518 Code::Ext1(Ext1::NonBreakingTransparentSpace),
1519 None
1520 ),
1521 code_map_bytes!([0x10, 0x25], Code::Ext1(Ext1::HorizontalElipses), Some('…')),
1522 code_map_bytes!(
1523 [0x10, 0x2A],
1524 Code::Ext1(Ext1::LatinCapitalSWithCaron),
1525 Some('Š')
1526 ),
1527 code_map_bytes!(
1528 [0x10, 0x2C],
1529 Code::Ext1(Ext1::LatinCapitalLigatureOE),
1530 Some('Œ')
1531 ),
1532 code_map_bytes!([0x10, 0x30], Code::Ext1(Ext1::FullBlock), Some('█')),
1533 code_map_bytes!([0x10, 0x31], Code::Ext1(Ext1::SingleOpenQuote), Some('‘')),
1534 code_map_bytes!([0x10, 0x32], Code::Ext1(Ext1::SingleCloseQuote), Some('’')),
1535 code_map_bytes!([0x10, 0x33], Code::Ext1(Ext1::DoubleOpenQuote), Some('“')),
1536 code_map_bytes!([0x10, 0x34], Code::Ext1(Ext1::DoubleCloseQuote), Some('”')),
1537 code_map_bytes!([0x10, 0x35], Code::Ext1(Ext1::SolidDot), None),
1538 code_map_bytes!([0x10, 0x39], Code::Ext1(Ext1::TradeMarkSign), Some('™')),
1539 code_map_bytes!(
1540 [0x10, 0x3A],
1541 Code::Ext1(Ext1::LatinLowerSWithCaron),
1542 Some('š')
1543 ),
1544 code_map_bytes!(
1545 [0x10, 0x3C],
1546 Code::Ext1(Ext1::LatinLowerLigatureOE),
1547 Some('œ')
1548 ),
1549 code_map_bytes!(
1550 [0x10, 0x3F],
1551 Code::Ext1(Ext1::LatinCapitalYWithDiaeresis),
1552 Some('Ÿ')
1553 ),
1554 code_map_bytes!([0x10, 0x76], Code::Ext1(Ext1::Fraction18), Some('⅛')),
1555 code_map_bytes!([0x10, 0x77], Code::Ext1(Ext1::Fraction38), Some('⅜')),
1556 code_map_bytes!([0x10, 0x78], Code::Ext1(Ext1::Fraction58), Some('⅝')),
1557 code_map_bytes!([0x10, 0x79], Code::Ext1(Ext1::Fraction78), Some('⅞')),
1558 code_map_bytes!([0x10, 0x7A], Code::Ext1(Ext1::VerticalBorder), None),
1559 code_map_bytes!([0x10, 0x7B], Code::Ext1(Ext1::UpperRightBorder), None),
1560 code_map_bytes!([0x10, 0x7C], Code::Ext1(Ext1::LowerLeftBorder), None),
1561 code_map_bytes!([0x10, 0x7D], Code::Ext1(Ext1::HorizontalBorder), None),
1562 code_map_bytes!([0x10, 0x7E], Code::Ext1(Ext1::LowerRightBorder), None),
1563 code_map_bytes!([0x10, 0x7F], Code::Ext1(Ext1::UpperLeftBorder), None),
1564 code_map_bytes!([0x10, 0xA0], Code::Ext1(Ext1::ClosedCaptionSign), None),
1565 code_map_single_byte!(0x20, Code::Space, Some(' ')),
1566 code_map_single_byte!(0x21, Code::ExclamationMark, Some('!')),
1567 code_map_single_byte!(0x22, Code::QuotationMark, Some('\"')),
1568 code_map_single_byte!(0x23, Code::NumberSign, Some('#')),
1569 code_map_single_byte!(0x24, Code::DollarSign, Some('$')),
1570 code_map_single_byte!(0x25, Code::PercentSign, Some('%')),
1571 code_map_single_byte!(0x26, Code::Ampersand, Some('&')),
1572 code_map_single_byte!(0x27, Code::Apostrophe, Some('\'')),
1573 code_map_single_byte!(0x28, Code::LeftParenthesis, Some('(')),
1574 code_map_single_byte!(0x29, Code::RightParenthesis, Some(')')),
1575 code_map_single_byte!(0x2A, Code::Asterisk, Some('*')),
1576 code_map_single_byte!(0x2B, Code::PlusSign, Some('+')),
1577 code_map_single_byte!(0x2C, Code::Comma, Some(',')),
1578 code_map_single_byte!(0x2D, Code::HyphenMinus, Some('-')),
1579 code_map_single_byte!(0x2E, Code::FullStop, Some('.')),
1580 code_map_single_byte!(0x2F, Code::Solidus, Some('/')),
1581 code_map_single_byte!(0x30, Code::Zero, Some('0')),
1582 code_map_single_byte!(0x31, Code::One, Some('1')),
1583 code_map_single_byte!(0x32, Code::Two, Some('2')),
1584 code_map_single_byte!(0x33, Code::Three, Some('3')),
1585 code_map_single_byte!(0x34, Code::Four, Some('4')),
1586 code_map_single_byte!(0x35, Code::Five, Some('5')),
1587 code_map_single_byte!(0x36, Code::Six, Some('6')),
1588 code_map_single_byte!(0x37, Code::Seven, Some('7')),
1589 code_map_single_byte!(0x38, Code::Eight, Some('8')),
1590 code_map_single_byte!(0x39, Code::Nine, Some('9')),
1591 code_map_single_byte!(0x3A, Code::Colon, Some(':')),
1592 code_map_single_byte!(0x3B, Code::SemiColon, Some(';')),
1593 code_map_single_byte!(0x3C, Code::LessThan, Some('<')),
1594 code_map_single_byte!(0x3D, Code::Equals, Some('=')),
1595 code_map_single_byte!(0x3E, Code::GreaterThan, Some('>')),
1596 code_map_single_byte!(0x3F, Code::QuestionMark, Some('?')),
1597 code_map_single_byte!(0x40, Code::CommercialAt, Some('@')),
1598 code_map_single_byte!(0x41, Code::LatinCapitalA, Some('A')),
1599 code_map_single_byte!(0x42, Code::LatinCapitalB, Some('B')),
1600 code_map_single_byte!(0x43, Code::LatinCapitalC, Some('C')),
1601 code_map_single_byte!(0x44, Code::LatinCapitalD, Some('D')),
1602 code_map_single_byte!(0x45, Code::LatinCapitalE, Some('E')),
1603 code_map_single_byte!(0x46, Code::LatinCapitalF, Some('F')),
1604 code_map_single_byte!(0x47, Code::LatinCapitalG, Some('G')),
1605 code_map_single_byte!(0x48, Code::LatinCapitalH, Some('H')),
1606 code_map_single_byte!(0x49, Code::LatinCapitalI, Some('I')),
1607 code_map_single_byte!(0x4A, Code::LatinCapitalJ, Some('J')),
1608 code_map_single_byte!(0x4B, Code::LatinCapitalK, Some('K')),
1609 code_map_single_byte!(0x4C, Code::LatinCapitalL, Some('L')),
1610 code_map_single_byte!(0x4D, Code::LatinCapitalM, Some('M')),
1611 code_map_single_byte!(0x4E, Code::LatinCapitalN, Some('N')),
1612 code_map_single_byte!(0x4F, Code::LatinCapitalO, Some('O')),
1613 code_map_single_byte!(0x50, Code::LatinCapitalP, Some('P')),
1614 code_map_single_byte!(0x51, Code::LatinCapitalQ, Some('Q')),
1615 code_map_single_byte!(0x52, Code::LatinCapitalR, Some('R')),
1616 code_map_single_byte!(0x53, Code::LatinCapitalS, Some('S')),
1617 code_map_single_byte!(0x54, Code::LatinCapitalT, Some('T')),
1618 code_map_single_byte!(0x55, Code::LatinCapitalU, Some('U')),
1619 code_map_single_byte!(0x56, Code::LatinCapitalV, Some('V')),
1620 code_map_single_byte!(0x57, Code::LatinCapitalW, Some('W')),
1621 code_map_single_byte!(0x58, Code::LatinCapitalX, Some('X')),
1622 code_map_single_byte!(0x59, Code::LatinCapitalY, Some('Y')),
1623 code_map_single_byte!(0x5A, Code::LatinCapitalZ, Some('Z')),
1624 code_map_single_byte!(0x5B, Code::LeftSquareBracket, Some('[')),
1625 code_map_single_byte!(0x5C, Code::ReverseSolidus, Some('\\')),
1626 code_map_single_byte!(0x5D, Code::RightSquareBracket, Some(']')),
1627 code_map_single_byte!(0x5E, Code::CircumflexAccent, Some('^')),
1628 code_map_single_byte!(0x5F, Code::LowLine, Some('_')),
1629 code_map_single_byte!(0x60, Code::GraveAccent, Some('`')),
1630 code_map_single_byte!(0x61, Code::LatinLowerA, Some('a')),
1631 code_map_single_byte!(0x62, Code::LatinLowerB, Some('b')),
1632 code_map_single_byte!(0x63, Code::LatinLowerC, Some('c')),
1633 code_map_single_byte!(0x64, Code::LatinLowerD, Some('d')),
1634 code_map_single_byte!(0x65, Code::LatinLowerE, Some('e')),
1635 code_map_single_byte!(0x66, Code::LatinLowerF, Some('f')),
1636 code_map_single_byte!(0x67, Code::LatinLowerG, Some('g')),
1637 code_map_single_byte!(0x68, Code::LatinLowerH, Some('h')),
1638 code_map_single_byte!(0x69, Code::LatinLowerI, Some('i')),
1639 code_map_single_byte!(0x6A, Code::LatinLowerJ, Some('j')),
1640 code_map_single_byte!(0x6B, Code::LatinLowerK, Some('k')),
1641 code_map_single_byte!(0x6C, Code::LatinLowerL, Some('l')),
1642 code_map_single_byte!(0x6D, Code::LatinLowerM, Some('m')),
1643 code_map_single_byte!(0x6E, Code::LatinLowerN, Some('n')),
1644 code_map_single_byte!(0x6F, Code::LatinLowerO, Some('o')),
1645 code_map_single_byte!(0x70, Code::LatinLowerP, Some('p')),
1646 code_map_single_byte!(0x71, Code::LatinLowerQ, Some('q')),
1647 code_map_single_byte!(0x72, Code::LatinLowerR, Some('r')),
1648 code_map_single_byte!(0x73, Code::LatinLowerS, Some('s')),
1649 code_map_single_byte!(0x74, Code::LatinLowerT, Some('t')),
1650 code_map_single_byte!(0x75, Code::LatinLowerU, Some('u')),
1651 code_map_single_byte!(0x76, Code::LatinLowerV, Some('v')),
1652 code_map_single_byte!(0x77, Code::LatinLowerW, Some('w')),
1653 code_map_single_byte!(0x78, Code::LatinLowerX, Some('x')),
1654 code_map_single_byte!(0x79, Code::LatinLowerY, Some('y')),
1655 code_map_single_byte!(0x7A, Code::LatinLowerZ, Some('z')),
1656 code_map_single_byte!(0x7B, Code::LeftCurlyBracket, Some('{')),
1657 code_map_single_byte!(0x7C, Code::VerticalLine, Some('|')),
1658 code_map_single_byte!(0x7D, Code::RightCurlyBracket, Some('}')),
1659 code_map_single_byte!(0x7E, Code::Tilde, Some('~')),
1660 code_map_single_byte!(0x7F, Code::MusicalSymbolEighthNote, Some('♪')),
1661 code_map_single_byte!(0x80, Code::SetCurrentWindow0, None),
1662 code_map_single_byte!(0x81, Code::SetCurrentWindow1, None),
1663 code_map_single_byte!(0x82, Code::SetCurrentWindow2, None),
1664 code_map_single_byte!(0x83, Code::SetCurrentWindow3, None),
1665 code_map_single_byte!(0x84, Code::SetCurrentWindow4, None),
1666 code_map_single_byte!(0x85, Code::SetCurrentWindow5, None),
1667 code_map_single_byte!(0x86, Code::SetCurrentWindow6, None),
1668 code_map_single_byte!(0x87, Code::SetCurrentWindow7, None),
1669 code_map_single_byte!(0x8E, Code::DelayCancel, None),
1670 code_map_single_byte!(0x8F, Code::Reset, None),
1671 code_map_single_byte!(0xA0, Code::NonBreakingSpace, Some('\u{A0}')),
1672 code_map_single_byte!(0xA1, Code::InvertedExclamationMark, Some('¡')),
1673 code_map_single_byte!(0xA2, Code::CentSign, Some('¢')),
1674 code_map_single_byte!(0xA3, Code::PoundSign, Some('£')),
1675 code_map_single_byte!(0xA4, Code::GeneralCurrencySign, Some('¤')),
1676 code_map_single_byte!(0xA5, Code::YenSign, Some('¥')),
1677 code_map_single_byte!(0xA6, Code::BrokenVerticalBar, Some('¦')),
1678 code_map_single_byte!(0xA7, Code::SectionSign, Some('§')),
1679 code_map_single_byte!(0xA8, Code::Umlaut, Some('¨')),
1680 code_map_single_byte!(0xA9, Code::CopyrightSign, Some('©')),
1681 code_map_single_byte!(0xAA, Code::FeminineOrdinalSign, Some('ª')),
1682 code_map_single_byte!(0xAB, Code::LeftDoubleAngleQuote, Some('«')),
1683 code_map_single_byte!(0xAC, Code::LogicalNotSign, Some('¬')),
1684 code_map_single_byte!(0xAD, Code::SoftHyphen, Some('\u{00ad}')),
1685 code_map_single_byte!(0xAE, Code::RegisteredTrademarkSign, Some('Ⓡ')),
1686 code_map_single_byte!(0xAF, Code::SpacingMacronLongAccent, Some('¯')),
1687 code_map_single_byte!(0xB0, Code::DegreeSign, Some('°')),
1688 code_map_single_byte!(0xB1, Code::PlusOrMinusSign, Some('±')),
1689 code_map_single_byte!(0xB2, Code::Superscript2, Some('²')),
1690 code_map_single_byte!(0xB3, Code::Superscript3, Some('³')),
1691 code_map_single_byte!(0xB4, Code::SpacingAccuteAccent, Some('´')),
1692 code_map_single_byte!(0xB5, Code::MicroSign, Some('µ')),
1693 code_map_single_byte!(0xB6, Code::ParagraphSign, Some('¶')),
1694 code_map_single_byte!(0xB7, Code::MiddleDot, Some('·')),
1695 code_map_single_byte!(0xB8, Code::SpacingCedilla, Some('¸')),
1696 code_map_single_byte!(0xB9, Code::Superscript1, Some('¹')),
1697 code_map_single_byte!(0xBA, Code::MasculineOrdinalSign, Some('º')),
1698 code_map_single_byte!(0xBB, Code::RightDoubleAngleQuote, Some('»')),
1699 code_map_single_byte!(0xBC, Code::Fraction14, Some('¼')),
1700 code_map_single_byte!(0xBD, Code::Fraction12, Some('½')),
1701 code_map_single_byte!(0xBE, Code::Fraction34, Some('¾')),
1702 code_map_single_byte!(0xBF, Code::InvertedQuestionMark, Some('¿')),
1703 code_map_single_byte!(0xC0, Code::LatinCapitalAWithGrave, Some('À')),
1704 code_map_single_byte!(0xC1, Code::LatinCapitalAWithAcute, Some('Á')),
1705 code_map_single_byte!(0xC2, Code::LatinCapitalAWithCircumflex, Some('Â')),
1706 code_map_single_byte!(0xC3, Code::LatinCapitalAWithTilde, Some('Ã')),
1707 code_map_single_byte!(0xC4, Code::LatinCapitalAWithDiaeresis, Some('Ä')),
1708 code_map_single_byte!(0xC5, Code::LatinCapitalAWithRingAbove, Some('Å')),
1709 code_map_single_byte!(0xC6, Code::LatinCapitalAe, Some('Æ')),
1710 code_map_single_byte!(0xC7, Code::LatinCapitalCWithCedilla, Some('Ç')),
1711 code_map_single_byte!(0xC8, Code::LatinCapitalEWithGrave, Some('È')),
1712 code_map_single_byte!(0xC9, Code::LatinCapitalEWithAcute, Some('É')),
1713 code_map_single_byte!(0xCA, Code::LatinCapitalEWithCircumflex, Some('Ê')),
1714 code_map_single_byte!(0xCB, Code::LatinCapitalEWithDiaeseris, Some('Ë')),
1715 code_map_single_byte!(0xCC, Code::LatinCapitalIWithGrave, Some('Ì')),
1716 code_map_single_byte!(0xCD, Code::LatinCapitalIWithAcute, Some('Í')),
1717 code_map_single_byte!(0xCE, Code::LatinCapitalIWithCircumflex, Some('Î')),
1718 code_map_single_byte!(0xCF, Code::LatinCapitalIWithDiaeseris, Some('Ï')),
1719 code_map_single_byte!(0xD0, Code::LatinCapitalEth, Some('Đ')),
1720 code_map_single_byte!(0xD1, Code::LatinCapitalNWithTilde, Some('Ñ')),
1721 code_map_single_byte!(0xD2, Code::LatinCapitalOWithGrave, Some('Ò')),
1722 code_map_single_byte!(0xD3, Code::LatinCapitalOWithAcute, Some('Ó')),
1723 code_map_single_byte!(0xD4, Code::LatinCapitalOWithCircumflex, Some('Ô')),
1724 code_map_single_byte!(0xD5, Code::LatinCapitalOWithTilde, Some('Õ')),
1725 code_map_single_byte!(0xD6, Code::LatinCapitalOWithDiaeresis, Some('Ö')),
1726 code_map_single_byte!(0xD7, Code::MultiplicationSign, Some('×')),
1727 code_map_single_byte!(0xD8, Code::LatinCapitalOWithStroke, Some('Ø')),
1728 code_map_single_byte!(0xD9, Code::LatinCapitalUWithGrave, Some('Ù')),
1729 code_map_single_byte!(0xDA, Code::LatinCapitalUWithAcute, Some('Ú')),
1730 code_map_single_byte!(0xDB, Code::LatinCapitalUWithCircumflex, Some('Û')),
1731 code_map_single_byte!(0xDC, Code::LatinCapitalUWithDiaeresis, Some('Ü')),
1732 code_map_single_byte!(0xDD, Code::LatinCapitalYWithAcute, Some('Ý')),
1733 code_map_single_byte!(0xDE, Code::LatinCapitalThorn, Some('Þ')),
1734 code_map_single_byte!(0xDF, Code::LatinLowerSharpS, Some('ß')),
1735 code_map_single_byte!(0xE0, Code::LatinLowerAWithGrave, Some('à')),
1736 code_map_single_byte!(0xE1, Code::LatinLowerAWithAcute, Some('á')),
1737 code_map_single_byte!(0xE2, Code::LatinLowerAWithCircumflex, Some('â')),
1738 code_map_single_byte!(0xE3, Code::LatinLowerAWithTilde, Some('ã')),
1739 code_map_single_byte!(0xE4, Code::LatinLowerAWithDiaeresis, Some('ä')),
1740 code_map_single_byte!(0xE5, Code::LatinLowerAWithRingAbove, Some('å')),
1741 code_map_single_byte!(0xE6, Code::LatinLowerAe, Some('æ')),
1742 code_map_single_byte!(0xE7, Code::LatinLowerCWithCedilla, Some('ç')),
1743 code_map_single_byte!(0xE8, Code::LatinLowerEWithGrave, Some('è')),
1744 code_map_single_byte!(0xE9, Code::LatinLowerEWithAcute, Some('é')),
1745 code_map_single_byte!(0xEA, Code::LatinLowerEWithCircumflex, Some('ê')),
1746 code_map_single_byte!(0xEB, Code::LatinLowerEWithDiaeseris, Some('ë')),
1747 code_map_single_byte!(0xEC, Code::LatinLowerIWithGrave, Some('ì')),
1748 code_map_single_byte!(0xED, Code::LatinLowerIWithAcute, Some('í')),
1749 code_map_single_byte!(0xEE, Code::LatinLowerIWithCircumflex, Some('î')),
1750 code_map_single_byte!(0xEF, Code::LatinLowerIWithDiaeseris, Some('ï')),
1751 code_map_single_byte!(0xF0, Code::LatinLowerEth, Some('ð')),
1752 code_map_single_byte!(0xF1, Code::LatinLowerNWithTilde, Some('ñ')),
1753 code_map_single_byte!(0xF2, Code::LatinLowerOWithGrave, Some('ò')),
1754 code_map_single_byte!(0xF3, Code::LatinLowerOWithAcute, Some('ó')),
1755 code_map_single_byte!(0xF4, Code::LatinLowerOWithCircumflex, Some('ô')),
1756 code_map_single_byte!(0xF5, Code::LatinLowerOWithTilde, Some('õ')),
1757 code_map_single_byte!(0xF6, Code::LatinLowerOWithDiaeresis, Some('ö')),
1758 code_map_single_byte!(0xF7, Code::DivisionSign, Some('÷')),
1759 code_map_single_byte!(0xF8, Code::LatinLowerOWithStroke, Some('ø')),
1760 code_map_single_byte!(0xF9, Code::LatinLowerUWithGrave, Some('ù')),
1761 code_map_single_byte!(0xFA, Code::LatinLowerUWithAcute, Some('ú')),
1762 code_map_single_byte!(0xFB, Code::LatinLowerUWithCircumflex, Some('û')),
1763 code_map_single_byte!(0xFC, Code::LatinLowerUWithDiaeresis, Some('ü')),
1764 code_map_single_byte!(0xFD, Code::LatinLowerYWithAcute, Some('ý')),
1765 code_map_single_byte!(0xFE, Code::LatinLowerThorn, Some('þ')),
1766 code_map_single_byte!(0xFF, Code::LatinLowerYWithDiaeresis, Some('ÿ')),
1767];
1768
1769macro_rules! parse_control_code {
1770 ($data:expr, $arg_len:expr, $enum_val:path) => {{
1771 let args: [u8; $arg_len] = $data[1..$arg_len + 1].try_into().unwrap();
1772 $enum_val(args.into())
1773 }};
1774}
1775
1776macro_rules! write_control_code {
1777 ($control_byte:expr, $w:expr, $args:expr, $arg_len:expr) => {{
1778 $w.write_all(&[$control_byte])?;
1779 let args: [u8; $arg_len] = $args.into();
1780 $w.write_all(&args)
1781 }};
1782}
1783
1784impl Code {
1785 fn expected_size(bytes: &[u8]) -> Result<usize, CodeError> {
1786 if bytes.is_empty() {
1787 return Err(CodeError::LengthMismatch {
1788 expected: 1,
1789 actual: 0,
1790 });
1791 }
1792 match bytes[0] {
1793 0x00..=0x0F => Ok(1),
1794 0x10 => Ok(Ext1::expected_size(&bytes[1..])? + 1),
1795 0x11..=0x17 => Ok(2),
1796 0x18..=0x1F => Ok(3),
1797 0x20..=0x7F => Ok(1),
1798 0x80..=0x87 => Ok(1), 0x88..=0x8C => Ok(2), 0x8D => Ok(2), 0x8E => Ok(1), 0x8F => Ok(1), 0x90 => Ok(3), 0x91 => Ok(4), 0x92 => Ok(3), 0x93..=0x96 => Ok(1), 0x97 => Ok(5), 0x98..=0x9F => Ok(7), 0xA0..=0xFF => Ok(1),
1810 }
1811 }
1812
1813 pub fn byte_len(&self) -> usize {
1821 if let Ok(idx) = CODE_MAP_TABLE.binary_search_by_key(&self, |code_map| &code_map.code) {
1822 return CODE_MAP_TABLE[idx].cea708_bytes.len();
1823 }
1824 match self {
1825 Code::Ext1(ext1) => ext1.byte_len(),
1826 Code::P16(_) => 3,
1827 Code::ClearWindows(_args) => 2,
1828 Code::DisplayWindows(_args) => 2,
1829 Code::HideWindows(_args) => 2,
1830 Code::ToggleWindows(_args) => 2,
1831 Code::DeleteWindows(_args) => 2,
1832 Code::SetPenAttributes(_args) => 3,
1833 Code::SetPenColor(_args) => 4,
1834 Code::SetPenLocation(_args) => 3,
1835 Code::SetWindowAttributes(_args) => 5,
1836 Code::DefineWindow(_args) => 7,
1837 Code::Unknown(data) => data.len(),
1838 _ => unreachable!(),
1839 }
1840 }
1841
1842 fn parse_element(data: &[u8]) -> Result<Code, CodeError> {
1843 let size = Code::expected_size(data)?;
1844 if data.len() > size {
1845 return Err(CodeError::LengthMismatch {
1846 expected: size,
1847 actual: data.len(),
1848 });
1849 }
1850 if let Ok(idx) =
1851 CODE_MAP_TABLE.binary_search_by_key(&data, |code_map| code_map.cea708_bytes)
1852 {
1853 return Ok(CODE_MAP_TABLE[idx].code.clone());
1854 }
1855 Ok(match data[0] {
1856 0x10 => Code::Ext1(Ext1::parse(&data[1..])?),
1857 0x18 => Code::P16((data[1] as u16) << 8 | data[2] as u16),
1858 0x88 => parse_control_code!(data, 1, Code::ClearWindows),
1859 0x89 => parse_control_code!(data, 1, Code::DisplayWindows),
1860 0x8A => parse_control_code!(data, 1, Code::HideWindows),
1861 0x8B => parse_control_code!(data, 1, Code::ToggleWindows),
1862 0x8C => parse_control_code!(data, 1, Code::DeleteWindows),
1863 0x90 => parse_control_code!(data, 2, Code::SetPenAttributes),
1864 0x91 => parse_control_code!(data, 3, Code::SetPenColor),
1865 0x92 => parse_control_code!(data, 2, Code::SetPenLocation),
1866 0x97 => parse_control_code!(data, 4, Code::SetWindowAttributes),
1867 0x98..=0x9F => {
1868 let args: [u8; 6] = data[1..7].try_into().unwrap();
1869 let args = args.into();
1870 let args = DefineWindowArgs {
1871 window_id: data[0] & 0x07,
1872 ..args
1873 };
1874 Code::DefineWindow(args)
1875 }
1876 _ => Code::Unknown(data.to_vec()),
1877 })
1878 }
1879
1880 pub fn from_data(data: &[u8]) -> Result<Vec<Code>, CodeError> {
1888 let mut data_iter = data;
1889 let mut ret = vec![];
1890 while !data_iter.is_empty() {
1891 let size = Code::expected_size(data_iter)?;
1892 if data_iter.len() < size {
1893 return Err(CodeError::LengthMismatch {
1894 expected: size,
1895 actual: data_iter.len(),
1896 });
1897 }
1898 let element = &data_iter[..size];
1899 let element = Code::parse_element(element)?;
1900 ret.push(element);
1901
1902 data_iter = &data_iter[size..];
1903 }
1904 Ok(ret)
1905 }
1906
1907 pub fn write<W: std::io::Write>(&self, w: &mut W) -> Result<(), std::io::Error> {
1917 if let Ok(idx) = CODE_MAP_TABLE.binary_search_by_key(&self, |code_map| &code_map.code) {
1918 return w.write_all(CODE_MAP_TABLE[idx].cea708_bytes);
1919 }
1920 match self {
1921 Code::Ext1(ext1) => {
1922 w.write_all(&[0x10])?;
1923 ext1.write(w)
1924 }
1925 Code::P16(c) => w.write_all(&[0x18, ((c & 0xFF00) >> 8) as u8, (c & 0xFF) as u8]),
1926 Code::ClearWindows(args) => write_control_code!(0x88, w, *args, 1),
1927 Code::DisplayWindows(args) => write_control_code!(0x89, w, *args, 1),
1928 Code::HideWindows(args) => write_control_code!(0x8A, w, *args, 1),
1929 Code::ToggleWindows(args) => write_control_code!(0x8B, w, *args, 1),
1930 Code::DeleteWindows(args) => write_control_code!(0x8C, w, *args, 1),
1931 Code::SetPenAttributes(args) => write_control_code!(0x90, w, *args, 2),
1932 Code::SetPenColor(args) => write_control_code!(0x91, w, *args, 3),
1933 Code::SetPenLocation(args) => write_control_code!(0x92, w, *args, 2),
1934 Code::SetWindowAttributes(args) => write_control_code!(0x97, w, *args, 4),
1935 Code::DefineWindow(args) => {
1936 write_control_code!(0x98 | (args.window_id & 0x07), w, *args, 6)
1937 }
1938 Code::Unknown(data) => w.write_all(data),
1939 _ => unreachable!(),
1940 }
1941 }
1942
1943 pub fn char(&self) -> Option<char> {
1953 CODE_MAP_TABLE.iter().find_map(|code_map| {
1956 if code_map.code == *self {
1957 code_map.utf8
1958 } else {
1959 None
1960 }
1961 })
1962 }
1963
1964 pub fn from_char(c: char) -> Option<Code> {
1974 CODE_MAP_TABLE.iter().find_map(|code_map| {
1977 if code_map.utf8 == Some(c) {
1978 Some(code_map.code.clone())
1979 } else {
1980 None
1981 }
1982 })
1983 }
1984}
1985
1986impl Ext1 {
1987 fn expected_size(bytes: &[u8]) -> Result<usize, CodeError> {
1988 if bytes.is_empty() {
1989 return Err(CodeError::LengthMismatch {
1990 expected: 1,
1991 actual: 0,
1992 });
1993 }
1994 match bytes[0] {
1995 0x00..=0x07 => Ok(1),
1996 0x08..=0x0F => Ok(2),
1997 0x10..=0x17 => Ok(3),
1998 0x18..=0x1F => Ok(4),
1999 0x20..=0x7F => Ok(1), 0x80..=0x87 => Ok(5),
2001 0x88..=0x8F => Ok(6),
2002 0x90..=0x9F => {
2003 if bytes.len() < 2 {
2004 return Err(CodeError::LengthMismatch {
2005 expected: 2,
2006 actual: 0,
2007 });
2008 }
2009 Ok(((bytes[1] & 0x3F) as usize) + 1)
2010 }
2011 0xA0..=0xFF => Ok(1), }
2013 }
2014
2015 fn byte_len(&self) -> usize {
2016 match self {
2018 Ext1::Unknown(data) => data.len(),
2019 _ => unreachable!(),
2020 }
2021 }
2022
2023 fn write<W: std::io::Write>(&self, w: &mut W) -> Result<(), std::io::Error> {
2024 match self {
2026 Ext1::Unknown(data) => w.write_all(data),
2027 _ => unreachable!(),
2028 }
2029 }
2030
2031 fn parse(data: &[u8]) -> Result<Ext1, CodeError> {
2032 Ok(Ext1::Unknown(data.to_vec()))
2034 }
2035}
2036
2037#[cfg(test)]
2038mod test {
2039 use super::*;
2040 use crate::tests::*;
2041 use log::trace;
2042
2043 #[test]
2044 fn codes_table_ordered() {
2045 test_init_log();
2046 let mut iter = CODE_MAP_TABLE.iter().peekable();
2047 while let Some(code_map) = iter.next() {
2048 if let Some(peek) = iter.peek() {
2049 trace!("checking ordinality for {code_map:?} and {peek:?}");
2050 assert!(peek.code > code_map.code);
2051 assert!(peek.cea708_bytes > code_map.cea708_bytes);
2052 }
2053 }
2054 }
2055
2056 static VARIABLE_TEST_CODES: [CodeMap; 10] = [
2057 code_map_bytes!(
2058 [0x9A, 0x38, 0x4A, 0xD1, 0x8B, 0x0F, 0x11],
2059 Code::DefineWindow(DefineWindowArgs::new(
2060 2,
2061 0,
2062 Anchor::BottomRight,
2063 false,
2064 74,
2065 209,
2066 11,
2067 15,
2068 true,
2069 true,
2070 true,
2071 2,
2072 1,
2073 )),
2074 None
2075 ),
2076 code_map_bytes!(
2077 [0x97, 0x64, 0x53, 0x88, 0x22],
2078 Code::SetWindowAttributes(SetWindowAttributesArgs::new(
2079 Justify::Left,
2080 Direction::LeftToRight,
2081 Direction::TopToBottom,
2082 false,
2083 DisplayEffect::Wipe,
2084 Direction::LeftToRight,
2085 2,
2086 Color::new(
2087 ColorValue::TwoThirds,
2088 ColorValue::OneThird,
2089 ColorValue::None
2090 ),
2091 Opacity::Flash,
2092 BorderType::ShadowRight,
2093 Color::new(ColorValue::OneThird, ColorValue::None, ColorValue::Full)
2094 )),
2095 None
2096 ),
2097 code_map_bytes!(
2098 [0x8B, 0xF6],
2099 Code::ToggleWindows(WindowBits::ZERO.or(WindowBits::THREE).not()),
2100 None
2101 ),
2102 code_map_bytes!(
2103 [0x8A, 0x7E],
2104 Code::HideWindows(WindowBits::ZERO.or(WindowBits::SEVEN).not()),
2105 None
2106 ),
2107 code_map_bytes!([0x89, 0x80], Code::DisplayWindows(WindowBits::SEVEN), None),
2108 code_map_bytes!(
2109 [0x8C, 0xFE],
2110 Code::DeleteWindows(WindowBits::ZERO.not()),
2111 None
2112 ),
2113 code_map_bytes!(
2114 [0x88, 0x13],
2115 Code::ClearWindows(WindowBits::ZERO.or(WindowBits::ONE).or(WindowBits::FOUR)),
2116 None
2117 ),
2118 code_map_bytes!(
2119 [0x90, 0x4A, 0xCA],
2120 Code::SetPenAttributes(SetPenAttributesArgs::new(
2121 PenSize::Large,
2122 FontStyle::ProportionallySpacedWithSerifs,
2123 TextTag::Voiceover,
2124 TextOffset::Superscript,
2125 true,
2126 true,
2127 EdgeType::Raised
2128 )),
2129 None
2130 ),
2131 code_map_bytes!(
2132 [0x91, 0x3F, 0xC0, 0x15],
2133 Code::SetPenColor(SetPenColorArgs::new(
2134 Color::new(ColorValue::Full, ColorValue::Full, ColorValue::Full),
2135 Opacity::Solid,
2136 Color::new(ColorValue::None, ColorValue::None, ColorValue::None),
2137 Opacity::Transparent,
2138 Color::new(
2139 ColorValue::OneThird,
2140 ColorValue::OneThird,
2141 ColorValue::OneThird
2142 )
2143 )),
2144 None
2145 ),
2146 code_map_bytes!(
2147 [0x92, 0x05, 0x08],
2148 Code::SetPenLocation(SetPenLocationArgs::new(5, 8)),
2149 None
2150 ),
2151 ];
2152
2153 #[test]
2154 fn codes_to_from_bytes() {
2155 test_init_log();
2156 for code_map in CODE_MAP_TABLE.iter().chain(VARIABLE_TEST_CODES.iter()) {
2157 trace!("parsing {code_map:?}");
2158 let parsed_code = Code::parse_element(code_map.cea708_bytes).unwrap();
2159 assert_eq!(parsed_code, code_map.code);
2160 let mut written = vec![];
2161 parsed_code.write(&mut written).unwrap();
2162 assert_eq!(written, code_map.cea708_bytes);
2163 assert_eq!(written.len(), code_map.code.byte_len());
2164 }
2165 }
2166
2167 #[test]
2168 fn codes_to_from_char() {
2169 test_init_log();
2170 for code_map in CODE_MAP_TABLE.iter() {
2171 trace!("parsing {code_map:?}");
2172 if let Some(c) = code_map.utf8 {
2173 let parsed_code = Code::from_char(c).unwrap();
2174 assert_eq!(parsed_code.char(), code_map.utf8);
2175 assert_eq!(parsed_code, code_map.code);
2176 let mut written = vec![];
2177 parsed_code.write(&mut written).unwrap();
2178 assert_eq!(written, code_map.cea708_bytes);
2179 }
2180 }
2181 }
2182
2183 #[test]
2184 fn define_zero_style_id() {
2185 test_init_log();
2186 let define = DefineWindowArgs::new(
2187 0,
2188 0,
2189 Anchor::BottomMiddle,
2190 true,
2191 100,
2192 50,
2193 11,
2194 31,
2195 true,
2196 true,
2197 true,
2198 0,
2199 0,
2200 );
2201 let win_attrs = define.window_attributes();
2202 assert_eq!(win_attrs.fill_opacity, Opacity::Solid);
2203 assert_eq!(win_attrs.fill_color, Color::BLACK);
2204 let pen_attrs = define.pen_attributes();
2205 assert_eq!(pen_attrs.font_style, FontStyle::Default);
2206 let pen_color = define.pen_color();
2207 assert_eq!(pen_color, PREDEFINED_PEN_STYLES_COLOR[0]);
2208 }
2209}