@@ -327,11 +327,12 @@ where
327327 | Opcode :: LLess => {
328328 self . do_logical_op ( & mut context, op) ?;
329329 }
330- Opcode :: ToBuffer
331- | Opcode :: ToDecimalString
332- | Opcode :: ToHexString
333- | Opcode :: ToInteger
334- | Opcode :: ToString => todo ! ( ) ,
330+ Opcode :: ToBuffer => self . do_to_buffer ( & mut context, op) ?,
331+ Opcode :: ToInteger => self . do_to_integer ( & mut context, op) ?,
332+ Opcode :: ToString => self . do_to_string ( & mut context, op) ?,
333+ Opcode :: ToDecimalString | Opcode :: ToHexString => {
334+ self . do_to_dec_hex_string ( & mut context, op) ?
335+ }
335336 Opcode :: Mid => self . do_mid ( & mut context, op) ?,
336337 Opcode :: Concat => self . do_concat ( & mut context, op) ?,
337338 Opcode :: ConcatRes => {
@@ -1202,11 +1203,10 @@ where
12021203 context. start_in_flight_op ( OpInFlight :: new ( opcode, 2 ) ) ;
12031204 }
12041205
1205- Opcode :: ToBuffer
1206- | Opcode :: ToDecimalString
1207- | Opcode :: ToHexString
1208- | Opcode :: ToInteger
1209- | Opcode :: ToString => context. start_in_flight_op ( OpInFlight :: new ( opcode, 2 ) ) ,
1206+ Opcode :: ToBuffer | Opcode :: ToDecimalString | Opcode :: ToHexString | Opcode :: ToInteger => {
1207+ context. start_in_flight_op ( OpInFlight :: new ( opcode, 2 ) )
1208+ }
1209+ Opcode :: ToString => context. start_in_flight_op ( OpInFlight :: new ( opcode, 3 ) ) ,
12101210
12111211 Opcode :: ObjectType => context. start_in_flight_op ( OpInFlight :: new ( opcode, 1 ) ) ,
12121212 Opcode :: CopyObject => todo ! ( ) ,
@@ -1485,6 +1485,140 @@ where
14851485 Ok ( ( ) )
14861486 }
14871487
1488+ fn do_to_buffer ( & self , context : & mut MethodContext , op : OpInFlight ) -> Result < ( ) , AmlError > {
1489+ let [ Argument :: Object ( operand) , target] = & op. arguments [ ..] else { panic ! ( ) } ;
1490+
1491+ let result = Arc :: new ( match * * operand {
1492+ Object :: Buffer ( ref bytes) => Object :: Buffer ( bytes. clone ( ) ) ,
1493+ Object :: Integer ( value) => {
1494+ if self . dsdt_revision >= 2 {
1495+ Object :: Buffer ( value. to_le_bytes ( ) . to_vec ( ) )
1496+ } else {
1497+ Object :: Buffer ( ( value as u32 ) . to_le_bytes ( ) . to_vec ( ) )
1498+ }
1499+ }
1500+ Object :: String ( ref value) => {
1501+ // XXX: an empty string is converted to an empty buffer, *without* the null-terminator
1502+ if value. is_empty ( ) {
1503+ Object :: Buffer ( vec ! [ ] )
1504+ } else {
1505+ let mut bytes = value. as_bytes ( ) . to_vec ( ) ;
1506+ bytes. push ( b'\0' ) ;
1507+ Object :: Buffer ( bytes)
1508+ }
1509+ }
1510+ _ => Err ( AmlError :: InvalidOperationOnObject { op : Operation :: ToBuffer , typ : operand. typ ( ) } ) ?,
1511+ } ) ;
1512+
1513+ // TODO: use result of store
1514+ self . do_store ( target, result. clone ( ) ) ?;
1515+ context. contribute_arg ( Argument :: Object ( result) ) ;
1516+ Ok ( ( ) )
1517+ }
1518+
1519+ fn do_to_integer ( & self , context : & mut MethodContext , op : OpInFlight ) -> Result < ( ) , AmlError > {
1520+ let [ Argument :: Object ( operand) , target] = & op. arguments [ ..] else { panic ! ( ) } ;
1521+
1522+ let result = Arc :: new ( match * * operand {
1523+ Object :: Integer ( value) => Object :: Integer ( value) ,
1524+ Object :: Buffer ( ref bytes) => {
1525+ /*
1526+ * The spec says this should respect the revision of the current definition block.
1527+ * Apparently, the NT interpreter always uses the first 8 bytes of the buffer.
1528+ */
1529+ let mut to_interpret = [ 0u8 ; 8 ] ;
1530+ ( to_interpret[ 0 ..usize:: min ( bytes. len ( ) , 8 ) ] ) . copy_from_slice ( & bytes) ;
1531+ Object :: Integer ( u64:: from_le_bytes ( to_interpret) )
1532+ }
1533+ Object :: String ( ref value) => {
1534+ if let Some ( value) = value. strip_prefix ( "0x" ) {
1535+ let parsed = u64:: from_str_radix ( value, 16 ) . map_err ( |_| {
1536+ AmlError :: InvalidOperationOnObject { op : Operation :: ToInteger , typ : ObjectType :: String }
1537+ } ) ?;
1538+ Object :: Integer ( parsed)
1539+ } else {
1540+ let parsed = u64:: from_str_radix ( value, 10 ) . map_err ( |_| {
1541+ AmlError :: InvalidOperationOnObject { op : Operation :: ToInteger , typ : ObjectType :: String }
1542+ } ) ?;
1543+ Object :: Integer ( parsed)
1544+ }
1545+ }
1546+ _ => Err ( AmlError :: InvalidOperationOnObject { op : Operation :: ToBuffer , typ : operand. typ ( ) } ) ?,
1547+ } ) ;
1548+
1549+ // TODO: use result of store
1550+ self . do_store ( target, result. clone ( ) ) ?;
1551+ context. contribute_arg ( Argument :: Object ( result) ) ;
1552+ Ok ( ( ) )
1553+ }
1554+
1555+ fn do_to_string ( & self , context : & mut MethodContext , op : OpInFlight ) -> Result < ( ) , AmlError > {
1556+ let [ Argument :: Object ( source) , Argument :: Object ( length) , target] = & op. arguments [ ..] else { panic ! ( ) } ;
1557+ let source = source. as_buffer ( ) ?;
1558+ let length = length. as_integer ( ) ? as usize ;
1559+
1560+ let result = Arc :: new ( if source. is_empty ( ) {
1561+ Object :: String ( String :: new ( ) )
1562+ } else {
1563+ let mut buffer = source. split_inclusive ( |b| * b == b'\0' ) . next ( ) . unwrap ( ) ;
1564+ if length < usize:: MAX {
1565+ buffer = & buffer[ 0 ..usize:: min ( length, buffer. len ( ) ) ] ;
1566+ }
1567+ let string = str:: from_utf8 ( buffer) . map_err ( |_| AmlError :: InvalidOperationOnObject {
1568+ op : Operation :: ToString ,
1569+ typ : ObjectType :: Buffer ,
1570+ } ) ?;
1571+ Object :: String ( string. to_string ( ) )
1572+ } ) ;
1573+
1574+ // TODO: use result of store
1575+ self . do_store ( target, result. clone ( ) ) ?;
1576+ context. contribute_arg ( Argument :: Object ( result) ) ;
1577+ Ok ( ( ) )
1578+ }
1579+
1580+ /// Perform a `ToDecimalString` or `ToHexString` operation
1581+ fn do_to_dec_hex_string ( & self , context : & mut MethodContext , op : OpInFlight ) -> Result < ( ) , AmlError > {
1582+ let [ Argument :: Object ( operand) , target] = & op. arguments [ ..] else { panic ! ( ) } ;
1583+ let operand = operand. clone ( ) . unwrap_transparent_reference ( ) ;
1584+
1585+ let result = Arc :: new ( match * operand {
1586+ Object :: String ( ref value) => Object :: String ( value. clone ( ) ) ,
1587+ Object :: Integer ( value) => match op. op {
1588+ Opcode :: ToDecimalString => Object :: String ( value. to_string ( ) ) ,
1589+ Opcode :: ToHexString => Object :: String ( alloc:: format!( "{:#x}" , value) ) ,
1590+ _ => panic ! ( ) ,
1591+ } ,
1592+ Object :: Buffer ( ref bytes) => {
1593+ if bytes. is_empty ( ) {
1594+ Object :: String ( String :: new ( ) )
1595+ } else {
1596+ // TODO: there has GOT to be a better way to format directly into a string...
1597+ let mut string = String :: new ( ) ;
1598+ for byte in bytes {
1599+ let as_str = match op. op {
1600+ Opcode :: ToDecimalString => alloc:: format!( "{}," , byte) ,
1601+ Opcode :: ToHexString => alloc:: format!( "{:?}," , byte) ,
1602+ _ => panic ! ( ) ,
1603+ } ;
1604+ string. push_str ( & as_str) ;
1605+ }
1606+ // Remove last comma, if present
1607+ if !string. is_empty ( ) {
1608+ string. pop ( ) ;
1609+ }
1610+ Object :: String ( string)
1611+ }
1612+ }
1613+ _ => Err ( AmlError :: InvalidOperationOnObject { op : Operation :: ToDecOrHexString , typ : operand. typ ( ) } ) ?,
1614+ } ) ;
1615+
1616+ // TODO: use result of store
1617+ self . do_store ( target, result. clone ( ) ) ?;
1618+ context. contribute_arg ( Argument :: Object ( result) ) ;
1619+ Ok ( ( ) )
1620+ }
1621+
14881622 fn do_mid ( & self , context : & mut MethodContext , op : OpInFlight ) -> Result < ( ) , AmlError > {
14891623 let [ Argument :: Object ( source) , Argument :: Object ( index) , Argument :: Object ( length) , target] =
14901624 & op. arguments [ ..]
@@ -2572,6 +2706,11 @@ pub enum Operation {
25722706 Release ,
25732707 ConvertToBuffer ,
25742708
2709+ ToBuffer ,
2710+ ToInteger ,
2711+ ToString ,
2712+ ToDecOrHexString ,
2713+
25752714 ReadBufferField ,
25762715 WriteBufferField ,
25772716 LogicalOp ,
0 commit comments