@@ -327,11 +327,12 @@ where
327
327
| Opcode :: LLess => {
328
328
self . do_logical_op ( & mut context, op) ?;
329
329
}
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
+ }
335
336
Opcode :: Mid => self . do_mid ( & mut context, op) ?,
336
337
Opcode :: Concat => self . do_concat ( & mut context, op) ?,
337
338
Opcode :: ConcatRes => {
@@ -1202,11 +1203,10 @@ where
1202
1203
context. start_in_flight_op ( OpInFlight :: new ( opcode, 2 ) ) ;
1203
1204
}
1204
1205
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 ) ) ,
1210
1210
1211
1211
Opcode :: ObjectType => context. start_in_flight_op ( OpInFlight :: new ( opcode, 1 ) ) ,
1212
1212
Opcode :: CopyObject => todo ! ( ) ,
@@ -1485,6 +1485,140 @@ where
1485
1485
Ok ( ( ) )
1486
1486
}
1487
1487
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
+
1488
1622
fn do_mid ( & self , context : & mut MethodContext , op : OpInFlight ) -> Result < ( ) , AmlError > {
1489
1623
let [ Argument :: Object ( source) , Argument :: Object ( index) , Argument :: Object ( length) , target] =
1490
1624
& op. arguments [ ..]
@@ -2572,6 +2706,11 @@ pub enum Operation {
2572
2706
Release ,
2573
2707
ConvertToBuffer ,
2574
2708
2709
+ ToBuffer ,
2710
+ ToInteger ,
2711
+ ToString ,
2712
+ ToDecOrHexString ,
2713
+
2575
2714
ReadBufferField ,
2576
2715
WriteBufferField ,
2577
2716
LogicalOp ,
0 commit comments