swf: SwfStr no longer contains encoding
SwfStr is now an unsized slice analogous to `str` or `bstr`. The desired encoding must be supplied when converting to String.
This commit is contained in:
parent
700c3c1767
commit
66256dd3be
|
@ -559,7 +559,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
Action::Return => self.action_return(),
|
Action::Return => self.action_return(),
|
||||||
Action::SetMember => self.action_set_member(),
|
Action::SetMember => self.action_set_member(),
|
||||||
Action::SetProperty => self.action_set_property(),
|
Action::SetProperty => self.action_set_property(),
|
||||||
Action::SetTarget(target) => self.action_set_target(&target.to_str_lossy()),
|
Action::SetTarget(target) => {
|
||||||
|
self.action_set_target(&target.to_str_lossy(self.encoding()))
|
||||||
|
}
|
||||||
Action::SetTarget2 => self.action_set_target2(),
|
Action::SetTarget2 => self.action_set_target2(),
|
||||||
Action::SetVariable => self.action_set_variable(),
|
Action::SetVariable => self.action_set_variable(),
|
||||||
Action::StackSwap => self.action_stack_swap(),
|
Action::StackSwap => self.action_stack_swap(),
|
||||||
|
@ -889,13 +891,13 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
|
|
||||||
fn action_constant_pool(
|
fn action_constant_pool(
|
||||||
&mut self,
|
&mut self,
|
||||||
constant_pool: &[SwfStr<'_>],
|
constant_pool: &[&'_ SwfStr],
|
||||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
self.context.avm1.constant_pool = GcCell::allocate(
|
self.context.avm1.constant_pool = GcCell::allocate(
|
||||||
self.context.gc_context,
|
self.context.gc_context,
|
||||||
constant_pool
|
constant_pool
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| (*s).to_string_lossy())
|
.map(|s| (*s).to_string_lossy(self.encoding()))
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
self.set_constant_pool(self.context.avm1.constant_pool);
|
self.set_constant_pool(self.context.avm1.constant_pool);
|
||||||
|
@ -911,11 +913,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
|
|
||||||
fn action_define_function(
|
fn action_define_function(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: SwfStr<'_>,
|
name: &'_ SwfStr,
|
||||||
params: &[SwfStr<'_>],
|
params: &[&'_ SwfStr],
|
||||||
actions: SwfSlice,
|
actions: SwfSlice,
|
||||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
let name = name.to_str_lossy();
|
let name = name.to_str_lossy(self.encoding());
|
||||||
let name = name.as_ref();
|
let name = name.as_ref();
|
||||||
let swf_version = self.swf_version();
|
let swf_version = self.swf_version();
|
||||||
let scope = Scope::new_closure_scope(self.scope_cell(), self.context.gc_context);
|
let scope = Scope::new_closure_scope(self.scope_cell(), self.context.gc_context);
|
||||||
|
@ -982,7 +984,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
if action_func.name.is_empty() {
|
if action_func.name.is_empty() {
|
||||||
self.context.avm1.push(func_obj);
|
self.context.avm1.push(func_obj);
|
||||||
} else {
|
} else {
|
||||||
self.define(&action_func.name.to_str_lossy(), func_obj);
|
self.define(&action_func.name.to_str_lossy(self.encoding()), func_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
|
@ -1220,12 +1222,12 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
|
|
||||||
fn action_get_url(
|
fn action_get_url(
|
||||||
&mut self,
|
&mut self,
|
||||||
url: SwfStr<'_>,
|
url: &'_ SwfStr,
|
||||||
target: SwfStr<'_>,
|
target: &'_ SwfStr,
|
||||||
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
let target = target.to_str_lossy();
|
let target = target.to_str_lossy(self.encoding());
|
||||||
let target = target.as_ref();
|
let target = target.as_ref();
|
||||||
let url = url.to_string_lossy();
|
let url = url.to_string_lossy(self.encoding());
|
||||||
if target.starts_with("_level") && target.len() > 6 {
|
if target.starts_with("_level") && target.len() > 6 {
|
||||||
match target[6..].parse::<u32>() {
|
match target[6..].parse::<u32>() {
|
||||||
Ok(level_id) => {
|
Ok(level_id) => {
|
||||||
|
@ -1425,13 +1427,15 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action_goto_label(&mut self, label: SwfStr<'_>) -> Result<FrameControl<'gc>, Error<'gc>> {
|
fn action_goto_label(&mut self, label: &'_ SwfStr) -> Result<FrameControl<'gc>, Error<'gc>> {
|
||||||
if let Some(clip) = self.target_clip() {
|
if let Some(clip) = self.target_clip() {
|
||||||
if let Some(clip) = clip.as_movie_clip() {
|
if let Some(clip) = clip.as_movie_clip() {
|
||||||
if let Some(frame) = clip.frame_label_to_number(&label.to_str_lossy()) {
|
if let Some(frame) =
|
||||||
|
clip.frame_label_to_number(&label.to_str_lossy(self.encoding()))
|
||||||
|
{
|
||||||
clip.goto_frame(&mut self.context, frame, true);
|
clip.goto_frame(&mut self.context, frame, true);
|
||||||
} else {
|
} else {
|
||||||
avm_warn!(self, "GoToLabel: Frame label '{}' not found", label);
|
avm_warn!(self, "GoToLabel: Frame label '{:?}' not found", label);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
avm_warn!(self, "GoToLabel: Target is not a MovieClip");
|
avm_warn!(self, "GoToLabel: Target is not a MovieClip");
|
||||||
|
@ -1776,7 +1780,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
SwfValue::Float(v) => f64::from(*v).into(),
|
SwfValue::Float(v) => f64::from(*v).into(),
|
||||||
SwfValue::Double(v) => (*v).into(),
|
SwfValue::Double(v) => (*v).into(),
|
||||||
SwfValue::Str(v) => {
|
SwfValue::Str(v) => {
|
||||||
AvmString::new(self.context.gc_context, v.to_string_lossy()).into()
|
AvmString::new(self.context.gc_context, v.to_string_lossy(self.encoding()))
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
SwfValue::Register(v) => self.current_register(*v),
|
SwfValue::Register(v) => self.current_register(*v),
|
||||||
SwfValue::ConstantPool(i) => {
|
SwfValue::ConstantPool(i) => {
|
||||||
|
@ -2279,9 +2284,10 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
);
|
);
|
||||||
|
|
||||||
match catch_vars {
|
match catch_vars {
|
||||||
CatchVar::Var(name) => {
|
CatchVar::Var(name) => activation.set_variable(
|
||||||
activation.set_variable(&name.to_str_lossy(), value.to_owned())?
|
&name.to_str_lossy(activation.encoding()),
|
||||||
}
|
value.to_owned(),
|
||||||
|
)?,
|
||||||
CatchVar::Register(id) => {
|
CatchVar::Register(id) => {
|
||||||
activation.set_current_register(*id, value.to_owned())
|
activation.set_current_register(*id, value.to_owned())
|
||||||
}
|
}
|
||||||
|
@ -2874,6 +2880,14 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
self.scope_cell().read().is_defined(self, name)
|
self.scope_cell().read().is_defined(self, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the suggested string encoding for actions.
|
||||||
|
/// For SWF version 6 and higher, this is always UTF-8.
|
||||||
|
/// For SWF version 5 and lower, this is locale-dependent,
|
||||||
|
/// and we default to WINDOWS-1252.
|
||||||
|
pub fn encoding(&self) -> &'static swf::Encoding {
|
||||||
|
swf::SwfStr::encoding_for_version(self.swf_version)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the SWF version of the action or function being executed.
|
/// Returns the SWF version of the action or function being executed.
|
||||||
pub fn swf_version(&self) -> u8 {
|
pub fn swf_version(&self) -> u8 {
|
||||||
self.swf_version
|
self.swf_version
|
||||||
|
|
|
@ -94,7 +94,7 @@ impl<'gc> Avm1Function<'gc> {
|
||||||
swf_version: u8,
|
swf_version: u8,
|
||||||
actions: SwfSlice,
|
actions: SwfSlice,
|
||||||
name: &str,
|
name: &str,
|
||||||
params: &[SwfStr<'_>],
|
params: &[&'_ SwfStr],
|
||||||
scope: GcCell<'gc, Scope<'gc>>,
|
scope: GcCell<'gc, Scope<'gc>>,
|
||||||
constant_pool: GcCell<'gc, Vec<String>>,
|
constant_pool: GcCell<'gc, Vec<String>>,
|
||||||
base_clip: DisplayObject<'gc>,
|
base_clip: DisplayObject<'gc>,
|
||||||
|
@ -121,7 +121,12 @@ impl<'gc> Avm1Function<'gc> {
|
||||||
preload_global: false,
|
preload_global: false,
|
||||||
params: params
|
params: params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&s| (None, s.to_string_lossy()))
|
.map(|&s| {
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
s.to_string_lossy(SwfStr::encoding_for_version(swf_version)),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
scope,
|
scope,
|
||||||
constant_pool,
|
constant_pool,
|
||||||
|
@ -141,7 +146,11 @@ impl<'gc> Avm1Function<'gc> {
|
||||||
let name = if swf_function.name.is_empty() {
|
let name = if swf_function.name.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(swf_function.name.to_string_lossy())
|
Some(
|
||||||
|
swf_function
|
||||||
|
.name
|
||||||
|
.to_string_lossy(SwfStr::encoding_for_version(swf_version)),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut owned_params = Vec::new();
|
let mut owned_params = Vec::new();
|
||||||
|
@ -150,7 +159,10 @@ impl<'gc> Avm1Function<'gc> {
|
||||||
register_index: r,
|
register_index: r,
|
||||||
} in &swf_function.params
|
} in &swf_function.params
|
||||||
{
|
{
|
||||||
owned_params.push((*r, (*s).to_string_lossy()))
|
owned_params.push((
|
||||||
|
*r,
|
||||||
|
(*s).to_string_lossy(SwfStr::encoding_for_version(swf_version)),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
Avm1Function {
|
Avm1Function {
|
||||||
|
|
|
@ -841,7 +841,9 @@ pub trait TDisplayObject<'gc>:
|
||||||
self.set_color_transform(gc_context, &color_transform.clone().into());
|
self.set_color_transform(gc_context, &color_transform.clone().into());
|
||||||
}
|
}
|
||||||
if let Some(name) = &place_object.name {
|
if let Some(name) = &place_object.name {
|
||||||
self.set_name(gc_context, &name.to_str_lossy());
|
let encoding = swf::SwfStr::encoding_for_version(self.swf_version());
|
||||||
|
let name = name.to_str_lossy(encoding);
|
||||||
|
self.set_name(gc_context, &name);
|
||||||
}
|
}
|
||||||
if let Some(clip_depth) = place_object.clip_depth {
|
if let Some(clip_depth) = place_object.clip_depth {
|
||||||
self.set_clip_depth(gc_context, clip_depth.into());
|
self.set_clip_depth(gc_context, clip_depth.into());
|
||||||
|
|
|
@ -152,11 +152,12 @@ impl<'gc> EditText<'gc> {
|
||||||
let document = XMLDocument::new(context.gc_context);
|
let document = XMLDocument::new(context.gc_context);
|
||||||
let text = swf_tag.initial_text.clone().unwrap_or_default();
|
let text = swf_tag.initial_text.clone().unwrap_or_default();
|
||||||
let default_format = TextFormat::from_swf_tag(swf_tag.clone(), swf_movie.clone(), context);
|
let default_format = TextFormat::from_swf_tag(swf_tag.clone(), swf_movie.clone(), context);
|
||||||
|
let encoding = swf_movie.encoding();
|
||||||
|
|
||||||
let mut text_spans = FormatSpans::new();
|
let mut text_spans = FormatSpans::new();
|
||||||
text_spans.set_default_format(default_format.clone());
|
text_spans.set_default_format(default_format.clone());
|
||||||
|
|
||||||
let text = text.to_str_lossy();
|
let text = text.to_str_lossy(encoding);
|
||||||
if is_html {
|
if is_html {
|
||||||
let _ = document
|
let _ = document
|
||||||
.as_node()
|
.as_node()
|
||||||
|
@ -193,7 +194,7 @@ impl<'gc> EditText<'gc> {
|
||||||
base.matrix_mut(context.gc_context).ty = bounds.y_min;
|
base.matrix_mut(context.gc_context).ty = bounds.y_min;
|
||||||
|
|
||||||
let variable = if !swf_tag.variable_name.is_empty() {
|
let variable = if !swf_tag.variable_name.is_empty() {
|
||||||
Some(swf_tag.variable_name.clone())
|
Some(swf_tag.variable_name)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -212,13 +213,15 @@ impl<'gc> EditText<'gc> {
|
||||||
id: swf_tag.id,
|
id: swf_tag.id,
|
||||||
bounds: swf_tag.bounds,
|
bounds: swf_tag.bounds,
|
||||||
font_id: swf_tag.font_id,
|
font_id: swf_tag.font_id,
|
||||||
font_class_name: swf_tag.font_class_name.map(|s| s.to_string_lossy()),
|
font_class_name: swf_tag
|
||||||
|
.font_class_name
|
||||||
|
.map(|s| s.to_string_lossy(encoding)),
|
||||||
height: swf_tag.height,
|
height: swf_tag.height,
|
||||||
color: swf_tag.color.clone(),
|
color: swf_tag.color.clone(),
|
||||||
max_length: swf_tag.max_length,
|
max_length: swf_tag.max_length,
|
||||||
layout: swf_tag.layout.clone(),
|
layout: swf_tag.layout.clone(),
|
||||||
variable_name: swf_tag.variable_name.to_string_lossy(),
|
variable_name: swf_tag.variable_name.to_string_lossy(encoding),
|
||||||
initial_text: swf_tag.initial_text.map(|s| s.to_string_lossy()),
|
initial_text: swf_tag.initial_text.map(|s| s.to_string_lossy(encoding)),
|
||||||
is_word_wrap: swf_tag.is_word_wrap,
|
is_word_wrap: swf_tag.is_word_wrap,
|
||||||
is_multiline: swf_tag.is_multiline,
|
is_multiline: swf_tag.is_multiline,
|
||||||
is_password: swf_tag.is_password,
|
is_password: swf_tag.is_password,
|
||||||
|
@ -247,7 +250,7 @@ impl<'gc> EditText<'gc> {
|
||||||
intrinsic_bounds,
|
intrinsic_bounds,
|
||||||
bounds,
|
bounds,
|
||||||
autosize: AutoSizeMode::None,
|
autosize: AutoSizeMode::None,
|
||||||
variable: variable.map(|s| s.to_string_lossy()),
|
variable: variable.map(|s| s.to_string_lossy(encoding)),
|
||||||
bound_stage_object: None,
|
bound_stage_object: None,
|
||||||
firing_variable_binding: false,
|
firing_variable_binding: false,
|
||||||
selection: None,
|
selection: None,
|
||||||
|
@ -620,7 +623,7 @@ impl<'gc> EditText<'gc> {
|
||||||
.initial_text
|
.initial_text
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let _ = self.set_text(text.to_string(), &mut activation.context);
|
let _ = self.set_text(text, &mut activation.context);
|
||||||
|
|
||||||
self.0.write(activation.context.gc_context).variable = variable;
|
self.0.write(activation.context.gc_context).variable = variable;
|
||||||
self.try_bind_text_field_variable(activation, true);
|
self.try_bind_text_field_variable(activation, true);
|
||||||
|
|
|
@ -459,7 +459,7 @@ impl<'gc> MovieClip<'gc> {
|
||||||
// giving us a `SwfSlice` for later parsing, so we have to replcate the
|
// giving us a `SwfSlice` for later parsing, so we have to replcate the
|
||||||
// *entire* parsing code here. This sucks.
|
// *entire* parsing code here. This sucks.
|
||||||
let flags = reader.read_u32()?;
|
let flags = reader.read_u32()?;
|
||||||
let name = reader.read_string()?.to_string_lossy();
|
let name = reader.read_string()?.to_string_lossy(reader.encoding());
|
||||||
let is_lazy_initialize = flags & 1 != 0;
|
let is_lazy_initialize = flags & 1 != 0;
|
||||||
let domain = library.avm2_domain();
|
let domain = library.avm2_domain();
|
||||||
|
|
||||||
|
@ -499,7 +499,7 @@ impl<'gc> MovieClip<'gc> {
|
||||||
|
|
||||||
for _ in 0..num_symbols {
|
for _ in 0..num_symbols {
|
||||||
let id = reader.read_u16()?;
|
let id = reader.read_u16()?;
|
||||||
let class_name = reader.read_string()?.to_string_lossy();
|
let class_name = reader.read_string()?.to_string_lossy(reader.encoding());
|
||||||
|
|
||||||
if let Some(name) =
|
if let Some(name) =
|
||||||
Avm2QName::from_symbol_class(&class_name, activation.context.gc_context)
|
Avm2QName::from_symbol_class(&class_name, activation.context.gc_context)
|
||||||
|
@ -565,10 +565,11 @@ impl<'gc> MovieClip<'gc> {
|
||||||
.map(|fld| fld.frame_num + 1)
|
.map(|fld| fld.frame_num + 1)
|
||||||
.unwrap_or_else(|| static_data.total_frames as u32 + 1);
|
.unwrap_or_else(|| static_data.total_frames as u32 + 1);
|
||||||
|
|
||||||
|
let label = label.to_string_lossy(reader.encoding());
|
||||||
static_data.scene_labels.insert(
|
static_data.scene_labels.insert(
|
||||||
label.to_string(),
|
label.clone(),
|
||||||
Scene {
|
Scene {
|
||||||
name: label.to_string(),
|
name: label,
|
||||||
start,
|
start,
|
||||||
length: end as u16 - start as u16,
|
length: end as u16 - start as u16,
|
||||||
},
|
},
|
||||||
|
@ -576,9 +577,10 @@ impl<'gc> MovieClip<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for FrameLabelData { frame_num, label } in sfl_data.frame_labels {
|
for FrameLabelData { frame_num, label } in sfl_data.frame_labels {
|
||||||
static_data
|
static_data.frame_labels.insert(
|
||||||
.frame_labels
|
label.to_string_lossy(reader.encoding()),
|
||||||
.insert(label.to_string(), frame_num as u16 + 1);
|
frame_num as u16 + 1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2468,7 +2470,13 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
is_bold: false,
|
is_bold: false,
|
||||||
is_italic: false,
|
is_italic: false,
|
||||||
};
|
};
|
||||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
let font_object = Font::from_swf_tag(
|
||||||
|
context.gc_context,
|
||||||
|
context.renderer,
|
||||||
|
&font,
|
||||||
|
reader.encoding(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
.library_for_movie_mut(self.movie())
|
.library_for_movie_mut(self.movie())
|
||||||
|
@ -2483,7 +2491,13 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
reader: &mut SwfStream<'a>,
|
reader: &mut SwfStream<'a>,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let font = reader.read_define_font_2(2)?;
|
let font = reader.read_define_font_2(2)?;
|
||||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
let font_object = Font::from_swf_tag(
|
||||||
|
context.gc_context,
|
||||||
|
context.renderer,
|
||||||
|
&font,
|
||||||
|
reader.encoding(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
.library_for_movie_mut(self.movie())
|
.library_for_movie_mut(self.movie())
|
||||||
|
@ -2498,7 +2512,13 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
reader: &mut SwfStream<'a>,
|
reader: &mut SwfStream<'a>,
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let font = reader.read_define_font_2(3)?;
|
let font = reader.read_define_font_2(3)?;
|
||||||
let font_object = Font::from_swf_tag(context.gc_context, context.renderer, &font).unwrap();
|
let font_object = Font::from_swf_tag(
|
||||||
|
context.gc_context,
|
||||||
|
context.renderer,
|
||||||
|
&font,
|
||||||
|
reader.encoding(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
context
|
context
|
||||||
.library
|
.library
|
||||||
.library_for_movie_mut(self.movie())
|
.library_for_movie_mut(self.movie())
|
||||||
|
@ -2606,15 +2626,16 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let exports = reader.read_export_assets()?;
|
let exports = reader.read_export_assets()?;
|
||||||
for export in exports {
|
for export in exports {
|
||||||
|
let name = export.name.to_str_lossy(reader.encoding());
|
||||||
let character = context
|
let character = context
|
||||||
.library
|
.library
|
||||||
.library_for_movie_mut(self.movie())
|
.library_for_movie_mut(self.movie())
|
||||||
.register_export(export.id, &export.name.to_str_lossy());
|
.register_export(export.id, &name);
|
||||||
|
|
||||||
// TODO: do other types of Character need to know their exported name?
|
// TODO: do other types of Character need to know their exported name?
|
||||||
if let Some(Character::MovieClip(movie_clip)) = character {
|
if let Some(Character::MovieClip(movie_clip)) = character {
|
||||||
*movie_clip.0.read().static_data.exported_name.borrow_mut() =
|
*movie_clip.0.read().static_data.exported_name.borrow_mut() =
|
||||||
Some(export.name.to_string());
|
Some(name.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2631,7 +2652,10 @@ impl<'gc, 'a> MovieClipData<'gc> {
|
||||||
) -> DecodeResult {
|
) -> DecodeResult {
|
||||||
let frame_label = reader.read_frame_label(tag_len)?;
|
let frame_label = reader.read_frame_label(tag_len)?;
|
||||||
// Frame labels are case insensitive (ASCII).
|
// Frame labels are case insensitive (ASCII).
|
||||||
let label = frame_label.label.to_str_lossy().to_ascii_lowercase();
|
let label = frame_label
|
||||||
|
.label
|
||||||
|
.to_str_lossy(reader.encoding())
|
||||||
|
.to_ascii_lowercase();
|
||||||
if let std::collections::hash_map::Entry::Vacant(v) = static_data.frame_labels.entry(label)
|
if let std::collections::hash_map::Entry::Vacant(v) = static_data.frame_labels.entry(label)
|
||||||
{
|
{
|
||||||
v.insert(cur_frame);
|
v.insert(cur_frame);
|
||||||
|
|
|
@ -101,6 +101,7 @@ impl<'gc> Font<'gc> {
|
||||||
gc_context: MutationContext<'gc, '_>,
|
gc_context: MutationContext<'gc, '_>,
|
||||||
renderer: &mut dyn RenderBackend,
|
renderer: &mut dyn RenderBackend,
|
||||||
tag: &swf::Font,
|
tag: &swf::Font,
|
||||||
|
encoding: &'static swf::Encoding,
|
||||||
) -> Result<Font<'gc>, Error> {
|
) -> Result<Font<'gc>, Error> {
|
||||||
let mut glyphs = vec![];
|
let mut glyphs = vec![];
|
||||||
let mut code_point_to_glyph = fnv::FnvHashMap::default();
|
let mut code_point_to_glyph = fnv::FnvHashMap::default();
|
||||||
|
@ -124,7 +125,7 @@ impl<'gc> Font<'gc> {
|
||||||
fnv::FnvHashMap::default()
|
fnv::FnvHashMap::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let descriptor = FontDescriptor::from_swf_tag(tag);
|
let descriptor = FontDescriptor::from_swf_tag(tag, encoding);
|
||||||
let (ascent, descent, leading) = if let Some(layout) = &tag.layout {
|
let (ascent, descent, leading) = if let Some(layout) = &tag.layout {
|
||||||
(layout.ascent, layout.descent, layout.leading)
|
(layout.ascent, layout.descent, layout.leading)
|
||||||
} else {
|
} else {
|
||||||
|
@ -392,12 +393,8 @@ pub struct FontDescriptor {
|
||||||
|
|
||||||
impl FontDescriptor {
|
impl FontDescriptor {
|
||||||
/// Obtain a font descriptor from a SWF font tag.
|
/// Obtain a font descriptor from a SWF font tag.
|
||||||
pub fn from_swf_tag(val: &swf::Font) -> Self {
|
pub fn from_swf_tag(val: &swf::Font, encoding: &'static swf::Encoding) -> Self {
|
||||||
let mut name = val.name.to_string();
|
let name = val.name.to_string_lossy(encoding);
|
||||||
|
|
||||||
if let Some(first_null) = name.find('\0') {
|
|
||||||
name.truncate(first_null);
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -193,12 +193,12 @@ impl TextFormat {
|
||||||
swf_movie: Arc<SwfMovie>,
|
swf_movie: Arc<SwfMovie>,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let encoding = swf_movie.encoding();
|
||||||
let movie_library = context.library.library_for_movie_mut(swf_movie);
|
let movie_library = context.library.library_for_movie_mut(swf_movie);
|
||||||
|
|
||||||
let font = et.font_id.and_then(|fid| movie_library.get_font(fid));
|
let font = et.font_id.and_then(|fid| movie_library.get_font(fid));
|
||||||
let font_class = et
|
let font_class = et
|
||||||
.font_class_name
|
.font_class_name
|
||||||
.map(|s| s.to_string_lossy())
|
.map(|s| s.to_string_lossy(encoding))
|
||||||
.or_else(|| font.map(|font| font.descriptor().class().to_string()))
|
.or_else(|| font.map(|font| font.descriptor().class().to_string()))
|
||||||
.unwrap_or_else(|| "Times New Roman".to_string());
|
.unwrap_or_else(|| "Times New Roman".to_string());
|
||||||
let align = et.layout.clone().map(|l| l.align);
|
let align = et.layout.clone().map(|l| l.align);
|
||||||
|
@ -211,7 +211,7 @@ impl TextFormat {
|
||||||
// Times New Roman non-bold, non-italic. This will need to be revised
|
// Times New Roman non-bold, non-italic. This will need to be revised
|
||||||
// when we start supporting device fonts.
|
// when we start supporting device fonts.
|
||||||
Self {
|
Self {
|
||||||
font: Some(font_class.to_string()),
|
font: Some(font_class),
|
||||||
size: et.height.map(|h| h.to_pixels()),
|
size: et.height.map(|h| h.to_pixels()),
|
||||||
color: et.color,
|
color: et.color,
|
||||||
align,
|
align,
|
||||||
|
|
|
@ -1281,8 +1281,12 @@ impl Player {
|
||||||
renderer: &mut dyn RenderBackend,
|
renderer: &mut dyn RenderBackend,
|
||||||
) -> Result<crate::font::Font<'gc>, Error> {
|
) -> Result<crate::font::Font<'gc>, Error> {
|
||||||
let mut reader = swf::read::Reader::new(data, 8);
|
let mut reader = swf::read::Reader::new(data, 8);
|
||||||
let device_font =
|
let device_font = crate::font::Font::from_swf_tag(
|
||||||
crate::font::Font::from_swf_tag(gc_context, renderer, &reader.read_define_font_2(3)?)?;
|
gc_context,
|
||||||
|
renderer,
|
||||||
|
&reader.read_define_font_2(3)?,
|
||||||
|
reader.encoding(),
|
||||||
|
)?;
|
||||||
Ok(device_font)
|
Ok(device_font)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ pub struct SwfMovie {
|
||||||
|
|
||||||
/// Any parameters provided when loading this movie (also known as 'flashvars')
|
/// Any parameters provided when loading this movie (also known as 'flashvars')
|
||||||
parameters: PropertyMap<String>,
|
parameters: PropertyMap<String>,
|
||||||
|
|
||||||
|
/// The suggest encoding for this SWF.
|
||||||
|
encoding: &'static swf::Encoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SwfMovie {
|
impl SwfMovie {
|
||||||
|
@ -42,6 +45,7 @@ impl SwfMovie {
|
||||||
data: vec![],
|
data: vec![],
|
||||||
url: None,
|
url: None,
|
||||||
parameters: PropertyMap::new(),
|
parameters: PropertyMap::new(),
|
||||||
|
encoding: swf::UTF_8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +60,7 @@ impl SwfMovie {
|
||||||
data,
|
data,
|
||||||
url: source.url.clone(),
|
url: source.url.clone(),
|
||||||
parameters: source.parameters.clone(),
|
parameters: source.parameters.clone(),
|
||||||
|
encoding: source.encoding,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +79,13 @@ impl SwfMovie {
|
||||||
/// Construct a movie based on the contents of the SWF datastream.
|
/// Construct a movie based on the contents of the SWF datastream.
|
||||||
pub fn from_data(swf_data: &[u8], url: Option<String>) -> Result<Self, Error> {
|
pub fn from_data(swf_data: &[u8], url: Option<String>) -> Result<Self, Error> {
|
||||||
let swf_buf = swf::read::decompress_swf(&swf_data[..])?;
|
let swf_buf = swf::read::decompress_swf(&swf_data[..])?;
|
||||||
|
let encoding = swf::SwfStr::encoding_for_version(swf_buf.header.version);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
header: swf_buf.header,
|
header: swf_buf.header,
|
||||||
data: swf_buf.data,
|
data: swf_buf.data,
|
||||||
url,
|
url,
|
||||||
parameters: PropertyMap::new(),
|
parameters: PropertyMap::new(),
|
||||||
|
encoding,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +102,14 @@ impl SwfMovie {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the suggested string encoding for the given SWF version.
|
||||||
|
/// For SWF version 6 and higher, this is always UTF-8.
|
||||||
|
/// For SWF version 5 and lower, this is locale-dependent,
|
||||||
|
/// and we default to WINDOWS-1252.
|
||||||
|
pub fn encoding(&self) -> &'static swf::Encoding {
|
||||||
|
self.encoding
|
||||||
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> u32 {
|
pub fn width(&self) -> u32 {
|
||||||
(self.header.stage_size.x_max - self.header.stage_size.x_min).to_pixels() as u32
|
(self.header.stage_size.x_max - self.header.stage_size.x_min).to_pixels() as u32
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::avm1::{opcode::OpCode, types::*};
|
use crate::avm1::{opcode::OpCode, types::*};
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::read::SwfReadExt;
|
use crate::read::SwfReadExt;
|
||||||
use crate::string::SwfStr;
|
use crate::string::{Encoding, SwfStr, UTF_8, WINDOWS_1252};
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
|
|
||||||
|
@ -11,27 +11,35 @@ use std::io::{self, Read};
|
||||||
pub struct Reader<'a> {
|
pub struct Reader<'a> {
|
||||||
input: &'a [u8],
|
input: &'a [u8],
|
||||||
version: u8,
|
version: u8,
|
||||||
encoding: &'static encoding_rs::Encoding,
|
encoding: &'static Encoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Reader<'a> {
|
impl<'a> Reader<'a> {
|
||||||
|
#[inline]
|
||||||
pub fn new(input: &'a [u8], version: u8) -> Self {
|
pub fn new(input: &'a [u8], version: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
input,
|
input,
|
||||||
version,
|
version,
|
||||||
encoding: if version > 5 {
|
encoding: if version > 5 {
|
||||||
encoding_rs::UTF_8
|
UTF_8
|
||||||
} else {
|
} else {
|
||||||
// TODO: Allow configurable encoding
|
// TODO: Allow configurable encoding
|
||||||
encoding_rs::WINDOWS_1252
|
WINDOWS_1252
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn encoding(&self) -> &'static Encoding {
|
||||||
|
SwfStr::encoding_for_version(self.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn get_ref(&self) -> &'a [u8] {
|
pub fn get_ref(&self) -> &'a [u8] {
|
||||||
self.input
|
self.input
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn get_mut(&mut self) -> &mut &'a [u8] {
|
pub fn get_mut(&mut self) -> &mut &'a [u8] {
|
||||||
&mut self.input
|
&mut self.input
|
||||||
}
|
}
|
||||||
|
@ -49,7 +57,7 @@ impl<'a> Reader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_string(&mut self) -> io::Result<SwfStr<'a>> {
|
pub fn read_string(&mut self) -> io::Result<&'a SwfStr> {
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
loop {
|
loop {
|
||||||
let byte = *self.input.get(pos).ok_or_else(|| {
|
let byte = *self.input.get(pos).ok_or_else(|| {
|
||||||
|
@ -63,7 +71,7 @@ impl<'a> Reader<'a> {
|
||||||
|
|
||||||
let s = unsafe {
|
let s = unsafe {
|
||||||
let slice = self.input.get_unchecked(..pos);
|
let slice = self.input.get_unchecked(..pos);
|
||||||
SwfStr::from_bytes_unchecked(slice, self.encoding)
|
SwfStr::from_bytes(slice)
|
||||||
};
|
};
|
||||||
self.input = &self.input[pos + 1..];
|
self.input = &self.input[pos + 1..];
|
||||||
Ok(s)
|
Ok(s)
|
||||||
|
@ -483,7 +491,6 @@ pub mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_define_function() {
|
fn read_define_function() {
|
||||||
use encoding_rs::WINDOWS_1252;
|
|
||||||
// Ensure we read a function properly along with the function data.
|
// Ensure we read a function properly along with the function data.
|
||||||
let action_bytes = vec![
|
let action_bytes = vec![
|
||||||
0x9b, 0x08, 0x00, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x96, 0x06, 0x00,
|
0x9b, 0x08, 0x00, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x96, 0x06, 0x00,
|
||||||
|
|
|
@ -18,11 +18,11 @@ pub enum Action<'a> {
|
||||||
CastOp,
|
CastOp,
|
||||||
CharToAscii,
|
CharToAscii,
|
||||||
CloneSprite,
|
CloneSprite,
|
||||||
ConstantPool(Vec<SwfStr<'a>>),
|
ConstantPool(Vec<&'a SwfStr>),
|
||||||
Decrement,
|
Decrement,
|
||||||
DefineFunction {
|
DefineFunction {
|
||||||
name: SwfStr<'a>,
|
name: &'a SwfStr,
|
||||||
params: Vec<SwfStr<'a>>,
|
params: Vec<&'a SwfStr>,
|
||||||
actions: &'a [u8],
|
actions: &'a [u8],
|
||||||
},
|
},
|
||||||
DefineFunction2(Function<'a>),
|
DefineFunction2(Function<'a>),
|
||||||
|
@ -41,8 +41,8 @@ pub enum Action<'a> {
|
||||||
GetProperty,
|
GetProperty,
|
||||||
GetTime,
|
GetTime,
|
||||||
GetUrl {
|
GetUrl {
|
||||||
url: SwfStr<'a>,
|
url: &'a SwfStr,
|
||||||
target: SwfStr<'a>,
|
target: &'a SwfStr,
|
||||||
},
|
},
|
||||||
GetUrl2 {
|
GetUrl2 {
|
||||||
send_vars_method: SendVarsMethod,
|
send_vars_method: SendVarsMethod,
|
||||||
|
@ -55,7 +55,7 @@ pub enum Action<'a> {
|
||||||
set_playing: bool,
|
set_playing: bool,
|
||||||
scene_offset: u16,
|
scene_offset: u16,
|
||||||
},
|
},
|
||||||
GotoLabel(SwfStr<'a>),
|
GotoLabel(&'a SwfStr),
|
||||||
Greater,
|
Greater,
|
||||||
If {
|
If {
|
||||||
offset: i16,
|
offset: i16,
|
||||||
|
@ -91,7 +91,7 @@ pub enum Action<'a> {
|
||||||
Return,
|
Return,
|
||||||
SetMember,
|
SetMember,
|
||||||
SetProperty,
|
SetProperty,
|
||||||
SetTarget(SwfStr<'a>),
|
SetTarget(&'a SwfStr),
|
||||||
SetTarget2,
|
SetTarget2,
|
||||||
SetVariable,
|
SetVariable,
|
||||||
StackSwap,
|
StackSwap,
|
||||||
|
@ -140,7 +140,7 @@ pub enum Value<'a> {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Float(f32),
|
Float(f32),
|
||||||
Double(f64),
|
Double(f64),
|
||||||
Str(SwfStr<'a>),
|
Str(&'a SwfStr),
|
||||||
Register(u8),
|
Register(u8),
|
||||||
ConstantPool(u16),
|
ConstantPool(u16),
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ pub enum SendVarsMethod {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Function<'a> {
|
pub struct Function<'a> {
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
pub register_count: u8,
|
pub register_count: u8,
|
||||||
pub params: Vec<FunctionParam<'a>>,
|
pub params: Vec<FunctionParam<'a>>,
|
||||||
pub preload_parent: bool,
|
pub preload_parent: bool,
|
||||||
|
@ -171,7 +171,7 @@ pub struct Function<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct FunctionParam<'a> {
|
pub struct FunctionParam<'a> {
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
pub register_index: Option<u8>,
|
pub register_index: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +184,6 @@ pub struct TryBlock<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum CatchVar<'a> {
|
pub enum CatchVar<'a> {
|
||||||
Var(SwfStr<'a>),
|
Var(&'a SwfStr),
|
||||||
Register(u8),
|
Register(u8),
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ impl<W: Write> SwfWriteExt for Writer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> {
|
fn write_string(&mut self, s: &'_ SwfStr) -> io::Result<()> {
|
||||||
self.output.write_all(s.as_bytes())?;
|
self.output.write_all(s.as_bytes())?;
|
||||||
self.write_u8(0)
|
self.write_u8(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ impl<W: Write> SwfWriteExt for Writer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> {
|
fn write_string(&mut self, s: &'_ SwfStr) -> io::Result<()> {
|
||||||
self.output.write_all(s.as_bytes())?;
|
self.output.write_all(s.as_bytes())?;
|
||||||
self.write_u8(0)
|
self.write_u8(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
string::SwfStr,
|
string::{Encoding, SwfStr},
|
||||||
types::*,
|
types::*,
|
||||||
};
|
};
|
||||||
use bitstream_io::BitRead;
|
use bitstream_io::BitRead;
|
||||||
|
@ -248,28 +248,30 @@ impl<'a, 'b> BitReader<'a, 'b> {
|
||||||
pub struct Reader<'a> {
|
pub struct Reader<'a> {
|
||||||
input: &'a [u8],
|
input: &'a [u8],
|
||||||
version: u8,
|
version: u8,
|
||||||
encoding: &'static encoding_rs::Encoding,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Reader<'a> {
|
impl<'a> Reader<'a> {
|
||||||
|
#[inline]
|
||||||
pub fn new(input: &'a [u8], version: u8) -> Reader<'a> {
|
pub fn new(input: &'a [u8], version: u8) -> Reader<'a> {
|
||||||
Reader {
|
Reader { input, version }
|
||||||
input,
|
|
||||||
version,
|
|
||||||
encoding: if version > 5 {
|
|
||||||
encoding_rs::UTF_8
|
|
||||||
} else {
|
|
||||||
// TODO: Allow configurable encoding
|
|
||||||
encoding_rs::WINDOWS_1252
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the suggested string encoding for this SWF.
|
||||||
|
/// For SWF version 6 and higher, this is always UTF-8.
|
||||||
|
/// For SWF version 5 and lower, this is locale-dependent,
|
||||||
|
/// and we default to WINDOWS-1252.
|
||||||
|
#[inline]
|
||||||
|
pub fn encoding(&self) -> &'static Encoding {
|
||||||
|
SwfStr::encoding_for_version(self.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn version(&self) -> u8 {
|
pub fn version(&self) -> u8 {
|
||||||
self.version
|
self.version
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the underlying `Reader`.
|
/// Returns a reference to the underlying `Reader`.
|
||||||
|
#[inline]
|
||||||
pub fn get_ref(&self) -> &'a [u8] {
|
pub fn get_ref(&self) -> &'a [u8] {
|
||||||
self.input
|
self.input
|
||||||
}
|
}
|
||||||
|
@ -277,6 +279,7 @@ impl<'a> Reader<'a> {
|
||||||
/// Returns a mutable reference to the underlying `Reader`.
|
/// Returns a mutable reference to the underlying `Reader`.
|
||||||
///
|
///
|
||||||
/// Reading from this reference is not recommended.
|
/// Reading from this reference is not recommended.
|
||||||
|
#[inline]
|
||||||
pub fn get_mut(&mut self) -> &mut &'a [u8] {
|
pub fn get_mut(&mut self) -> &mut &'a [u8] {
|
||||||
&mut self.input
|
&mut self.input
|
||||||
}
|
}
|
||||||
|
@ -317,7 +320,7 @@ impl<'a> Reader<'a> {
|
||||||
slice
|
slice
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_string(&mut self) -> io::Result<SwfStr<'a>> {
|
pub fn read_string(&mut self) -> io::Result<&'a SwfStr> {
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
loop {
|
loop {
|
||||||
let byte = *self.input.get(pos).ok_or_else(|| {
|
let byte = *self.input.get(pos).ok_or_else(|| {
|
||||||
|
@ -329,16 +332,14 @@ impl<'a> Reader<'a> {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let s = unsafe {
|
let slice = unsafe { self.input.get_unchecked(..pos) };
|
||||||
let slice = self.input.get_unchecked(..pos);
|
let s = SwfStr::from_bytes(slice);
|
||||||
SwfStr::from_bytes_unchecked(slice, self.encoding)
|
|
||||||
};
|
|
||||||
self.input = &self.input[pos + 1..];
|
self.input = &self.input[pos + 1..];
|
||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_string_with_len(&mut self, len: usize) -> io::Result<SwfStr<'a>> {
|
fn read_string_with_len(&mut self, len: usize) -> io::Result<&'a SwfStr> {
|
||||||
Ok(SwfStr::from_bytes(&self.read_slice(len)?, self.encoding))
|
Ok(SwfStr::from_bytes_null_terminated(&self.read_slice(len)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the next SWF tag from the stream.
|
/// Reads the next SWF tag from the stream.
|
||||||
|
|
|
@ -1,58 +1,49 @@
|
||||||
//! String typed used by SWF files.
|
//! String type used by SWF files.
|
||||||
//!
|
|
||||||
//! Allows for locale-dependent encoding for SWF version <6.
|
|
||||||
|
|
||||||
use encoding_rs::{Encoding, UTF_8};
|
pub use encoding_rs::{Encoding, SHIFT_JIS, UTF_8, WINDOWS_1252};
|
||||||
use std::{borrow::Cow, fmt};
|
use std::{borrow::Cow, fmt};
|
||||||
|
|
||||||
/// `SwfStr` is returned by SWF and AVM1 parsing functions.
|
/// `SwfStr` is the string type returned by SWF parsing functions.
|
||||||
/// `SwfStr` is analogous to `&str`, with some additional allowances:
|
/// `SwfStr` is a bstr-like type analogous to `str`:
|
||||||
/// * An encoding is specified along with the string data.
|
/// * The encoding depends on the SWF version (UTF-8 for SWF6 and higher).
|
||||||
/// * The string contains no null bytes.
|
/// Use `Reader::encoding` or `SwfStr::encoding_for_version` to get the
|
||||||
|
/// proper encoding.
|
||||||
/// * Invalid data for any particular encoding is allowed;
|
/// * Invalid data for any particular encoding is allowed;
|
||||||
/// any conversions to std::String will be lossy for invalid data.
|
/// any conversions to std::String will be lossy for invalid data.
|
||||||
/// This handles the locale dependent encoding of early SWF files and
|
|
||||||
/// mimics C-style null-terminated string behavior.
|
|
||||||
/// To convert this to a standard Rust string, use `SwfStr::to_str_lossy`.
|
/// To convert this to a standard Rust string, use `SwfStr::to_str_lossy`.
|
||||||
/// `SwfStr`s are equal if both their encoding and data matches.
|
#[derive(Eq, PartialEq)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[repr(transparent)]
|
||||||
pub struct SwfStr<'a> {
|
pub struct SwfStr {
|
||||||
/// The string bytes.
|
/// The string bytes.
|
||||||
string: &'a [u8],
|
string: [u8],
|
||||||
|
|
||||||
/// The encoding of the string data.
|
|
||||||
encoding: &'static Encoding,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SwfStr<'a> {
|
impl SwfStr {
|
||||||
/// Create a new `SwfStr` from a byte slice with a given encoding.
|
/// Create a new `SwfStr` from a byte slice with a given encoding.
|
||||||
/// The string will be truncated if a null byte is encountered.
|
/// The string will be truncated if a null byte is encountered.
|
||||||
/// The data is not required to be valid for the given encoding.
|
/// The data is not required to be valid for the given encoding.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_bytes(string: &'a [u8], encoding: &'static Encoding) -> Self {
|
pub fn from_bytes(string: &[u8]) -> &Self {
|
||||||
let i = string.iter().position(|&c| c == 0).unwrap_or(string.len());
|
unsafe { &*(string as *const [u8] as *const Self) }
|
||||||
Self {
|
|
||||||
string: &string[..i],
|
|
||||||
encoding,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `SwfStr` from a byte slice with a given encoding.
|
|
||||||
/// The data is not required to be valid for the given encoding.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The string should contain no null bytes.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_bytes_unchecked(string: &'a [u8], encoding: &'static Encoding) -> Self {
|
pub fn from_bytes_null_terminated(string: &[u8]) -> &Self {
|
||||||
Self { string, encoding }
|
let i = string.iter().position(|&c| c == 0).unwrap_or(string.len());
|
||||||
|
Self::from_bytes(&string[..i])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new UTF-8 `SwfStr` from a Rust `str`.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_utf8_str(string: &str) -> &Self {
|
||||||
|
Self::from_bytes(string.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new UTF-8 `SwfStr` from a Rust `str`.
|
/// Create a new UTF-8 `SwfStr` from a Rust `str`.
|
||||||
/// The string will be truncated if a null byte is encountered.
|
/// The string will be truncated if a null byte is encountered.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_utf8_str(string: &'a str) -> Self {
|
pub fn from_utf8_str_null_terminated(string: &str) -> &Self {
|
||||||
Self::from_bytes(string.as_bytes(), UTF_8)
|
Self::from_bytes_null_terminated(string.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `SwfStr` with the given encoding from a Rust `str`.
|
/// Create a new `SwfStr` with the given encoding from a Rust `str`.
|
||||||
|
@ -60,24 +51,34 @@ impl<'a> SwfStr<'a> {
|
||||||
/// The string will be truncated if a null byte is encountered.
|
/// The string will be truncated if a null byte is encountered.
|
||||||
/// `None` is returned if the encoding is not lossless.
|
/// `None` is returned if the encoding is not lossless.
|
||||||
/// Intended for tests.
|
/// Intended for tests.
|
||||||
pub fn from_str_with_encoding(string: &'a str, encoding: &'static Encoding) -> Option<Self> {
|
pub fn from_str_with_encoding<'a>(
|
||||||
|
string: &'a str,
|
||||||
|
encoding: &'static Encoding,
|
||||||
|
) -> Option<&'a Self> {
|
||||||
if let (Cow::Borrowed(s), _, false) = encoding.encode(&string) {
|
if let (Cow::Borrowed(s), _, false) = encoding.encode(&string) {
|
||||||
Some(Self::from_bytes(s, encoding))
|
Some(Self::from_bytes(s))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the byte slice of this string.
|
/// Returns the suggested string encoding for the given SWF version.
|
||||||
|
/// For SWF version 6 and higher, this is always UTF-8.
|
||||||
|
/// For SWF version 5 and lower, this is locale-dependent,
|
||||||
|
/// and we default to WINDOWS-1252.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_bytes(&self) -> &'a [u8] {
|
pub fn encoding_for_version(swf_version: u8) -> &'static Encoding {
|
||||||
self.string
|
if swf_version >= 6 {
|
||||||
|
UTF_8
|
||||||
|
} else {
|
||||||
|
WINDOWS_1252
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the encoding used by this string.
|
/// Returns the byte slice of this string.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn encoding(&self) -> &'static Encoding {
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
self.encoding
|
&self.string
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the string has a length of zero, and `false` otherwise.
|
/// Returns `true` if the string has a length of zero, and `false` otherwise.
|
||||||
|
@ -95,47 +96,40 @@ impl<'a> SwfStr<'a> {
|
||||||
/// Decodes the string into a Rust UTF-8 `str`.
|
/// Decodes the string into a Rust UTF-8 `str`.
|
||||||
/// The UTF-8 replacement character will be uses for any invalid data.
|
/// The UTF-8 replacement character will be uses for any invalid data.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_str_lossy(&self) -> Cow<'a, str> {
|
pub fn to_str_lossy(&self, encoding: &'static Encoding) -> Cow<'_, str> {
|
||||||
self.encoding.decode_without_bom_handling(self.string).0
|
encoding.decode_without_bom_handling(&self.string).0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes the string into a Rust UTF-8 `String`.
|
/// Decodes the string into a Rust UTF-8 `String`.
|
||||||
/// The UTF-8 replacement character will be uses for any invalid data.
|
/// The UTF-8 replacement character will be uses for any invalid data.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_string_lossy(&self) -> String {
|
pub fn to_string_lossy(&self, encoding: &'static Encoding) -> String {
|
||||||
self.to_str_lossy().into_owned()
|
self.to_str_lossy(encoding).into_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for SwfStr<'a> {
|
impl<'a> Default for &'a SwfStr {
|
||||||
fn default() -> Self {
|
fn default() -> &'a SwfStr {
|
||||||
Self {
|
SwfStr::from_bytes(&[])
|
||||||
string: &[],
|
|
||||||
encoding: UTF_8,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for SwfStr<'a> {
|
impl<'a> From<&'a str> for &'a SwfStr {
|
||||||
fn from(s: &'a str) -> Self {
|
fn from(s: &'a str) -> &'a SwfStr {
|
||||||
SwfStr::from_utf8_str(s)
|
SwfStr::from_utf8_str(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: AsRef<str>> PartialEq<T> for SwfStr<'a> {
|
impl<'a, T: ?Sized + AsRef<str>> PartialEq<T> for SwfStr {
|
||||||
fn eq(&self, other: &T) -> bool {
|
fn eq(&self, other: &T) -> bool {
|
||||||
self.string == other.as_ref().as_bytes()
|
&self.string == other.as_ref().as_bytes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for SwfStr<'a> {
|
impl fmt::Debug for SwfStr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.to_str_lossy())
|
// Note that this assumes UTF-8 encoding;
|
||||||
}
|
// other encodings like Shift-JIS will output gibberish.
|
||||||
}
|
f.write_str(&self.to_str_lossy(UTF_8))
|
||||||
|
|
||||||
impl<'a> fmt::Debug for SwfStr<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.to_str_lossy())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,10 @@ use crate::avm2::read::tests::read_abc_from_file;
|
||||||
use crate::avm2::types::*;
|
use crate::avm2::types::*;
|
||||||
use crate::read::tests::{read_tag_bytes_from_file, read_tag_bytes_from_file_with_index};
|
use crate::read::tests::{read_tag_bytes_from_file, read_tag_bytes_from_file_with_index};
|
||||||
use crate::read::{decompress_swf, parse_swf};
|
use crate::read::{decompress_swf, parse_swf};
|
||||||
use crate::string::SwfStr;
|
use crate::string::{SwfStr, WINDOWS_1252};
|
||||||
use crate::tag_code::TagCode;
|
use crate::tag_code::TagCode;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::write::write_swf;
|
use crate::write::write_swf;
|
||||||
use encoding_rs::WINDOWS_1252;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ pub struct FileAttributes {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct FrameLabel<'a> {
|
pub struct FrameLabel<'a> {
|
||||||
pub label: SwfStr<'a>,
|
pub label: &'a SwfStr,
|
||||||
pub is_anchor: bool,
|
pub is_anchor: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ pub struct DefineSceneAndFrameLabelData<'a> {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct FrameLabelData<'a> {
|
pub struct FrameLabelData<'a> {
|
||||||
pub frame_num: u32,
|
pub frame_num: u32,
|
||||||
pub label: SwfStr<'a>,
|
pub label: &'a SwfStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Depth = u16;
|
pub type Depth = u16;
|
||||||
|
@ -274,9 +274,9 @@ pub struct PlaceObject<'a> {
|
||||||
pub matrix: Option<Matrix>,
|
pub matrix: Option<Matrix>,
|
||||||
pub color_transform: Option<ColorTransform>,
|
pub color_transform: Option<ColorTransform>,
|
||||||
pub ratio: Option<u16>,
|
pub ratio: Option<u16>,
|
||||||
pub name: Option<SwfStr<'a>>,
|
pub name: Option<&'a SwfStr>,
|
||||||
pub clip_depth: Option<Depth>,
|
pub clip_depth: Option<Depth>,
|
||||||
pub class_name: Option<SwfStr<'a>>,
|
pub class_name: Option<&'a SwfStr>,
|
||||||
pub filters: Option<Vec<Filter>>,
|
pub filters: Option<Vec<Filter>>,
|
||||||
pub background_color: Option<Color>,
|
pub background_color: Option<Color>,
|
||||||
pub blend_mode: Option<BlendMode>,
|
pub blend_mode: Option<BlendMode>,
|
||||||
|
@ -472,7 +472,7 @@ pub enum Tag<'a> {
|
||||||
},
|
},
|
||||||
ShowFrame,
|
ShowFrame,
|
||||||
|
|
||||||
Protect(Option<SwfStr<'a>>),
|
Protect(Option<&'a SwfStr>),
|
||||||
CsmTextSettings(CsmTextSettings),
|
CsmTextSettings(CsmTextSettings),
|
||||||
DebugId(DebugId),
|
DebugId(DebugId),
|
||||||
DefineBinaryData {
|
DefineBinaryData {
|
||||||
|
@ -505,8 +505,8 @@ pub enum Tag<'a> {
|
||||||
DefineFontInfo(Box<FontInfo<'a>>),
|
DefineFontInfo(Box<FontInfo<'a>>),
|
||||||
DefineFontName {
|
DefineFontName {
|
||||||
id: CharacterId,
|
id: CharacterId,
|
||||||
name: SwfStr<'a>,
|
name: &'a SwfStr,
|
||||||
copyright_info: SwfStr<'a>,
|
copyright_info: &'a SwfStr,
|
||||||
},
|
},
|
||||||
DefineMorphShape(Box<DefineMorphShape>),
|
DefineMorphShape(Box<DefineMorphShape>),
|
||||||
DefineScalingGrid {
|
DefineScalingGrid {
|
||||||
|
@ -524,14 +524,14 @@ pub enum Tag<'a> {
|
||||||
id: CharacterId,
|
id: CharacterId,
|
||||||
action_data: &'a [u8],
|
action_data: &'a [u8],
|
||||||
},
|
},
|
||||||
EnableDebugger(SwfStr<'a>),
|
EnableDebugger(&'a SwfStr),
|
||||||
EnableTelemetry {
|
EnableTelemetry {
|
||||||
password_hash: &'a [u8],
|
password_hash: &'a [u8],
|
||||||
},
|
},
|
||||||
End,
|
End,
|
||||||
Metadata(SwfStr<'a>),
|
Metadata(&'a SwfStr),
|
||||||
ImportAssets {
|
ImportAssets {
|
||||||
url: SwfStr<'a>,
|
url: &'a SwfStr,
|
||||||
imports: Vec<ExportedAsset<'a>>,
|
imports: Vec<ExportedAsset<'a>>,
|
||||||
},
|
},
|
||||||
JpegTables(JpegTables<'a>),
|
JpegTables(JpegTables<'a>),
|
||||||
|
@ -545,7 +545,7 @@ pub enum Tag<'a> {
|
||||||
SoundStreamHead2(Box<SoundStreamHead>),
|
SoundStreamHead2(Box<SoundStreamHead>),
|
||||||
StartSound(StartSound),
|
StartSound(StartSound),
|
||||||
StartSound2 {
|
StartSound2 {
|
||||||
class_name: SwfStr<'a>,
|
class_name: &'a SwfStr,
|
||||||
sound_info: Box<SoundInfo>,
|
sound_info: Box<SoundInfo>,
|
||||||
},
|
},
|
||||||
SymbolClass(Vec<SymbolClassLink<'a>>),
|
SymbolClass(Vec<SymbolClassLink<'a>>),
|
||||||
|
@ -570,7 +570,7 @@ pub type ExportAssets<'a> = Vec<ExportedAsset<'a>>;
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ExportedAsset<'a> {
|
pub struct ExportedAsset<'a> {
|
||||||
pub id: CharacterId,
|
pub id: CharacterId,
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -584,7 +584,7 @@ pub type SetBackgroundColor = Color;
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct SymbolClassLink<'a> {
|
pub struct SymbolClassLink<'a> {
|
||||||
pub id: CharacterId,
|
pub id: CharacterId,
|
||||||
pub class_name: SwfStr<'a>,
|
pub class_name: &'a SwfStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -897,7 +897,7 @@ pub struct FontV1 {
|
||||||
pub struct Font<'a> {
|
pub struct Font<'a> {
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
pub id: CharacterId,
|
pub id: CharacterId,
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
pub language: Language,
|
pub language: Language,
|
||||||
pub layout: Option<FontLayout>,
|
pub layout: Option<FontLayout>,
|
||||||
pub glyphs: Vec<Glyph>,
|
pub glyphs: Vec<Glyph>,
|
||||||
|
@ -913,7 +913,7 @@ pub struct Font4<'a> {
|
||||||
pub id: CharacterId,
|
pub id: CharacterId,
|
||||||
pub is_italic: bool,
|
pub is_italic: bool,
|
||||||
pub is_bold: bool,
|
pub is_bold: bool,
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
pub data: Option<&'a [u8]>,
|
pub data: Option<&'a [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,7 +944,7 @@ pub struct KerningRecord {
|
||||||
pub struct FontInfo<'a> {
|
pub struct FontInfo<'a> {
|
||||||
pub id: CharacterId,
|
pub id: CharacterId,
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
pub is_small_text: bool,
|
pub is_small_text: bool,
|
||||||
pub is_shift_jis: bool,
|
pub is_shift_jis: bool,
|
||||||
pub is_ansi: bool,
|
pub is_ansi: bool,
|
||||||
|
@ -983,13 +983,13 @@ pub struct EditText<'a> {
|
||||||
pub id: CharacterId,
|
pub id: CharacterId,
|
||||||
pub bounds: Rectangle,
|
pub bounds: Rectangle,
|
||||||
pub font_id: Option<CharacterId>, // TODO(Herschel): Combine with height
|
pub font_id: Option<CharacterId>, // TODO(Herschel): Combine with height
|
||||||
pub font_class_name: Option<SwfStr<'a>>,
|
pub font_class_name: Option<&'a SwfStr>,
|
||||||
pub height: Option<Twips>,
|
pub height: Option<Twips>,
|
||||||
pub color: Option<Color>,
|
pub color: Option<Color>,
|
||||||
pub max_length: Option<u16>,
|
pub max_length: Option<u16>,
|
||||||
pub layout: Option<TextLayout>,
|
pub layout: Option<TextLayout>,
|
||||||
pub variable_name: SwfStr<'a>,
|
pub variable_name: &'a SwfStr,
|
||||||
pub initial_text: Option<SwfStr<'a>>,
|
pub initial_text: Option<&'a SwfStr>,
|
||||||
pub is_word_wrap: bool,
|
pub is_word_wrap: bool,
|
||||||
pub is_multiline: bool,
|
pub is_multiline: bool,
|
||||||
pub is_password: bool,
|
pub is_password: bool,
|
||||||
|
@ -1116,7 +1116,7 @@ pub struct DefineBitsJpeg3<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct DoAbc<'a> {
|
pub struct DoAbc<'a> {
|
||||||
pub name: SwfStr<'a>,
|
pub name: &'a SwfStr,
|
||||||
pub is_lazy_initialize: bool,
|
pub is_lazy_initialize: bool,
|
||||||
pub data: &'a [u8],
|
pub data: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ pub trait SwfWriteExt {
|
||||||
fn write_i32(&mut self, n: i32) -> io::Result<()>;
|
fn write_i32(&mut self, n: i32) -> io::Result<()>;
|
||||||
fn write_f32(&mut self, n: f32) -> io::Result<()>;
|
fn write_f32(&mut self, n: f32) -> io::Result<()>;
|
||||||
fn write_f64(&mut self, n: f64) -> io::Result<()>;
|
fn write_f64(&mut self, n: f64) -> io::Result<()>;
|
||||||
fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()>;
|
fn write_string(&mut self, s: &'_ SwfStr) -> io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BitWriter<W: Write> {
|
pub struct BitWriter<W: Write> {
|
||||||
|
@ -257,7 +257,7 @@ impl<W: Write> SwfWriteExt for Writer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_string(&mut self, s: SwfStr<'_>) -> io::Result<()> {
|
fn write_string(&mut self, s: &'_ SwfStr) -> io::Result<()> {
|
||||||
self.output.write_all(s.as_bytes())?;
|
self.output.write_all(s.as_bytes())?;
|
||||||
self.write_u8(0)
|
self.write_u8(0)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue