Parcourir la source

Implement DefMid

Isaac Woods il y a 3 ans
Parent
commit
a37008df12
3 fichiers modifiés avec 67 ajouts et 5 suppressions
  1. 6 4
      aml/src/lib.rs
  2. 1 0
      aml/src/opcode.rs
  3. 60 1
      aml/src/type2.rs

+ 6 - 4
aml/src/lib.rs

@@ -715,10 +715,6 @@ pub enum AmlError {
     InvalidNameSeg,
     InvalidPkgLength,
     InvalidFieldFlags,
-    IncompatibleValueConversion {
-        current: AmlType,
-        target: AmlType,
-    },
     UnterminatedStringConstant,
     InvalidStringConstant,
     InvalidRegionSpace(u8),
@@ -785,6 +781,10 @@ pub enum AmlError {
     /*
      * Errors produced working with AML values.
      */
+    IncompatibleValueConversion {
+        current: AmlType,
+        target: AmlType,
+    },
     InvalidStatusObject,
     InvalidShiftLeft,
     InvalidShiftRight,
@@ -792,6 +792,8 @@ pub enum AmlError {
     FieldInvalidAddress,
     FieldInvalidAccessSize,
     TypeCannotBeCompared(AmlType),
+    /// Produced when the `Mid` operator is applied to a value of a type other than `Buffer` or `String`.
+    TypeCannotBeSliced(AmlType),
 }
 
 #[cfg(test)]

+ 1 - 0
aml/src/opcode.rs

@@ -59,6 +59,7 @@ pub const DEF_L_NOT_OP: u8 = 0x92;
 pub const DEF_L_EQUAL_OP: u8 = 0x93;
 pub const DEF_L_GREATER_OP: u8 = 0x94;
 pub const DEF_L_LESS_OP: u8 = 0x95;
+pub const DEF_MID_OP: u8 = 0x9e;
 
 /*
  * Miscellaneous objects

+ 60 - 1
aml/src/type2.rs

@@ -18,7 +18,11 @@ use crate::{
     AmlError,
     DebugVerbosity,
 };
-use alloc::{vec, vec::Vec};
+use alloc::{
+    string::{String, ToString},
+    vec,
+    vec::Vec,
+};
 use core::{cmp::Ordering, convert::TryInto, mem};
 
 /// Type 2 opcodes return a value and so can be used in expressions.
@@ -53,6 +57,7 @@ where
             def_l_less_equal(),
             def_l_not_equal(),
             def_l_or(),
+            def_mid(),
             def_package(),
             def_shift_left(),
             def_shift_right(),
@@ -390,6 +395,60 @@ where
         .map(|(((), ()), result)| Ok(result))
 }
 
+fn def_mid<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
+where
+    'c: 'a,
+{
+    /*
+     * DefMid := 0x9e MidObj TermArg TermArg Target
+     * MidObj := TermArg => Buffer | String
+     */
+    opcode(opcode::DEF_MID_OP)
+        .then(comment_scope(
+            DebugVerbosity::AllScopes,
+            "DefMid",
+            term_arg().then(term_arg()).then(term_arg()).then(target()).map_with_context(
+                |(((source, index), length), target), context| {
+                    let index = try_with_context!(context, index.as_integer(context)) as usize;
+                    let length = try_with_context!(context, length.as_integer(context)) as usize;
+
+                    let result = try_with_context!(
+                        context,
+                        match source {
+                            AmlValue::Buffer(bytes) => {
+                                if index >= bytes.len() {
+                                    Ok(AmlValue::Buffer(vec![]))
+                                } else if (index + length) >= bytes.len() {
+                                    Ok(AmlValue::Buffer(bytes[index..].to_vec()))
+                                } else {
+                                    Ok(AmlValue::Buffer(bytes[index..(index + length)].to_vec()))
+                                }
+                            }
+                            /*
+                             * XXX: The spec conflates characters and bytes, so we effectively ignore unicode and do
+                             * this bytewise, to hopefully match other implementations.
+                             */
+                            AmlValue::String(string) => {
+                                if index >= string.len() {
+                                    Ok(AmlValue::String(String::new()))
+                                } else if (index + length) >= string.len() {
+                                    Ok(AmlValue::String(string[index..].to_string()))
+                                } else {
+                                    Ok(AmlValue::String(string[index..(index + length)].to_string()))
+                                }
+                            }
+                            _ => Err(AmlError::TypeCannotBeSliced(source.type_of())),
+                        }
+                    );
+
+                    try_with_context!(context, context.store(target, result.clone()));
+                    (Ok(result), context)
+                },
+            ),
+        ))
+        .map(|((), result)| Ok(result))
+}
+
 pub fn def_package<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
 where
     'c: 'a,