What changed, and why it matters
This is a routine firmware release merge (v3.0.4) for the Keystone 3 hardware wallet. The bulk of the changes are UI tweaks, new feature support (Solana CLI, Lace Wallet), and hardening fixes found during an internal 'regular AI review'. The security-relevant hardening includes: rejecting NUL bytes inside Ethereum EIP-712 typed-data messages, validating NUL bytes before converting Rust strings to C strings, adding null/UTF-8 checks when parsing UR payloads, replacing unsafe strcpy/sprintf with bounded versions, and fixing a format-string bug in a debug LCD print function. There is no public disclosure or CVE tied to this commit, and the vendor does not describe it as a security release.
Treat as a normal firmware update with embedded hardening fixes. Users should install v3.0.4 to benefit from the defensive improvements. Security teams may want to review the EIP-712 NUL-byte and C-string conversion changes for completeness, and confirm all call sites of PrintOnLcd now pre-format with snprintf.
Security signals we found
NUL-byte rejection in EIP-712 typed data parsing
C-string conversion hardening against NUL bytes
Null-pointer and UTF-8 validation added to UR parsing entry points
Bounded string copies (snprintf/strcpy_s) replacing unbounded sprintf/strcpy
Removal of variadic vsprintf in LCD debug print path
Key-derivation schema count limit added
Bitcoin fee-warning policy refinement for Dogecoin
Evidence from the diff
The commit merges release v3.0.4. Security-relevant code changes observed in the diff: (1) rust/apps/ethereum/src/lib.rs now rejects EIP-712 typed data containing NUL characters before signing/parsing, preventing display spoofing via embedded nulls. (2) rust/rust_c/src/common/utils.rs introduces validate_c_char/try_convert_c_char and changes convert_c_char to strip NUL bytes, avoiding CString::new panics and potential C-string truncation issues. (3) rust/rust_c/src/common/ur.rs adds null-pointer and valid-UTF-8 checks to parse_ur/receive. (4) rust/rust_c/src/wallet/structs.rs limits key-derivation schemas to 1..24. (5) C code replaces multiple sprintf/strcpy calls with snprintf/strcpy_s and removes a variadic PrintOnLcd that used vsprintf with attacker-influenced text, eliminating format-string and stack-overflow risks. (6) Bitcoin fee-warning logic is refined for Dogecoin. These are defensive fixes; no exploit chain is demonstrated in the commit materials.
Changed components
Ethereum typed-data parser (rust/apps/ethereum)Rust/C FFI string utilities (rust/rust_c/src/common/utils.rs)UR parsing C bindings (rust/rust_c/src/common/ur.rs)Wallet hardware-call parser (rust/rust_c/src/wallet)Bitcoin transaction parser (rust/apps/bitcoin)Cardano C bindings (rust/rust_c/src/cardano)LCD debug print driver (src/hardware_interface/draw_on_lcd.c)C backtrace and RSA utilities (src/cm_backtrace/cm_backtrace.c, src/crypto/rsa.c)Bitcoin GUI chain (src/ui/gui_chain/gui_btc.c)Monero GUI chain (src/ui/gui_chain/multi/cypherpunk/gui_monero.c)Inspect captured patch +4960 / −5488
### CHANGELOG-ZH.md
@@ -1,3 +1,29 @@
+## 3.0.4 (2026-8-10)
+
+**Web3:**
+
+### 新增
+
+1. 支持 Solana CLI
+2. 支持通过 Lace Wallet 管理 BTC 和 ADA 资产
+
+### 优化
+
+1. 交易解析展示优化
+
+**Cypherpunk:**
+
+### 优化
+
+1. 交易解析展示优化
+
+**BTC Only:**
+
+### 优化
+
+1. 交易解析展示优化
+
+
## 3.0.2 (2026-07-24)
**Cypherpunk:**
### CHANGELOG.md
@@ -1,3 +1,28 @@
+## 3.0.4 (2026-08-10)
+
+**Web3:**
+
+### What's new
+
+1. Added support for Solana CLI
+2. Supported managing BTC and ADA assets using Lace Wallet
+
+### Improvements
+
+1. Optimized transaction parsing
+
+**Cypherpunk:**
+
+### Improvements
+
+1. Optimized transaction parsing
+
+**BTC Only:**
+
+### Improvements
+
+1. Optimized transaction parsing
+
## 3.0.2 (2026-07-24)
**Cypherpunk:**
### rust/apps/bitcoin/src/network.rs
@@ -17,6 +17,10 @@ pub struct LargeFeePolicy {
/// Fee-rate threshold in the network's smallest unit per virtual byte.
/// Some networks use a fee policy that is not meaningfully byte based.
pub rate_threshold_per_vbyte: Option<u64>,
+ /// Whether a fee larger than the transferred amount should be highlighted.
+ /// This is not useful for networks such as Dogecoin where small transfers
+ /// can legitimately cost more than the transferred amount.
+ pub warn_fee_larger_than_amount: bool,
}
pub const UNSUPPORTED_LEGACY_UTXO_MESSAGE: &str =
@@ -90,31 +94,38 @@ impl NetworkT for Network {
Network::Bitcoin | Network::BitcoinTestnet | Network::AvaxBtcBridge => LargeFeePolicy {
absolute_threshold: 5_000_000,
rate_threshold_per_vbyte: Some(100),
+ warn_fee_larger_than_amount: true,
},
// Litecoin's normal relay/wallet fee scale is higher in litoshi/vB.
Network::Litecoin => LargeFeePolicy {
absolute_threshold: 10_000_000,
rate_threshold_per_vbyte: Some(1_000),
+ warn_fee_larger_than_amount: true,
},
- // Dogecoin Core recommends 0.01 DOGE/kB. Small transactions can
- // therefore legitimately be several thousand koinu/vB.
+ // Dogecoin Core recommends a minimum of 0.01 DOGE/kB. Wallet and
+ // swap transactions can legitimately pay substantially more, so
+ // warn at 1 DOGE/kB or an absolute fee above 1 DOGE.
Network::Dogecoin => LargeFeePolicy {
absolute_threshold: 100_000_000,
- rate_threshold_per_vbyte: Some(10_000),
+ rate_threshold_per_vbyte: Some(100_000),
+ warn_fee_larger_than_amount: false,
},
Network::Dash => LargeFeePolicy {
absolute_threshold: 10_000_000,
rate_threshold_per_vbyte: Some(100),
+ warn_fee_larger_than_amount: true,
},
Network::BitcoinCash => LargeFeePolicy {
absolute_threshold: 10_000_000,
rate_threshold_per_vbyte: Some(100),
+ warn_fee_larger_than_amount: true,
},
// Zcash conventional fees are action based rather than a simple
// sat/vB-style market, so only use the absolute safety threshold.
Network::Zcash => LargeFeePolicy {
absolute_threshold: 10_000_000,
rate_threshold_per_vbyte: None,
+ warn_fee_larger_than_amount: true,
},
}
}
@@ -182,6 +193,7 @@ impl NetworkT for CustomNewNetwork {
LargeFeePolicy {
absolute_threshold: 5_000_000,
rate_threshold_per_vbyte: Some(100),
+ warn_fee_larger_than_amount: true,
}
}
}
### rust/apps/bitcoin/src/transactions/parsed_tx.rs
@@ -287,7 +287,8 @@ pub trait TxParser {
from: overview_from,
to: overview_to,
network: network.normalize(),
- fee_larger_than_amount: fee > overview_amount,
+ fee_larger_than_amount: large_fee_policy.warn_fee_larger_than_amount
+ && fee > overview_amount,
is_large_fee,
is_multisig: inputs.iter().any(|v| v.is_multisig),
need_sign: Self::is_need_sign(&inputs),
@@ -561,13 +562,25 @@ mod tests {
.unwrap();
assert!(!normal_doge_fee.overview.is_large_fee);
+ let normal_small_doge_transfer = DummyParser
+ .normalize(
+ vec![build_input_with_value(23_482_934, 0x01)],
+ vec![build_output(10_000_000)],
+ &Network::Dogecoin,
+ false,
+ Some(200),
+ )
+ .unwrap();
+ assert!(!normal_small_doge_transfer.overview.is_large_fee);
+ assert!(!normal_small_doge_transfer.overview.fee_larger_than_amount);
+
let high_doge_rate = DummyParser
.normalize(
- vec![build_input_with_value(110_000_001, 0x01)],
+ vec![build_input_with_value(120_000_001, 0x01)],
vec![build_output(100_000_000)],
&Network::Dogecoin,
false,
- Some(1_000),
+ Some(200),
)
.unwrap();
assert!(high_doge_rate.overview.is_large_fee);
### rust/apps/bitcoin/src/transactions/psbt/wrapped_psbt.rs
@@ -256,11 +256,9 @@ impl WrappedPsbt {
fn check_my_wallet_type(&self, input: &Input, context: &ParseContext) -> Result<()> {
if let Some(config) = &context.multisig_wallet_config {
- if context
- .verify_code
- .as_ref()
- .is_some_and(|verify_code| verify_code != &config.verify_code)
- {
+ if context.verify_code.as_ref().is_some_and(|verify_code| {
+ verify_code != &config.verify_code && verify_code != &config.verify_without_mfp
+ }) {
return Err(BitcoinError::WalletTypeError(
"multisig wallet config does not match verify code".to_string(),
));
@@ -1601,7 +1599,7 @@ mod tests {
format: "P2WSH-P2SH".to_string(),
xpub_items,
verify_code: "test".to_string(),
- verify_without_mfp: String::new(),
+ verify_without_mfp: "without-mfp".to_string(),
config_text: String::new(),
network: MultiSigNetwork::TestNet,
};
@@ -1614,6 +1612,8 @@ mod tests {
let wrapper = WrappedPsbt { psbt };
let input = wrapper.psbt.inputs[0].clone();
assert!(wrapper.check_my_wallet_type(&input, &context).is_ok());
+ context.verify_code = Some("without-mfp".to_string());
+ assert!(wrapper.check_my_wallet_type(&input, &context).is_ok());
context.verify_code = Some("wrong".to_string());
assert!(wrapper.check_my_wallet_type(&input, &context).is_err());
context.verify_code = Some("test".to_string());
### rust/apps/ethereum/src/lib.rs
@@ -72,11 +72,64 @@ pub fn parse_personal_message(
pub fn parse_typed_data_message(tx_hex: &[u8], from_key: Option<PublicKey>) -> Result<TypedData> {
let utf8_message = String::from_utf8(tx_hex.to_vec())
.map_err(|e| EthereumError::InvalidUtf8Error(e.to_string()))?;
- let typed_data: Eip712TypedData = serde_json::from_str(&utf8_message)
- .map_err(|e| EthereumError::InvalidTypedData(e.to_string(), utf8_message))?;
+ let typed_data = parse_typed_data_json(utf8_message)?;
TypedData::from_raw(typed_data, from_key)
}
+fn parse_typed_data_json(utf8_message: String) -> Result<Eip712TypedData> {
+ let typed_data: Eip712TypedData = serde_json::from_str(&utf8_message)
+ .map_err(|e| EthereumError::InvalidTypedData(e.to_string(), utf8_message.clone()))?;
+
+ if typed_data_contains_nul(&typed_data) {
+ return Err(EthereumError::InvalidTypedData(
+ "NUL characters are not supported".to_string(),
+ String::new(),
+ ));
+ }
+
+ Ok(typed_data)
+}
+
+fn typed_data_contains_nul(typed_data: &Eip712TypedData) -> bool {
+ typed_data.primary_type.contains('\0')
+ || typed_data
+ .domain
+ .name
+ .as_deref()
+ .is_some_and(|value| value.contains('\0'))
+ || typed_data
+ .domain
+ .version
+ .as_deref()
+ .is_some_and(|value| value.contains('\0'))
+ || typed_data
+ .domain
+ .verifying_contract
+ .as_deref()
+ .is_some_and(|value| value.contains('\0'))
+ || typed_data.types.iter().any(|(name, fields)| {
+ name.contains('\0')
+ || fields
+ .iter()
+ .any(|field| field.name.contains('\0') || field.r#type.contains('\0'))
+ })
+ || typed_data
+ .message
+ .iter()
+ .any(|(key, value)| key.contains('\0') || json_value_contains_nul(value))
+}
+
+fn json_value_contains_nul(value: &serde_json::Value) -> bool {
+ match value {
+ serde_json::Value::String(value) => value.contains('\0'),
+ serde_json::Value::Array(values) => values.iter().any(json_value_contains_nul),
+ serde_json::Value::Object(values) => values
+ .iter()
+ .any(|(key, value)| key.contains('\0') || json_value_contains_nul(value)),
+ _ => false,
+ }
+}
+
pub fn sign_legacy_tx(sign_data: &[u8], seed: &[u8], path: &String) -> Result<EthereumSignature> {
let tx = LegacyTransaction::decode_raw(sign_data)?;
let hash = keccak256(sign_data);
@@ -158,8 +211,7 @@ pub fn sign_typed_data_message(
) -> Result<EthereumSignature> {
let utf8_message = String::from_utf8(sign_data.to_vec())
.map_err(|e| EthereumError::InvalidUtf8Error(e.to_string()))?;
- let typed_data: Eip712TypedData = serde_json::from_str(&utf8_message)
- .map_err(|e| EthereumError::InvalidTypedData(e.to_string(), utf8_message))?;
+ let typed_data = parse_typed_data_json(utf8_message)?;
let hash = typed_data
.encode_eip712()
@@ -296,6 +348,26 @@ mod tests {
assert!(parse_typed_data_message(sign_data, None).is_err());
}
+ #[test]
+ fn test_typed_data_rejects_nul() {
+ let sign_data = br#"{"types":{"EIP712Domain":[],"Message":[{"name":"text","type":"string"}]},"primaryType":"Message","domain":{},"message":{"text":{"nested":["USDT\u0000FAKE"]}}}"#;
+
+ let parse_error = parse_typed_data_message(sign_data, None).unwrap_err();
+ assert!(parse_error
+ .to_string()
+ .contains("NUL characters are not supported"));
+
+ let seed = [0u8; 64];
+ let path = "m/44'/60'/0'/0/0".to_string();
+ let sign_error = match sign_typed_data_message(sign_data, &seed, &path) {
+ Ok(_) => panic!(),
+ Err(error) => error,
+ };
+ assert!(sign_error
+ .to_string()
+ .contains("NUL characters are not supported"));
+ }
+
#[test]
fn test_sign_typed_data() {
### rust/rust_c/src/allocator.rs
@@ -4,28 +4,21 @@ use crate::my_alloc::KTAllocator;
static KT_ALLOCATOR: KTAllocator = KTAllocator;
use core::panic::PanicInfo;
-use cstr_core::CString;
+
+static OOM_MESSAGE: &[u8] = b"rust out of memory\0";
#[alloc_error_handler]
-fn oom(layout: core::alloc::Layout) -> ! {
- unsafe {
- crate::bindings::LogRustPanic(
- CString::new(alloc::format!("Out of memory: {layout:?}"))
- .unwrap()
- .into_raw(),
- )
- };
+fn oom(_layout: core::alloc::Layout) -> ! {
+ unsafe { crate::bindings::LogRustPanic(OOM_MESSAGE.as_ptr() as *mut cty::c_char) };
loop {}
}
#[panic_handler]
fn panic(e: &PanicInfo) -> ! {
- unsafe {
- crate::bindings::LogRustPanic(
- CString::new(alloc::format!("rust panic: {e:?}"))
- .unwrap()
- .into_raw(),
- )
- }
+ let message = match e.location() {
+ Some(location) => alloc::format!("rust panic at {}:{}", location.file(), location.line()),
+ None => alloc::string::String::from("rust panic"),
+ };
+ unsafe { crate::bindings::LogRustPanic(crate::common::utils::convert_c_char(message)) }
loop {}
}
### rust/rust_c/src/cardano/mod.rs
@@ -348,12 +348,26 @@ pub unsafe extern "C" fn cardano_parse_sign_tx_hash(
let sign_hash_request = extract_ptr_with_type!(ptr, CardanoSignTxHashRequest);
let message = sign_hash_request.get_tx_hash();
let crypto_key_paths = sign_hash_request.get_paths();
- let paths = crypto_key_paths
+ let paths = match crypto_key_paths
.iter()
.map(|v| v.get_path())
.collect::<Option<Vec<String>>>()
- .unwrap_or_default();
+ {
+ Some(paths) => paths,
+ None => {
+ return TransactionParseResult::from(RustCError::InvalidData(
+ "invalid derivation path".to_string(),
+ ))
+ .c_ptr()
+ }
+ };
let address_list = sign_hash_request.get_address_list();
+ if paths.len() != address_list.len() {
+ return TransactionParseResult::from(RustCError::InvalidData(
+ "address and derivation path count mismatch".to_string(),
+ ))
+ .c_ptr();
+ }
let network = "Cardano".to_string();
let result = DisplayCardanoSignTxHash::new(network, paths, message, address_list);
TransactionParseResult::success(result.c_ptr()).c_ptr()
@@ -479,9 +493,10 @@ pub unsafe extern "C" fn cardano_parse_catalyst(
) -> PtrT<TransactionParseResult<DisplayCardanoCatalyst>> {
let cardano_catalyst_request =
extract_ptr_with_type!(ptr, CardanoCatalystVotingRegistrationRequest);
- let res = DisplayCardanoCatalyst::from(cardano_catalyst_request.clone()).c_ptr();
-
- TransactionParseResult::success(res).c_ptr()
+ match DisplayCardanoCatalyst::try_from(cardano_catalyst_request.clone()) {
+ Ok(value) => TransactionParseResult::success(value.c_ptr()).c_ptr(),
+ Err(error) => TransactionParseResult::from(error).c_ptr(),
+ }
}
#[no_mangle]
### rust/rust_c/src/cardano/structs.rs
@@ -1,6 +1,7 @@
use alloc::string::ToString;
use alloc::vec::Vec;
use alloc::{boxed::Box, string::String};
+use app_cardano::errors::CardanoError;
use app_cardano::structs::{
CardanoCertificate, CardanoFrom, CardanoTo, CardanoWithdrawal, ParsedCardanoSignCip8Data,
ParsedCardanoSignData, ParsedCardanoTx, VotingProcedure, VotingProposal,
@@ -33,17 +34,17 @@ pub struct DisplayCardanoCatalyst {
pub vote_keys: Ptr<VecFFI<PtrString>>,
}
-impl From<CardanoCatalystVotingRegistrationRequest> for DisplayCardanoCatalyst {
- fn from(value: CardanoCatalystVotingRegistrationRequest) -> Self {
- Self {
+impl TryFrom<CardanoCatalystVotingRegistrationRequest> for DisplayCardanoCatalyst {
+ type Error = CardanoError;
+
+ fn try_from(value: CardanoCatalystVotingRegistrationRequest) -> Result<Self, Self::Error> {
+ let stake_key = app_cardano::governance::parse_stake_address(value.get_stake_pub())?;
+ let rewards = app_cardano::governance::parse_payment_address(value.get_payment_address())?;
+
+ Ok(Self {
nonce: convert_c_char(value.get_nonce().to_string()),
- stake_key: convert_c_char(
- app_cardano::governance::parse_stake_address(value.get_stake_pub()).unwrap(),
- ),
- rewards: convert_c_char(
- app_cardano::governance::parse_payment_address(value.get_payment_address())
- .unwrap(),
- ),
+ stake_key: convert_c_char(stake_key),
+ rewards: convert_c_char(rewards),
vote_keys: VecFFI::from(
value
.get_delegations()
@@ -52,7 +53,7 @@ impl From<CardanoCatalystVotingRegistrationRequest> for DisplayCardanoCatalyst {
.collect_vec(),
)
.c_ptr(),
- }
+ })
}
}
### rust/rust_c/src/common/macros.rs
@@ -74,7 +74,7 @@ macro_rules! impl_new_error {
let result = Self::new();
Self {
error_code: error_code as u32,
- error_message: CString::new(error_message).unwrap().into_raw(),
+ error_message: $crate::common::utils::convert_c_char(error_message),
..result
}
}
@@ -211,7 +211,7 @@ macro_rules! impl_new_error {
let result = Self::new();
Self {
error_code: error_code as u32,
- error_message: CString::new(error_message).unwrap().into_raw(),
+ error_message: $crate::common::utils::convert_c_char(error_message),
..result
}
}
@@ -347,7 +347,7 @@ macro_rules! impl_simple_new_error {
let result = Self::new();
Self {
error_code: error_code as u32,
- error_message: CString::new(error_message).unwrap().into_raw(),
+ error_message: $crate::common::utils::convert_c_char(error_message),
..result
}
}
### rust/rust_c/src/common/ur.rs
@@ -80,7 +80,7 @@ use super::errors::{ErrorCodes, RustCError};
use super::free::Free;
use super::types::{PtrDecoder, PtrEncoder, PtrString, PtrUR};
use super::ur_ext::InferViewType;
-use super::utils::{convert_c_char, recover_c_char};
+use super::utils::{check_recover_c_char_lossy, convert_c_char, recover_c_char};
use crate::{
extract_ptr_with_type, free_ptr_with_type, free_str_ptr, impl_c_ptr, impl_new_error,
impl_response,
@@ -1038,11 +1038,33 @@ pub extern "C" fn get_next_cyclic_part(ptr: PtrEncoder) -> *mut UREncodeMultiRes
#[no_mangle]
pub unsafe extern "C" fn parse_ur(ur: PtrString) -> *mut URParseResult {
- decode_ur(recover_c_char(ur)).c_ptr()
+ if ur.is_null() {
+ return URParseResult::from(RustCError::InvalidData("UR payload is null".to_string()))
+ .c_ptr();
+ }
+ let (is_valid_utf8, ur) = check_recover_c_char_lossy(ur);
+ if !is_valid_utf8 {
+ return URParseResult::from(RustCError::InvalidData(
+ "UR payload is not valid UTF-8".to_string(),
+ ))
+ .c_ptr();
+ }
+ decode_ur(ur).c_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn receive(ur: PtrString, decoder: PtrDecoder) -> *mut URParseMultiResult {
+ if ur.is_null() {
+ return URParseMultiResult::from(RustCError::InvalidData("UR payload is null".to_string()))
+ .c_ptr();
+ }
+ let (is_valid_utf8, ur) = check_recover_c_char_lossy(ur);
+ if !is_valid_utf8 {
+ return URParseMultiResult::from(RustCError::InvalidData(
+ "UR payload is not valid UTF-8".to_string(),
+ ))
+ .c_ptr();
+ }
let decoder = extract_ptr_with_type!(decoder, KeystoneURDecoder);
- receive_ur(recover_c_char(ur), decoder).c_ptr()
+ receive_ur(ur, decoder).c_ptr()
}
### rust/rust_c/src/common/utils.rs
@@ -7,10 +7,28 @@ use crate::{extract_array, extract_ptr_with_type};
use cstr_core::{CStr, CString};
use cty::c_char;
+use crate::common::errors::{RustCError, R};
use crate::common::types::{PtrString, PtrT};
+pub fn validate_c_char(s: &str) -> R<()> {
+ CString::new(s)
+ .map(|_| ())
+ .map_err(|_| RustCError::InvalidData("NUL characters are not supported".to_string()))
+}
+
+pub fn try_convert_c_char(s: String) -> R<PtrString> {
+ CString::new(s)
+ .map(CString::into_raw)
+ .map_err(|_| RustCError::InvalidData("NUL characters are not supported".to_string()))
+}
+
pub fn convert_c_char(s: String) -> PtrString {
- CString::new(s).unwrap().into_raw()
+ let mut bytes = s.into_bytes();
+ bytes.retain(|byte| *byte != 0);
+ match CString::new(bytes) {
+ Ok(value) => value.into_raw(),
+ Err(_) => core::ptr::null_mut(),
+ }
}
pub unsafe fn recover_c_char(s: *mut c_char) -> String {
### rust/rust_c/src/ethereum/mod.rs
@@ -413,9 +413,10 @@ pub unsafe extern "C" fn eth_parse_typed_data(
TransactionType::TypedData => {
let tx = parse_typed_data_message(&crypto_eth.get_sign_data(), pubkey);
match tx {
- Ok(t) => {
- TransactionParseResult::success(DisplayETHTypedData::from(t).c_ptr()).c_ptr()
- }
+ Ok(t) => match DisplayETHTypedData::try_from(t) {
+ Ok(display) => TransactionParseResult::success(display.c_ptr()).c_ptr(),
+ Err(error) => TransactionParseResult::from(error).c_ptr(),
+ },
Err(e) => TransactionParseResult::from(e).c_ptr(),
}
}
### rust/rust_c/src/ethereum/structs.rs
@@ -2,11 +2,12 @@
use alloc::boxed::Box;
use super::util::{calculate_max_txn_fee, convert_wei_to_eth};
+use crate::common::errors::RustCError;
use crate::common::ffi::VecFFI;
use crate::common::free::Free;
use crate::common::structs::{Response, TransactionParseResult};
use crate::common::types::{Ptr, PtrString, PtrT};
-use crate::common::utils::convert_c_char;
+use crate::common::utils::{convert_c_char, try_convert_c_char, validate_c_char};
use crate::{free_str_ptr, free_vec, impl_c_ptr, make_free_method};
use alloc::string::{String, ToString};
use alloc::vec::Vec;
@@ -309,29 +310,48 @@ pub struct DisplayETHTypedData {
safe_tx_hash: PtrString,
}
-impl From<TypedData> for DisplayETHTypedData {
- fn from(message: TypedData) -> Self {
- fn to_ptr_string(string: String) -> PtrString {
+impl TryFrom<TypedData> for DisplayETHTypedData {
+ type Error = RustCError;
+
+ fn try_from(message: TypedData) -> Result<Self, Self::Error> {
+ fn to_ptr_string(string: String) -> Result<PtrString, RustCError> {
if string.is_empty() {
- null_mut()
+ Ok(null_mut())
} else {
- convert_c_char(string)
+ try_convert_c_char(string)
}
}
- Self {
- name: to_ptr_string(message.name),
- version: to_ptr_string(message.version),
- chain_id: to_ptr_string(message.chain_id),
- verifying_contract: to_ptr_string(message.verifying_contract),
- salt: to_ptr_string(message.salt),
- primary_type: to_ptr_string(message.primary_type),
- message: to_ptr_string(message.message),
- from: message.from.map(to_ptr_string).unwrap_or(null_mut()),
- domain_hash: to_ptr_string(message.domain_separator),
- message_hash: to_ptr_string(message.message_hash),
- safe_tx_hash: to_ptr_string(message.safe_tx_hash),
+ validate_c_char(&message.name)?;
+ validate_c_char(&message.version)?;
+ validate_c_char(&message.chain_id)?;
+ validate_c_char(&message.verifying_contract)?;
+ validate_c_char(&message.salt)?;
+ validate_c_char(&message.primary_type)?;
+ validate_c_char(&message.message)?;
+ if let Some(from) = message.from.as_deref() {
+ validate_c_char(from)?;
}
+ validate_c_char(&message.domain_separator)?;
+ validate_c_char(&message.message_hash)?;
+ validate_c_char(&message.safe_tx_hash)?;
+
+ Ok(Self {
+ name: to_ptr_string(message.name)?,
+ version: to_ptr_string(message.version)?,
+ chain_id: to_ptr_string(message.chain_id)?,
+ verifying_contract: to_ptr_string(message.verifying_contract)?,
+ salt: to_ptr_string(message.salt)?,
+ primary_type: to_ptr_string(message.primary_type)?,
+ message: to_ptr_string(message.message)?,
+ from: match message.from {
+ Some(from) => to_ptr_string(from)?,
+ None => null_mut(),
+ },
+ domain_hash: to_ptr_string(message.domain_separator)?,
+ message_hash: to_ptr_string(message.message_hash)?,
+ safe_tx_hash: to_ptr_string(message.safe_tx_hash)?,
+ })
}
}
### rust/rust_c/src/wallet/mod.rs
@@ -51,72 +51,58 @@ pub unsafe extern "C" fn parse_qr_hardware_call(ur: PtrUR) -> Ptr<Response<QRHar
}
#[no_mangle]
-pub unsafe extern "C" fn check_hardware_call_path(
- path: PtrString,
- chain_type: PtrString,
-) -> *mut Response<bool> {
- let chain_type_str = recover_c_char(chain_type);
- let prefix = match chain_type_str.as_str() {
- "BTC_LEGACY" => "m/44'/0'",
- "BTC_NATIVE_SEGWIT" => "m/84'",
- "BTC_TAPROOT" => "m/86'",
- "BTC" => "m/49'",
- "ETH" => "m/44'/60'",
- "SOL" => "m/44'/501'",
- "XRP" => "m/44'/144'",
- "ADA" => "m/1852'/1815'",
- "ADA_CIP_1853" => "m/1853'/1815'",
- "ADA_CIP_1854" => "m/1854'/1815'",
- "TRX" => "m/44'/195'",
- "LTC" => "m/49'/2'",
- "BCH" => "m/44'/145'",
- "APT" => "m/44'/637'",
- "SUI" => "m/44'/784'",
- "DASH" => "m/44'/5'",
- "AR" => "m/44'/472'",
- "XLM" => "m/44'/148'",
- "TIA" => "m/44'/118'",
- "ATOM" => "m/44'/118'",
- "DYM" => "m/44'/118'",
- "OSMO" => "m/44'/118'",
- "INJ" => "m/44'/60'",
- "CRO" => "m/44'/394'",
- "KAVA" => "m/44'/459'",
- "LUNC" => "m/44'/330'",
- "AXL" => "m/44'/118'",
- "LUNA" => "m/44'/330'",
- "AKT" => "m/44'/118'",
- "STRD" => "m/44'/118'",
- "SCRT" => "m/44'/529'",
- "BLD" => "m/44'/564'",
- "CTK" => "m/44'/118'",
- "EVMOS" => "m/44'/60'",
- "STARS" => "m/44'/118'",
- "XPRT" => "m/44'/118'",
- "SOMM" => "m/44'/118'",
- "JUNO" => "m/44'/118'",
- "IRIS" => "m/44'/118'",
- "DVPN" => "m/44'/118'",
- "ROWAN" => "m/44'/118'",
- "REGEN" => "m/44'/118'",
- "BOOT" => "m/44'/118'",
- "GRAV" => "m/44'/118'",
- "IXO" => "m/44'/118'",
- "NGM" => "m/44'/118'",
- "IOV" => "m/44'/234'",
- "UMEE" => "m/44'/118'",
- "QCK" => "m/44'/118'",
- "TGD" => "m/44'/118'",
- "THOR" => "m/44'/931'",
- "IOTA" => "m/44'/4218'",
- _ => return Response::success(false).c_ptr(),
- };
+pub unsafe extern "C" fn check_hardware_call_path(path: PtrString) -> *mut Response<bool> {
let mut path = recover_c_char(path).to_lowercase();
if !path.starts_with('m') {
path = format!("m/{path}");
}
- let result = path.starts_with(prefix);
- Response::success(result).c_ptr()
+ if DerivationPath::from_str(path.as_str()).is_err() {
+ return Response::success(false).c_ptr();
+ }
+
+ Response::success(is_supported_hardware_call_path(path.as_str())).c_ptr()
+}
+
+fn is_supported_hardware_call_path(path: &str) -> bool {
+ const SUPPORTED_PATH_PREFIXES: &[&str] = &[
+ "m/44'/0'",
+ "m/84'",
+ "m/86'",
+ "m/49'",
+ "m/44'/60'",
+ "m/44'/501'",
+ "m/44'/144'",
+ "m/1852'/1815'",
+ "m/1853'/1815'",
+ "m/1854'/1815'",
+ "m/44'/195'",
+ "m/44'/145'",
+ "m/44'/637'",
+ "m/44'/784'",
+ "m/44'/5'",
+ "m/44'/472'",
+ "m/44'/148'",
+ "m/44'/118'",
+ "m/44'/394'",
+ "m/44'/459'",
+ "m/44'/330'",
+ "m/44'/529'",
+ "m/44'/564'",
+ "m/44'/234'",
+ "m/44'/931'",
+ "m/44'/4218'",
+ ];
+
+ SUPPORTED_PATH_PREFIXES
+ .iter()
+ .any(|prefix| path_matches_prefix(path, prefix))
+}
+
+fn path_matches_prefix(path: &str, prefix: &str) -> bool {
+ path == prefix
+ || path
+ .strip_prefix(prefix)
+ .map_or(false, |suffix| suffix.starts_with('/'))
}
#[no_mangle]
### rust/rust_c/src/wallet/structs.rs
@@ -14,6 +14,8 @@ use crate::common::types::{Ptr, PtrString, PtrT};
use crate::common::utils::{convert_c_char, recover_c_char};
use crate::{check_and_free_ptr, free_str_ptr, impl_c_ptr, make_free_method};
+const MAX_KEY_DERIVATION_SCHEMAS: usize = 24;
+
#[repr(C)]
pub struct QRHardwareCallData {
pub call_type: PtrString,
@@ -43,8 +45,14 @@ impl TryFrom<&mut QRHardwareCall> for QRHardwareCallData {
fn try_from(value: &mut QRHardwareCall) -> Result<Self, Self::Error> {
match value.get_params() {
CallParams::KeyDerivation(data) => {
- let schemas = data
- .get_schemas()
+ let source_schemas = data.get_schemas();
+ if source_schemas.is_empty() || source_schemas.len() > MAX_KEY_DERIVATION_SCHEMAS {
+ return Err(RustCError::InvalidData(
+ "invalid key derivation schema count".to_string(),
+ ));
+ }
+
+ let schemas = source_schemas
.iter()
.map(KeyDerivationSchema::try_from)
.collect::<Result<Vec<KeyDerivationSchema>, RustCError>>()?;
### src/cm_backtrace/cm_backtrace.c
@@ -385,14 +385,14 @@ static void print_call_stack(uint32_t sp)
cur_depth = cm_backtrace_call_stack(call_stack_buf, CMB_CALL_STACK_MAX_DEPTH, sp);
for (i = 0; i < cur_depth; i++) {
- sprintf(call_stack_info + i * (8 + 1), "%08lx", (unsigned long)call_stack_buf[i]);
+ snprintf(call_stack_info + i * (8 + 1), 9, "%08lx", (unsigned long)call_stack_buf[i]);
call_stack_info[i * (8 + 1) + 8] = ' ';
}
if (cur_depth) {
call_stack_info[cur_depth * (8 + 1) - 1] = '\0';
cmb_println(print_info[PRINT_CALL_STACK_INFO], fw_name, CMB_ELF_FILE_EXTENSION_NAME, call_stack_info);
- sprintf(callStackStr, print_info[PRINT_CALL_STACK_INFO], fw_name, CMB_ELF_FILE_EXTENSION_NAME, call_stack_info);
+ snprintf(callStackStr, sizeof(callStackStr), print_info[PRINT_CALL_STACK_INFO], fw_name, CMB_ELF_FILE_EXTENSION_NAME, call_stack_info);
} else {
cmb_println(print_info[PRINT_CALL_STACK_ERR]);
strcpy(callStackStr, print_info[PRINT_CALL_STACK_ERR]);
### src/config/legacy_web_update_pad.c
@@ -15,7 +15,7 @@
#ifdef CYPHERPUNK_VERSION
#ifndef LEGACY_USB_PAD_LEN
-#define LEGACY_USB_PAD_LEN 2U
+#define LEGACY_USB_PAD_LEN 1U
#endif
#endif
### src/config/version.h
@@ -7,7 +7,7 @@
#define SOFTWARE_VERSION_MAJOR 13
#define SOFTWARE_VERSION_MAJOR_OFFSET 10
#define SOFTWARE_VERSION_MINOR 0
-#define SOFTWARE_VERSION_BUILD 2
+#define SOFTWARE_VERSION_BUILD 4
#define SOFTWARE_VERSION_BETA 0
#define SOFTWARE_VERSION (SOFTWARE_VERSION_MAJOR * 10000 + SOFTWARE_VERSION_MINOR * 100 + SOFTWARE_VERSION_BUILD)
#ifdef WEB3_VERSION
### src/crypto/account_public_info.c
@@ -87,7 +87,7 @@ static void LoadCurrentAccountMultiReceiveIndex(void)
if (GetCurrenMultisigWalletByIndex(i) == NULL) {
continue;
}
- strcpy(g_multiSigReceiveIndex[i].verifyCode, GetCurrenMultisigWalletByIndex(i)->verifyCode);
+ strcpy_s(g_multiSigReceiveIndex[i].verifyCode, BUFFER_SIZE_16, GetCurrenMultisigWalletByIndex(i)->verifyCode);
}
}
@@ -242,7 +242,7 @@ void SetAccountMultiReceiveIndex(uint32_t index, char *verifyCode)
for (int i = 0; i < MAX_MULTI_SIG_WALLET_NUMBER; i++) {
if (strlen(g_multiSigReceiveIndex[i].verifyCode) == 0) {
g_multiSigReceiveIndex[i].index = index;
- strcpy(g_multiSigReceiveIndex[i].verifyCode, verifyCode);
+ strcpy_s(g_multiSigReceiveIndex[i].verifyCode, BUFFER_SIZE_16, verifyCode);
break;
} else if (strcmp(g_multiSigReceiveIndex[i].verifyCode, verifyCode) == 0) {
g_multiSigReceiveIndex[i].index = index;
### src/crypto/rsa.c
@@ -29,7 +29,7 @@ static void RsaHashWithSalt(const uint8_t *data, uint8_t *hash)
char hexString[2 * sizeof(mfp) + 1];
char *hexPtr = hexString;
for (size_t i = 0; i < sizeof(mfp); ++i) {
- sprintf(hexPtr, "%02X", mfp[i]);
+ snprintf(hexPtr, 3, "%02X", mfp[i]);
hexPtr += 2;
}
*hexPtr = '\0';
### src/hardware_interface/draw_on_lcd.c
@@ -9,13 +9,11 @@
#include "math.h"
#include "stdlib.h"
#include "ui_display_task.h"
-#include "stdarg.h"
#include "cmsis_os.h"
#include "user_memory.h"
#include "drv_lcd_bright.h"
#define TEXT_LINE_GAP 3
-#define DRAW_MAX_STRING_LEN 256
#define PAGE_MARGINS 15
typedef struct {
@@ -30,16 +28,16 @@ static void GetTrueColors(uint16_t *trueColors, const uint8_t *colorData, uint32
static LcdDrawColor_t g_bgColor = {0};
-void PrintOnLcd(const lv_font_t *font, uint16_t color, const char *format, ...)
+void PrintOnLcd(const lv_font_t *font, uint16_t color, const char *text)
{
static bool backInit = false;
static uint16_t yCursor = PAGE_MARGINS;
uint8_t *gram = GetLvglGramAddr();
- char str[DRAW_MAX_STRING_LEN];
LcdDrawColor_t *pColor;
- va_list argList;
- va_start(argList, format);
+ if (text == NULL) {
+ return;
+ }
if (backInit == false) {
backInit = true;
osKernelLock();
@@ -54,10 +52,7 @@ void PrintOnLcd(const lv_font_t *font, uint16_t color, const char *format, ...)
LcdDraw(0, 400, LCD_DISPLAY_WIDTH, 800 - 1, (uint16_t *)gram);
while (LcdBusy());
}
- vsprintf(str, format, argList);
- printf(str);
- yCursor = DrawStringOnLcd(PAGE_MARGINS, yCursor, str, color, font);
- va_end(argList);
+ yCursor = DrawStringOnLcd(PAGE_MARGINS, yCursor, text, color, font);
}
/// @brief Draw string on lcd.
### src/hardware_interface/draw_on_lcd.h
@@ -7,7 +7,10 @@
#include "lv_font.h"
#include "lv_img_buf.h"
-void PrintOnLcd(const lv_font_t *font, uint16_t color, const char *format, ...);
+// Draws a plain, already-formatted string. Deliberately NOT variadic: callers must
+// snprintf into their own buffer first, so no caller-supplied text is ever parsed
+// as a printf format string.
+void PrintOnLcd(const lv_font_t *font, uint16_t color, const char *text);
int16_t DrawStringOnLcd(uint16_t x, uint16_t y, const char *string, uint16_t color, const lv_font_t *font);
void DrawProgressBarOnLcd(uint16_t x, uint16_t y, uint16_t length, uint16_t width, uint8_t progress, uint16_t color);
void DrawImageOnLcd(uint16_t x, uint16_t y, const lv_img_dsc_t *imgDsc);
### src/ui/gui_assets/font/cn/cnIllustrate.c
[binary or diff unavailable]
### src/ui/gui_assets/font/cn/cnText.c
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 24 px
* Bpp: 2
- * Opts: --bpp 2 --size 24 --no-compress --font NotoSansSC-Regular.ttf --symbols "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~£¥·€、一三上不与个中为主么了二于互交产享亮什从代以件传体何作使例保信候允入全公共关准出分列创初删前办功加动助励包化升单卡即压及取受变可号各同名后吗启和固在地址坊型基处备复多天太失奖好如始委子字安完定密导小屏展差已币帐幕广序度建开异式强当径待志忘快念态总恢息悉您情成我或户扩扫拒择持指振换捷接描播擦收改教数文新方日时明易是显暂更未本机条析查标校格检概模款正毕气永池派测消添熵片版状理生用电白的盘相知短码确示禁私种秒称移程稍立端签简算管类系级纹络绝统继续维网置署脚自芯要解言计认记许设访证词试详语误请败账资路跳软载输过这进连退选通道重金钟钥钱链锁错键闭问除随隙页额验骰,:? --format lvgl -o ../gui_assets/font/cn/cnText.c
+ * Opts: --bpp 2 --size 24 --no-compress --font NotoSansSC-Regular.ttf --symbols !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~£¥·€、一三上不与个中为主么了二于互交产享亮什从代以件传体何作使例保信候允入全公共关准出分列创初删前办功加动助励包化升单卡即压及取受变可号各同名后吗启和固在地址坊型基处备复多天太失奖好如始委子字安完定密导小屏展差已币帐幕广序度建开异式强当径待志忘快念态总恢息悉您情成我或户扩扫拒择持指振换捷接描播擦收改教数文新方日时明易是显暂更未本机条析查标校格检概模款正毕气永池派测消添熵片版状理生用电白的盘盲相知短码确示禁私种秒称移程稍立端签简算管类系级纹络绝统继续维网置署脚自芯要解言计认记许设访证词试详语误请败账资路跳软载输过这进连退选通道重金钟钥钱链锁错键闭问除随隙页额验骰,:? --format lvgl -o ../gui_assets/font/cn/cnText.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -29,10 +29,6 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x3c, 0x38, 0x38, 0x38, 0x38, 0x0, 0x14, 0xbd,
0xbd, 0x7c,
- /* U+0022 "\"" */
- 0xf4, 0x3c, 0xf4, 0x3c, 0xf4, 0x3c, 0xb4, 0x3c,
- 0xb4, 0x3c, 0xb0, 0x3c, 0x70, 0x2c, 0x0, 0x0,
-
/* U+0023 "#" */
0x0, 0xb0, 0x2c, 0x0, 0x2c, 0xb, 0x0, 0xe,
0x3, 0x80, 0x3, 0x80, 0xe0, 0x0, 0xd0, 0x34,
@@ -4467,6 +4463,25 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0xe0, 0x78, 0x1e, 0xf, 0xff, 0xff, 0xff, 0xff,
0xff, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50,
+ /* U+76F2 "盲" */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0xd0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0,
+ 0x6, 0xaa, 0xaa, 0xfe, 0xaa, 0xa9, 0x7f, 0xff,
+ 0xff, 0xff, 0xff, 0xd0, 0x2c, 0x0, 0x0, 0x0,
+ 0x0, 0x2, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x2e,
+ 0xaa, 0xaa, 0xaa, 0x90, 0x2, 0xff, 0xff, 0xff,
+ 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff,
+ 0xff, 0xc0, 0x1, 0xd0, 0x0, 0x0, 0x3c, 0x0,
+ 0x1c, 0x0, 0x0, 0x3, 0xc0, 0x1, 0xff, 0xff,
+ 0xff, 0xfc, 0x0, 0x1d, 0x55, 0x55, 0x57, 0xc0,
+ 0x1, 0xc0, 0x0, 0x0, 0x3c, 0x0, 0x1f, 0xff,
+ 0xff, 0xff, 0xc0, 0x1, 0xe5, 0x55, 0x55, 0x7c,
+ 0x0, 0x1c, 0x0, 0x0, 0x3, 0xc0, 0x1, 0xe5,
+ 0x55, 0x55, 0x7c, 0x0, 0x1f, 0xff, 0xff, 0xff,
+ 0xc0, 0x1, 0xc0, 0x0, 0x0, 0x3c, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
/* U+76F8 "相" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0,
0x0, 0x0, 0x0, 0x0, 0x3, 0xc0, 0x2f, 0xff,
@@ -6131,393 +6146,393 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 86, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 124, .box_w = 4, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 18, .adv_w = 182, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 12},
- {.bitmap_index = 34, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 93, .adv_w = 213, .box_w = 11, .box_h = 25, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 162, .adv_w = 354, .box_w = 22, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 261, .adv_w = 261, .box_w = 16, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 333, .adv_w = 107, .box_w = 3, .box_h = 8, .ofs_x = 2, .ofs_y = 12},
- {.bitmap_index = 339, .adv_w = 130, .box_w = 6, .box_h = 26, .ofs_x = 2, .ofs_y = -5},
- {.bitmap_index = 378, .adv_w = 130, .box_w = 5, .box_h = 26, .ofs_x = 1, .ofs_y = -5},
- {.bitmap_index = 411, .adv_w = 179, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = 11},
- {.bitmap_index = 432, .adv_w = 213, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = 3},
- {.bitmap_index = 475, .adv_w = 107, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -5},
- {.bitmap_index = 487, .adv_w = 133, .box_w = 7, .box_h = 2, .ofs_x = 1, .ofs_y = 6},
- {.bitmap_index = 491, .adv_w = 107, .box_w = 4, .box_h = 4, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 495, .adv_w = 151, .box_w = 10, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
- {.bitmap_index = 558, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 612, .adv_w = 213, .box_w = 10, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 657, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 716, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 770, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 829, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 888, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 942, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 996, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 1050, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 1104, .adv_w = 107, .box_w = 4, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 1118, .adv_w = 107, .box_w = 5, .box_h = 19, .ofs_x = 1, .ofs_y = -5},
- {.bitmap_index = 1142, .adv_w = 213, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 3},
- {.bitmap_index = 1181, .adv_w = 213, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 5},
- {.bitmap_index = 1207, .adv_w = 213, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 3},
- {.bitmap_index = 1246, .adv_w = 182, .box_w = 10, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 1291, .adv_w = 363, .box_w = 21, .box_h = 23, .ofs_x = 1, .ofs_y = -5},
- {.bitmap_index = 1412, .adv_w = 233, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 1480, .adv_w = 252, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 1539, .adv_w = 245, .box_w = 14, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 1602, .adv_w = 264, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 1665, .adv_w = 226, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 1715, .adv_w = 212, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 1765, .adv_w = 265, .box_w = 14, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 1828, .adv_w = 280, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 1891, .adv_w = 113, .box_w = 3, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 1905, .adv_w = 205, .box_w = 11, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 1955, .adv_w = 248, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2018, .adv_w = 209, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2068, .adv_w = 312, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2140, .adv_w = 278, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2199, .adv_w = 285, .box_w = 16, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 2271, .adv_w = 243, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2330, .adv_w = 285, .box_w = 16, .box_h = 22, .ofs_x = 1, .ofs_y = -4},
- {.bitmap_index = 2418, .adv_w = 244, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2477, .adv_w = 229, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 2536, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 2599, .adv_w = 277, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 2658, .adv_w = 221, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 2721, .adv_w = 337, .box_w = 21, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 2816, .adv_w = 220, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 2879, .adv_w = 204, .box_w = 14, .box_h = 18, .ofs_x = -1, .ofs_y = 0},
- {.bitmap_index = 2942, .adv_w = 232, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3001, .adv_w = 130, .box_w = 6, .box_h = 25, .ofs_x = 2, .ofs_y = -5},
- {.bitmap_index = 3039, .adv_w = 151, .box_w = 10, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
- {.bitmap_index = 3102, .adv_w = 130, .box_w = 6, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
- {.bitmap_index = 3140, .adv_w = 213, .box_w = 11, .box_h = 11, .ofs_x = 1, .ofs_y = 8},
- {.bitmap_index = 3171, .adv_w = 215, .box_w = 14, .box_h = 2, .ofs_x = 0, .ofs_y = -4},
- {.bitmap_index = 3178, .adv_w = 233, .box_w = 6, .box_h = 6, .ofs_x = 3, .ofs_y = 16},
- {.bitmap_index = 3187, .adv_w = 216, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3226, .adv_w = 237, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 3286, .adv_w = 196, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3325, .adv_w = 238, .box_w = 12, .box_h = 20, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3385, .adv_w = 213, .box_w = 12, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3427, .adv_w = 125, .box_w = 9, .box_h = 20, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 3472, .adv_w = 217, .box_w = 13, .box_h = 20, .ofs_x = 1, .ofs_y = -6},
- {.bitmap_index = 3537, .adv_w = 233, .box_w = 11, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 3592, .adv_w = 106, .box_w = 4, .box_h = 20, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3612, .adv_w = 106, .box_w = 7, .box_h = 26, .ofs_x = -2, .ofs_y = -6},
- {.bitmap_index = 3658, .adv_w = 212, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 3718, .adv_w = 109, .box_w = 4, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 3738, .adv_w = 356, .box_w = 19, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 3805, .adv_w = 234, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 3844, .adv_w = 233, .box_w = 13, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 3890, .adv_w = 238, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = -6},
- {.bitmap_index = 3950, .adv_w = 238, .box_w = 12, .box_h = 20, .ofs_x = 1, .ofs_y = -6},
- {.bitmap_index = 4010, .adv_w = 149, .box_w = 8, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 4038, .adv_w = 180, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4077, .adv_w = 145, .box_w = 9, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4118, .adv_w = 233, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
- {.bitmap_index = 4157, .adv_w = 200, .box_w = 13, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4203, .adv_w = 308, .box_w = 19, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4270, .adv_w = 191, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4312, .adv_w = 200, .box_w = 13, .box_h = 20, .ofs_x = 0, .ofs_y = -6},
- {.bitmap_index = 4377, .adv_w = 182, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4416, .adv_w = 130, .box_w = 8, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
- {.bitmap_index = 4466, .adv_w = 104, .box_w = 3, .box_h = 28, .ofs_x = 2, .ofs_y = -7},
- {.bitmap_index = 4487, .adv_w = 130, .box_w = 8, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
- {.bitmap_index = 4537, .adv_w = 213, .box_w = 13, .box_h = 4, .ofs_x = 0, .ofs_y = 7},
- {.bitmap_index = 4550, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 4604, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4663, .adv_w = 384, .box_w = 6, .box_h = 6, .ofs_x = 9, .ofs_y = 7},
- {.bitmap_index = 4672, .adv_w = 213, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
- {.bitmap_index = 4735, .adv_w = 384, .box_w = 8, .box_h = 8, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 4751, .adv_w = 384, .box_w = 23, .box_h = 3, .ofs_x = 1, .ofs_y = 8},
- {.bitmap_index = 4769, .adv_w = 384, .box_w = 22, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 4874, .adv_w = 384, .box_w = 22, .box_h = 21, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 4990, .adv_w = 384, .box_w = 23, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 5111, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 5232, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 5370, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 5485, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 5606, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 5727, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 5848, .adv_w = 384, .box_w = 20, .box_h = 22, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 5958, .adv_w = 384, .box_w = 22, .box_h = 17, .ofs_x = 1, .ofs_y = 0},
- {.bitmap_index = 6052, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 6173, .adv_w = 384, .box_w = 22, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 6289, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 6422, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 6549, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 6681, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 6813, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 6951, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 7078, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 7216, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 7343, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 7470, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 7608, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 7740, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 7878, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 8010, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 8148, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 8286, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 8424, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 8557, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 8701, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 8839, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 8971, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 9109, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 9236, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 9363, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 9490, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 9611, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 9726, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 9859, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 9986, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 10113, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 10245, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 10378, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 10510, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 10648, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 10775, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 10902, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 11029, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 11167, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 11300, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 11438, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 11565, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 11703, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 11824, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 11951, .adv_w = 384, .box_w = 21, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 12062, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 12194, .adv_w = 384, .box_w = 24, .box_h = 21, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 12320, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 12453, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 12586, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 12724, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 12845, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 12972, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 13116, .adv_w = 384, .box_w = 20, .box_h = 21, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 13221, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 13336, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 13469, .adv_w = 384, .box_w = 21, .box_h = 22, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 13585, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 13717, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 13838, .adv_w = 384, .box_w = 20, .box_h = 22, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 13948, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 14075, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 14213, .adv_w = 384, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 14334, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 14478, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 14599, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 14737, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 14875, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 15019, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 15157, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 15284, .adv_w = 384, .box_w = 23, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 15405, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 15538, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 15676, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 15809, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 15947, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 16074, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 16212, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 16350, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 16471, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 16603, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 16730, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 16862, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 17006, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 17144, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 17271, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 17409, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 17542, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 17675, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 17802, .adv_w = 384, .box_w = 21, .box_h = 21, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 17913, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 18034, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 18172, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 18310, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 18443, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 18587, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 18720, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 18864, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 18985, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 19112, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 19239, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 19366, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 19481, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 19614, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 19758, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 19885, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 20018, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 20162, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 20295, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 20428, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 20555, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 20693, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 20826, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 20964, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 21097, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 21230, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 21374, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 21507, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 21628, .adv_w = 384, .box_w = 21, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 21754, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 21887, .adv_w = 384, .box_w = 21, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 22013, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 22146, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 22290, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 22434, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 22567, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 22711, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 22855, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 22999, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 23137, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 23275, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 23419, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 23546, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 23679, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 23812, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 23956, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 24094, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 24232, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 24365, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 24497, .adv_w = 384, .box_w = 16, .box_h = 22, .ofs_x = 4, .ofs_y = -3},
- {.bitmap_index = 24585, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 24712, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 24833, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 24960, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 25098, .adv_w = 384, .box_w = 24, .box_h = 20, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 25218, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 25350, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 25477, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 25609, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 25747, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 25891, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 26035, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 26173, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 26311, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 26449, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 26587, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 26731, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 26869, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 27013, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 27157, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 27301, .adv_w = 384, .box_w = 22, .box_h = 20, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 27411, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 27532, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 27670, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 27803, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 27936, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 28074, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 28207, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 28340, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 28478, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 28611, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 28743, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 28881, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 29019, .adv_w = 384, .box_w = 24, .box_h = 21, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 29145, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 29266, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 29387, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 3, .ofs_y = -2},
- {.bitmap_index = 29508, .adv_w = 384, .box_w = 18, .box_h = 24, .ofs_x = 3, .ofs_y = -3},
- {.bitmap_index = 29616, .adv_w = 384, .box_w = 21, .box_h = 24, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 29742, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 29869, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 30007, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 30134, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 30272, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 30399, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 30531, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 30658, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 30796, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 30934, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 31067, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 31200, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 31333, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 31471, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 31598, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 31725, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
- {.bitmap_index = 31846, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 31984, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 32117, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 32255, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 32393, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 32531, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 32664, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 32791, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 32924, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 33057, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 33201, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 33334, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 33472, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 33599, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 33732, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 33864, .adv_w = 384, .box_w = 20, .box_h = 21, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 33969, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 34090, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 34217, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 34350, .adv_w = 384, .box_w = 18, .box_h = 24, .ofs_x = 3, .ofs_y = -3},
- {.bitmap_index = 34458, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 34591, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 34718, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 34856, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 34988, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 35115, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 35248, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 35375, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 35508, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 35635, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 35767, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 35894, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 36021, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 36159, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 36292, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 36425, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 36563, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 36696, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 36828, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 36966, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 37087, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 37231, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 37369, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 37513, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 37651, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 37795, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 37922, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 38066, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 38193, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 38337, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 38464, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 38602, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 38740, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 38878, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 38999, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -1},
- {.bitmap_index = 39131, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 39264, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 39396, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 39534, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 39678, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
- {.bitmap_index = 39816, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 39960, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 40104, .adv_w = 384, .box_w = 20, .box_h = 22, .ofs_x = 2, .ofs_y = -2},
- {.bitmap_index = 40214, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
- {.bitmap_index = 40329, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 40467, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 40605, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 40743, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
- {.bitmap_index = 40864, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 41008, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
- {.bitmap_index = 41152, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
- {.bitmap_index = 41279, .adv_w = 384, .box_w = 5, .box_h = 9, .ofs_x = 3, .ofs_y = -3},
- {.bitmap_index = 41291, .adv_w = 384, .box_w = 4, .box_h = 17, .ofs_x = 4, .ofs_y = -1},
- {.bitmap_index = 41308, .adv_w = 384, .box_w = 12, .box_h = 20, .ofs_x = 0, .ofs_y = -1}
+ {.bitmap_index = 18, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 77, .adv_w = 213, .box_w = 11, .box_h = 25, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 146, .adv_w = 354, .box_w = 22, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 245, .adv_w = 261, .box_w = 16, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 317, .adv_w = 107, .box_w = 3, .box_h = 8, .ofs_x = 2, .ofs_y = 12},
+ {.bitmap_index = 323, .adv_w = 130, .box_w = 6, .box_h = 26, .ofs_x = 2, .ofs_y = -5},
+ {.bitmap_index = 362, .adv_w = 130, .box_w = 5, .box_h = 26, .ofs_x = 1, .ofs_y = -5},
+ {.bitmap_index = 395, .adv_w = 179, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = 11},
+ {.bitmap_index = 416, .adv_w = 213, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = 3},
+ {.bitmap_index = 459, .adv_w = 107, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -5},
+ {.bitmap_index = 471, .adv_w = 133, .box_w = 7, .box_h = 2, .ofs_x = 1, .ofs_y = 6},
+ {.bitmap_index = 475, .adv_w = 107, .box_w = 4, .box_h = 4, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 479, .adv_w = 151, .box_w = 10, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
+ {.bitmap_index = 542, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 596, .adv_w = 213, .box_w = 10, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 641, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 700, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 754, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 813, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 872, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 926, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 980, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 1034, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 1088, .adv_w = 107, .box_w = 4, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 1102, .adv_w = 107, .box_w = 5, .box_h = 19, .ofs_x = 1, .ofs_y = -5},
+ {.bitmap_index = 1126, .adv_w = 213, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 3},
+ {.bitmap_index = 1165, .adv_w = 213, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 5},
+ {.bitmap_index = 1191, .adv_w = 213, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 3},
+ {.bitmap_index = 1230, .adv_w = 182, .box_w = 10, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 1275, .adv_w = 363, .box_w = 21, .box_h = 23, .ofs_x = 1, .ofs_y = -5},
+ {.bitmap_index = 1396, .adv_w = 233, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 1464, .adv_w = 252, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 1523, .adv_w = 245, .box_w = 14, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 1586, .adv_w = 264, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 1649, .adv_w = 226, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 1699, .adv_w = 212, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 1749, .adv_w = 265, .box_w = 14, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 1812, .adv_w = 280, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 1875, .adv_w = 113, .box_w = 3, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 1889, .adv_w = 205, .box_w = 11, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 1939, .adv_w = 248, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2002, .adv_w = 209, .box_w = 11, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2052, .adv_w = 312, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2124, .adv_w = 278, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2183, .adv_w = 285, .box_w = 16, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 2255, .adv_w = 243, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2314, .adv_w = 285, .box_w = 16, .box_h = 22, .ofs_x = 1, .ofs_y = -4},
+ {.bitmap_index = 2402, .adv_w = 244, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2461, .adv_w = 229, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 2520, .adv_w = 230, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 2583, .adv_w = 277, .box_w = 13, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 2642, .adv_w = 221, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 2705, .adv_w = 337, .box_w = 21, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 2800, .adv_w = 220, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 2863, .adv_w = 204, .box_w = 14, .box_h = 18, .ofs_x = -1, .ofs_y = 0},
+ {.bitmap_index = 2926, .adv_w = 232, .box_w = 13, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 2985, .adv_w = 130, .box_w = 6, .box_h = 25, .ofs_x = 2, .ofs_y = -5},
+ {.bitmap_index = 3023, .adv_w = 151, .box_w = 10, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
+ {.bitmap_index = 3086, .adv_w = 130, .box_w = 6, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
+ {.bitmap_index = 3124, .adv_w = 213, .box_w = 11, .box_h = 11, .ofs_x = 1, .ofs_y = 8},
+ {.bitmap_index = 3155, .adv_w = 215, .box_w = 14, .box_h = 2, .ofs_x = 0, .ofs_y = -4},
+ {.bitmap_index = 3162, .adv_w = 233, .box_w = 6, .box_h = 6, .ofs_x = 3, .ofs_y = 16},
+ {.bitmap_index = 3171, .adv_w = 216, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 3210, .adv_w = 237, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 3270, .adv_w = 196, .box_w = 11, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 3309, .adv_w = 238, .box_w = 12, .box_h = 20, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 3369, .adv_w = 213, .box_w = 12, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 3411, .adv_w = 125, .box_w = 9, .box_h = 20, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 3456, .adv_w = 217, .box_w = 13, .box_h = 20, .ofs_x = 1, .ofs_y = -6},
+ {.bitmap_index = 3521, .adv_w = 233, .box_w = 11, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 3576, .adv_w = 106, .box_w = 4, .box_h = 20, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 3596, .adv_w = 106, .box_w = 7, .box_h = 26, .ofs_x = -2, .ofs_y = -6},
+ {.bitmap_index = 3642, .adv_w = 212, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 3702, .adv_w = 109, .box_w = 4, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 3722, .adv_w = 356, .box_w = 19, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 3789, .adv_w = 234, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 3828, .adv_w = 233, .box_w = 13, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 3874, .adv_w = 238, .box_w = 12, .box_h = 20, .ofs_x = 2, .ofs_y = -6},
+ {.bitmap_index = 3934, .adv_w = 238, .box_w = 12, .box_h = 20, .ofs_x = 1, .ofs_y = -6},
+ {.bitmap_index = 3994, .adv_w = 149, .box_w = 8, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 4022, .adv_w = 180, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4061, .adv_w = 145, .box_w = 9, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4102, .adv_w = 233, .box_w = 11, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
+ {.bitmap_index = 4141, .adv_w = 200, .box_w = 13, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4187, .adv_w = 308, .box_w = 19, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4254, .adv_w = 191, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4296, .adv_w = 200, .box_w = 13, .box_h = 20, .ofs_x = 0, .ofs_y = -6},
+ {.bitmap_index = 4361, .adv_w = 182, .box_w = 11, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4400, .adv_w = 130, .box_w = 8, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
+ {.bitmap_index = 4450, .adv_w = 104, .box_w = 3, .box_h = 28, .ofs_x = 2, .ofs_y = -7},
+ {.bitmap_index = 4471, .adv_w = 130, .box_w = 8, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
+ {.bitmap_index = 4521, .adv_w = 213, .box_w = 13, .box_h = 4, .ofs_x = 0, .ofs_y = 7},
+ {.bitmap_index = 4534, .adv_w = 213, .box_w = 12, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 4588, .adv_w = 213, .box_w = 13, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4647, .adv_w = 384, .box_w = 6, .box_h = 6, .ofs_x = 9, .ofs_y = 7},
+ {.bitmap_index = 4656, .adv_w = 213, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
+ {.bitmap_index = 4719, .adv_w = 384, .box_w = 8, .box_h = 8, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 4735, .adv_w = 384, .box_w = 23, .box_h = 3, .ofs_x = 1, .ofs_y = 8},
+ {.bitmap_index = 4753, .adv_w = 384, .box_w = 22, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 4858, .adv_w = 384, .box_w = 22, .box_h = 21, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 4974, .adv_w = 384, .box_w = 23, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 5095, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 5216, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 5354, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 5469, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 5590, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 5711, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 5832, .adv_w = 384, .box_w = 20, .box_h = 22, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 5942, .adv_w = 384, .box_w = 22, .box_h = 17, .ofs_x = 1, .ofs_y = 0},
+ {.bitmap_index = 6036, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 6157, .adv_w = 384, .box_w = 22, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 6273, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 6406, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 6533, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 6665, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 6797, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 6935, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 7062, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 7200, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 7327, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 7454, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 7592, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 7724, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 7862, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 7994, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 8132, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 8270, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 8408, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 8541, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 8685, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 8823, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 8955, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 9093, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 9220, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 9347, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 9474, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 9595, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 9710, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 9843, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 9970, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 10097, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 10229, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 10362, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 10494, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 10632, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 10759, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 10886, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 11013, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 11151, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 11284, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 11422, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 11549, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 11687, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 11808, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 11935, .adv_w = 384, .box_w = 21, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 12046, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 12178, .adv_w = 384, .box_w = 24, .box_h = 21, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 12304, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 12437, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 12570, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 12708, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 12829, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 12956, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 13100, .adv_w = 384, .box_w = 20, .box_h = 21, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 13205, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 13320, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 13453, .adv_w = 384, .box_w = 21, .box_h = 22, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 13569, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 13701, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 13822, .adv_w = 384, .box_w = 20, .box_h = 22, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 13932, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 14059, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 14197, .adv_w = 384, .box_w = 23, .box_h = 21, .ofs_x = 0, .ofs_y = -1},
+ {.bitmap_index = 14318, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 14462, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 14583, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 14721, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 14859, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 15003, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 15141, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 15268, .adv_w = 384, .box_w = 23, .box_h = 21, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 15389, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 15522, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 15660, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 15793, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 15931, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 16058, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 16196, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 16334, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 16455, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 16587, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 16714, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 16846, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 16990, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 17128, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 17255, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 17393, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 17526, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 17659, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -1},
+ {.bitmap_index = 17786, .adv_w = 384, .box_w = 21, .box_h = 21, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 17897, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 18018, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 18156, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 18294, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 18427, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 18571, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 18704, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 18848, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 18969, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 19096, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 19223, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 19350, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 19465, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 19598, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 19742, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 19869, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 20002, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 20146, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 20279, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 20412, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 20539, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 20677, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 20810, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 20948, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 21081, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 21214, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 21358, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 21491, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 21612, .adv_w = 384, .box_w = 21, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 21738, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 21871, .adv_w = 384, .box_w = 21, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 21997, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 22130, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 22274, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 22418, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 22551, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 22695, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 22839, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 22983, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 23121, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 23259, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 23403, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 23530, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 23663, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 23796, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 23940, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 24078, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 24216, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 24349, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 24481, .adv_w = 384, .box_w = 16, .box_h = 22, .ofs_x = 4, .ofs_y = -3},
+ {.bitmap_index = 24569, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 24696, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 24817, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 24944, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 25082, .adv_w = 384, .box_w = 24, .box_h = 20, .ofs_x = 0, .ofs_y = -1},
+ {.bitmap_index = 25202, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 25334, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 25461, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 25593, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 25731, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 25875, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 26019, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 26157, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 26295, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 26433, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 26571, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 26715, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 26853, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 26997, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 27141, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 27285, .adv_w = 384, .box_w = 22, .box_h = 20, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 27395, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 27516, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 27654, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 27787, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 27920, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 28058, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 28191, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 28324, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 28462, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 28595, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 28727, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 28865, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 29003, .adv_w = 384, .box_w = 24, .box_h = 21, .ofs_x = 0, .ofs_y = -1},
+ {.bitmap_index = 29129, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 29250, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 29371, .adv_w = 384, .box_w = 21, .box_h = 23, .ofs_x = 3, .ofs_y = -2},
+ {.bitmap_index = 29492, .adv_w = 384, .box_w = 18, .box_h = 24, .ofs_x = 3, .ofs_y = -3},
+ {.bitmap_index = 29600, .adv_w = 384, .box_w = 21, .box_h = 24, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 29726, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 29853, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 29985, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 30123, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 30250, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 30388, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 30515, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 30647, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 30774, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 30912, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 31050, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 31183, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 31316, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 31449, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 31587, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 31714, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 31841, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -1},
+ {.bitmap_index = 31962, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 32100, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 32233, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 32371, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 32509, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 32647, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 32780, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 32907, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 33040, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 33173, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 33317, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 33450, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 33588, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -1},
+ {.bitmap_index = 33715, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 33848, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 33980, .adv_w = 384, .box_w = 20, .box_h = 21, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 34085, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 34206, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 34333, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 34466, .adv_w = 384, .box_w = 18, .box_h = 24, .ofs_x = 3, .ofs_y = -3},
+ {.bitmap_index = 34574, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 34707, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 34834, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 34972, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 35104, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 35231, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 35364, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 35491, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 35624, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 35751, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 35883, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 36010, .adv_w = 384, .box_w = 22, .box_h = 23, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 36137, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 36275, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 36408, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 36541, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 36679, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 36812, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 36944, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 37082, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 37203, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 37347, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 37485, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 37629, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 37767, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 37911, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 38038, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 38182, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 38309, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 38453, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 38580, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 38718, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 38856, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 38994, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 39115, .adv_w = 384, .box_w = 24, .box_h = 22, .ofs_x = 0, .ofs_y = -1},
+ {.bitmap_index = 39247, .adv_w = 384, .box_w = 23, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 39380, .adv_w = 384, .box_w = 22, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 39512, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 39650, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 39794, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = -2},
+ {.bitmap_index = 39932, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 40076, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 40220, .adv_w = 384, .box_w = 20, .box_h = 22, .ofs_x = 2, .ofs_y = -2},
+ {.bitmap_index = 40330, .adv_w = 384, .box_w = 20, .box_h = 23, .ofs_x = 2, .ofs_y = -3},
+ {.bitmap_index = 40445, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 40583, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 40721, .adv_w = 384, .box_w = 23, .box_h = 24, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 40859, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = -3},
+ {.bitmap_index = 40980, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 41124, .adv_w = 384, .box_w = 24, .box_h = 24, .ofs_x = 0, .ofs_y = -3},
+ {.bitmap_index = 41268, .adv_w = 384, .box_w = 23, .box_h = 22, .ofs_x = 1, .ofs_y = -2},
+ {.bitmap_index = 41395, .adv_w = 384, .box_w = 5, .box_h = 9, .ofs_x = 3, .ofs_y = -3},
+ {.bitmap_index = 41407, .adv_w = 384, .box_w = 4, .box_h = 17, .ofs_x = 4, .ofs_y = -1},
+ {.bitmap_index = 41424, .adv_w = 384, .box_w = 12, .box_h = 20, .ofs_x = 0, .ofs_y = -1}
};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
-static const uint16_t unicode_list_1[] = {
+static const uint16_t unicode_list_2[] = {
0x0, 0x2, 0x14, 0x2009, 0x2f5e, 0x4d5d, 0x4d66, 0x4d67,
0x4d6a, 0x4d6b, 0x4d87, 0x4d8a, 0x4d97, 0x4d98, 0x4da5, 0x4de3,
0x4de9, 0x4deb, 0x4def, 0x4e01, 0x4e04, 0x4e08, 0x4e0b, 0x4e1d,
@@ -6542,30 +6557,34 @@ static const uint16_t unicode_list_1[] = {
0x66be, 0x66ed, 0x6742, 0x6764, 0x677e, 0x6799, 0x681d, 0x68df,
0x697e, 0x6a9b, 0x6ac0, 0x6b32, 0x6b71, 0x6b95, 0x6bbd, 0x6c9b,
0x6ca8, 0x6ce5, 0x6d58, 0x7112, 0x71a4, 0x71a5, 0x7213, 0x7363,
- 0x747c, 0x7485, 0x7492, 0x75da, 0x75e1, 0x7635, 0x7655, 0x7742,
- 0x774a, 0x775e, 0x77cb, 0x7897, 0x78de, 0x791e, 0x792a, 0x792f,
- 0x794d, 0x7958, 0x7968, 0x796a, 0x7a28, 0x7a4c, 0x7adb, 0x7add,
- 0x7af4, 0x7afe, 0x7bd8, 0x7c58, 0x7e04, 0x7e16, 0x7e39, 0x7e3a,
- 0x7e3c, 0x7e44, 0x7e4a, 0x7e51, 0x7eae, 0x7ecb, 0x7ecf, 0x8077,
- 0x8147, 0x820c, 0x88de, 0x8940, 0x895d, 0x8afe, 0x8b01, 0x8b0d,
- 0x8b15, 0x8b1b, 0x8b1c, 0x8b1e, 0x8b2a, 0x8b32, 0x8b43, 0x8b4a,
- 0x8b4c, 0x8b54, 0x8c82, 0x8c83, 0x8ca1, 0x8d4c, 0x8d50, 0x8ecc,
- 0x8eda, 0x8ef0, 0x8f24, 0x8f36, 0x8f38, 0x8f3b, 0x8f5d, 0x8f66,
- 0x8f77, 0x8fb0, 0x912a, 0x912e, 0x93fc, 0x9402, 0x940e, 0x945b,
- 0x945e, 0x9476, 0x948b, 0x954a, 0x954b, 0x95c1, 0x95ec, 0x95f6,
- 0x97d2, 0x97fa, 0x99e9, 0x9a0d, 0xfe69, 0xfe77, 0xfe7c
+ 0x747c, 0x7485, 0x7492, 0x75da, 0x75e1, 0x7635, 0x764f, 0x7655,
+ 0x7742, 0x774a, 0x775e, 0x77cb, 0x7897, 0x78de, 0x791e, 0x792a,
+ 0x792f, 0x794d, 0x7958, 0x7968, 0x796a, 0x7a28, 0x7a4c, 0x7adb,
+ 0x7add, 0x7af4, 0x7afe, 0x7bd8, 0x7c58, 0x7e04, 0x7e16, 0x7e39,
+ 0x7e3a, 0x7e3c, 0x7e44, 0x7e4a, 0x7e51, 0x7eae, 0x7ecb, 0x7ecf,
+ 0x8077, 0x8147, 0x820c, 0x88de, 0x8940, 0x895d, 0x8afe, 0x8b01,
+ 0x8b0d, 0x8b15, 0x8b1b, 0x8b1c, 0x8b1e, 0x8b2a, 0x8b32, 0x8b43,
+ 0x8b4a, 0x8b4c, 0x8b54, 0x8c82, 0x8c83, 0x8ca1, 0x8d4c, 0x8d50,
+ 0x8ecc, 0x8eda, 0x8ef0, 0x8f24, 0x8f36, 0x8f38, 0x8f3b, 0x8f5d,
+ 0x8f66, 0x8f77, 0x8fb0, 0x912a, 0x912e, 0x93fc, 0x9402, 0x940e,
+ 0x945b, 0x945e, 0x9476, 0x948b, 0x954a, 0x954b, 0x95c1, 0x95ec,
+ 0x95f6, 0x97d2, 0x97fa, 0x99e9, 0x9a0d, 0xfe69, 0xfe77, 0xfe7c
};
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] =
{
{
- .range_start = 32, .range_length = 95, .glyph_id_start = 1,
+ .range_start = 32, .range_length = 2, .glyph_id_start = 1,
.unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
},
{
- .range_start = 163, .range_length = 65149, .glyph_id_start = 96,
- .unicode_list = unicode_list_1, .glyph_id_ofs_list = NULL, .list_length = 287, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
+ .range_start = 35, .range_length = 92, .glyph_id_start = 3,
+ .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
+ },
+ {
+ .range_start = 163, .range_length = 65149, .glyph_id_start = 95,
+ .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 288, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
}
};
@@ -6577,18 +6596,18 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
/*Map glyph_ids to kern left classes*/
static const uint8_t kern_left_class_mapping[] =
{
- 0, 0, 0, 1, 0, 0, 0, 0,
- 1, 2, 0, 0, 0, 3, 4, 3,
- 5, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 6, 6, 0, 0, 0,
- 0, 0, 7, 8, 9, 10, 11, 12,
- 13, 0, 0, 14, 15, 16, 0, 0,
- 10, 17, 10, 18, 19, 20, 21, 22,
- 23, 24, 25, 26, 2, 27, 0, 0,
- 0, 0, 28, 29, 30, 0, 31, 32,
- 33, 34, 0, 0, 35, 36, 34, 34,
- 29, 29, 37, 38, 39, 40, 37, 41,
- 42, 43, 44, 45, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 0, 0, 0, 3, 4, 3, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 6, 6, 0, 0, 0, 0,
+ 0, 7, 8, 9, 10, 11, 12, 13,
+ 0, 0, 14, 15, 16, 0, 0, 10,
+ 17, 10, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 2, 27, 0, 0, 0,
+ 0, 28, 29, 30, 0, 31, 32, 33,
+ 34, 0, 0, 35, 36, 34, 34, 29,
+ 29, 37, 38, 39, 40, 37, 41, 42,
+ 43, 44, 45, 2, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -6630,18 +6649,18 @@ static const uint8_t kern_left_class_mapping[] =
/*Map glyph_ids to kern right classes*/
static const uint8_t kern_right_class_mapping[] =
{
- 0, 0, 1, 2, 0, 0, 0, 0,
- 2, 0, 3, 4, 0, 5, 6, 7,
- 8, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 9, 10, 0, 0, 0,
- 11, 0, 12, 0, 13, 0, 0, 0,
- 13, 0, 0, 14, 0, 0, 0, 0,
- 13, 0, 13, 0, 15, 16, 17, 18,
- 19, 20, 21, 22, 0, 23, 3, 0,
- 0, 0, 24, 0, 25, 25, 25, 26,
- 27, 0, 28, 29, 0, 0, 30, 30,
- 25, 30, 25, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0, 0, 2,
+ 0, 3, 4, 0, 5, 6, 7, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 10, 0, 0, 0, 11,
+ 0, 12, 0, 13, 0, 0, 0, 13,
+ 0, 0, 14, 0, 0, 0, 0, 13,
+ 0, 13, 0, 15, 16, 17, 18, 19,
+ 20, 21, 22, 0, 23, 3, 0, 0,
+ 0, 24, 0, 25, 25, 25, 26, 27,
+ 0, 28, 29, 0, 0, 30, 30, 25,
+ 30, 25, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 0, 0, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -6929,7 +6948,7 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
.cmaps = cmaps,
.kern_dsc = &kern_classes,
.kern_scale = 16,
- .cmap_num = 2,
+ .cmap_num = 3,
.bpp = 2,
.kern_classes = 1,
.bitmap_format = 0,
### src/ui/gui_assets/font/ja/jaIllustrate.c
[binary or diff unavailable]
### src/ui/gui_assets/font/ko/koIllustrate.c
[binary or diff unavailable]
### src/ui/gui_chain/gui_btc.c
@@ -488,7 +488,9 @@ static PtrT_TransactionCheckResult GuiGetPsbtStrCheckResult(void)
}
result = btc_check_psbt_bytes(g_psbtBytes, g_psbtBytesLen, mfp, sizeof(mfp), public_keys, verify_without_mfp, wallet_config);
- if (result->error_code != 0 && strnlen_s(verify_without_mfp, MAX_VERIFY_CODE_LEN) == 0) {
+ if (result != NULL && result->error_code != 0 &&
+ verify_without_mfp != NULL &&
+ strnlen_s(verify_without_mfp, MAX_VERIFY_CODE_LEN) == 0) {
free_TransactionCheckResult(result);
result = btc_check_psbt_bytes(g_psbtBytes, g_psbtBytesLen, mfp, sizeof(mfp), public_keys, verify_code, wallet_config);
}
@@ -528,10 +530,12 @@ static PtrT_TransactionCheckResult CheckPsbt(void *crypto, uint8_t *mfp, uint32_
}
}
- result = btc_check_psbt(crypto, mfp, sizeof(mfp), public_keys, verify_without_mfp, wallet_config);
- if (result->error_code != 0 && strnlen_s(verify_without_mfp, MAX_VERIFY_CODE_LEN) == 0) {
+ result = btc_check_psbt(crypto, mfp, mfpLen, public_keys, verify_without_mfp, wallet_config);
+ if (result != NULL && result->error_code != 0 &&
+ verify_without_mfp != NULL &&
+ strnlen_s(verify_without_mfp, MAX_VERIFY_CODE_LEN) == 0) {
free_TransactionCheckResult(result);
- result = btc_check_psbt(crypto, mfp, sizeof(mfp), public_keys, verify_code, wallet_config);
+ result = btc_check_psbt(crypto, mfp, mfpLen, public_keys, verify_code, wallet_config);
}
SRAM_FREE(verify_without_mfp);
SRAM_FREE(verify_code);
@@ -1094,8 +1098,8 @@ static lv_obj_t *CreateOverviewFromView(lv_obj_t *parent, DisplayTxOverview *ove
if (hasMultiFromAddress) {
orderLabel = lv_label_create(formInnerContainer);
- char str[4] = {0};
- sprintf(str, "%d", (i + 1));
+ char str[BUFFER_SIZE_16] = {0};
+ snprintf(str, sizeof(str), "%d", (i + 1));
lv_label_set_text(orderLabel, str);
lv_obj_align(orderLabel, LV_ALIGN_DEFAULT, 0, 0);
SetTitleLabelStyle(orderLabel);
@@ -1166,8 +1170,8 @@ static lv_obj_t *CreateOverviewToView(lv_obj_t *parent, DisplayTxOverview *overv
if (hasMultiToAddress) {
toOrderLabel = lv_label_create(toInnerContainer);
- char str[4] = {0};
- sprintf(str, "%d", (i + 1));
+ char str[BUFFER_SIZE_16] = {0};
+ snprintf(str, sizeof(str), "%d", (i + 1));
lv_label_set_text(toOrderLabel, str);
lv_obj_align(toOrderLabel, LV_ALIGN_DEFAULT, 0, 0);
SetTitleLabelStyle(toOrderLabel);
@@ -1308,8 +1312,8 @@ static lv_obj_t *CreateDetailFromView(lv_obj_t *parent, DisplayTxDetail *detailD
lv_obj_set_style_bg_opa(formInnerContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
orderLabel = lv_label_create(formInnerContainer);
- char str[4] = {0};
- sprintf(str, "%d", (i + 1));
+ char str[BUFFER_SIZE_16] = {0};
+ snprintf(str, sizeof(str), "%d", (i + 1));
lv_label_set_text(orderLabel, str);
lv_obj_align(orderLabel, LV_ALIGN_DEFAULT, 0, 0);
SetTitleLabelStyle(orderLabel);
@@ -1394,8 +1398,8 @@ static lv_obj_t *CreateDetailToView(lv_obj_t *parent, DisplayTxDetail *detailDat
lv_obj_set_style_bg_opa(toInnerContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
orderLabel = lv_label_create(toInnerContainer);
- char str[4] = {0};
- sprintf(str, "%d", (i + 1));
+ char str[BUFFER_SIZE_16] = {0};
+ snprintf(str, sizeof(str), "%d", (i + 1));
lv_label_set_text(orderLabel, str);
lv_obj_align(orderLabel, LV_ALIGN_DEFAULT, 0, 0);
SetTitleLabelStyle(orderLabel);
### src/ui/gui_chain/multi/cypherpunk/gui_monero.c
@@ -276,7 +276,7 @@ void GuiShowXmrTransactionOverview(lv_obj_t *parent, void *totalData)
bool is_change = data->outputs->data[i].is_change;
uint32_t addressY = 18 + 38 + i * 120 + addressOffset;
char outputIndex[BUFFER_SIZE_16] = {0};
- sprintf(outputIndex, "%d", i + 1);
+ snprintf(outputIndex, sizeof(outputIndex), "%zu", i + 1);
label = GuiCreateIllustrateLabel(detilsContainer, outputIndex);
lv_obj_align(label, LV_ALIGN_DEFAULT, 24, addressY);
lv_obj_set_style_text_opa(label, 144, LV_PART_MAIN);
@@ -349,7 +349,7 @@ void GuiShowXmrTransactionDetails(lv_obj_t *parent, void *totalData)
for (size_t i = 0; i < data->inputs->size; i++) {
char inputIndex[BUFFER_SIZE_16] = {0};
- sprintf(inputIndex, "Pubkey %d", i + 1);
+ snprintf(inputIndex, sizeof(inputIndex), "Pubkey %zu", i + 1);
lv_obj_t *titleLabel = GuiCreateIllustrateLabel(inputsContainer, inputIndex);
lv_obj_align(titleLabel, LV_ALIGN_DEFAULT, 24, 54 + i * 120);
lv_obj_set_style_text_opa(titleLabel, 144, LV_PART_MAIN);
@@ -376,7 +376,7 @@ void GuiShowXmrTransactionDetails(lv_obj_t *parent, void *totalData)
for (size_t i = 0; i < data->outputs->size; i++) {
bool is_change = data->outputs->data[i].is_change;
char outputIndex[BUFFER_SIZE_16] = {0};
- sprintf(outputIndex, "Address %d", i + 1);
+ snprintf(outputIndex, sizeof(outputIndex), "Address %zu", i + 1);
lv_obj_t *titleLabel = GuiCreateIllustrateLabel(outputsContainer, outputIndex);
lv_obj_align(titleLabel, LV_ALIGN_DEFAULT, 24, 54 + i * 150);
lv_obj_set_style_text_opa(titleLabel, 144, LV_PART_MAIN);
@@ -401,4 +401,4 @@ void GuiShowXmrTransactionDetails(lv_obj_t *parent, void *totalData)
lv_obj_align(label, LV_ALIGN_DEFAULT, 24, 84 + i * 150);
lv_obj_set_width(label, 332);
}
-}
\ No newline at end of file
+}
### src/ui/gui_chain/multi/web3/gui_ada.c
@@ -277,10 +277,15 @@ PtrT_TransactionCheckResult GuiGetAdaCatalystCheckResult(void)
uint8_t mfp[4];
GetMasterFingerPrint(mfp);
Ptr_SimpleResponse_c_char master_key_index = cardano_get_catalyst_root_index(data);
- if (master_key_index->error_code != 0) {
+ if (master_key_index == NULL) {
+ return NULL;
+ }
+ if (master_key_index->error_code != 0 || master_key_index->data == NULL) {
+ free_simple_response_c_char(master_key_index);
return NULL;
}
uint16_t index = atoi(master_key_index->data);
+ free_simple_response_c_char(master_key_index);
char *xpub = GetCurrentAccountPublicKey(GetAdaXPubTypeByIndex(index));
PtrT_TransactionCheckResult precheckResult;
precheckResult = cardano_check_catalyst_path_type(data, xpub);
@@ -910,13 +915,22 @@ void GuiShowAdaSignTxHashDetails(lv_obj_t *parent, void *totalData)
// address + path card
Ptr_VecFFI_PtrString addressList = hashData->address_list;
Ptr_VecFFI_PtrString pathList = hashData->path;
- for (int i = 0; i < addressList->size; i++) {
+ if (addressList == NULL || pathList == NULL || addressList->size != pathList->size ||
+ (addressList->size > 0 && (addressList->data == NULL || pathList->data == NULL))) {
+ return;
+ }
+ for (size_t i = 0; i < addressList->size; i++) {
+ if (addressList->data[i] == NULL || pathList->data[i] == NULL) {
+ return;
+ }
+ }
+ for (size_t i = 0; i < addressList->size; i++) {
char *address = addressList->data[i];
char *path = pathList->data[i];
char formattedPath[128] = {0};
snprintf(formattedPath, sizeof(formattedPath), "m/%s", path);
char num[10] = {0};
- snprintf(num, sizeof(num), "%d", i + 1);
+ snprintf(num, sizeof(num), "%zu", i + 1);
lv_obj_t *num_label = GuiCreateIllustrateLabel(from_container, num);
lv_obj_set_style_text_color(num_label, WHITE_COLOR, LV_PART_MAIN);
lv_obj_set_style_text_opa(num_label, 144, LV_PART_MAIN | LV_STATE_DEFAULT);
@@ -1162,4 +1176,4 @@ void GetCatalystVoteKeysSize(uint16_t *width, uint16_t *height, void *param)
DisplayCardanoCatalyst *data = (DisplayCardanoCatalyst *)param;
*width = 408;
*height = 62 + 60 * data->vote_keys->size;
-}
\ No newline at end of file
+}
### src/ui/gui_chain/multi/web3/gui_cosmos.c
@@ -477,22 +477,35 @@ void GuiCosmosTxDetails(lv_obj_t *parent, void *totalData)
lv_obj_update_layout(parent);
}
-static lv_obj_t *CreateCosmosDetailInlineValue(lv_obj_t *container, const char *titleText,
- const char *valueText, uint16_t y, bool highlight)
+static uint16_t CreateCosmosDetailInlineValue(lv_obj_t *container, const char *titleText,
+ const char *valueText, uint16_t y, bool highlight)
{
if (valueText == NULL) {
- return NULL;
+ return y;
}
lv_obj_t *title = GuiCreateIllustrateLabel(container, _(titleText));
lv_obj_align(title, LV_ALIGN_TOP_LEFT, 24, y);
lv_obj_set_style_text_opa(title, LV_OPA_64, LV_PART_MAIN);
+ lv_obj_update_layout(title);
lv_obj_t *value = GuiCreateIllustrateLabel(container, valueText);
if (highlight) {
lv_obj_set_style_text_color(value, ORANGE_COLOR, LV_PART_MAIN);
}
- lv_obj_align_to(value, title, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
- return value;
+ int32_t valueWidth = 360 - lv_obj_get_width(title) - 16;
+ if (valueWidth < 1) {
+ valueWidth = 1;
+ }
+ lv_obj_set_width(value, valueWidth);
+ lv_label_set_long_mode(value, LV_LABEL_LONG_WRAP);
+ lv_obj_align_to(value, title, LV_ALIGN_OUT_RIGHT_TOP, 16, 0);
+ lv_obj_update_layout(value);
+
+ int32_t rowHeight = lv_obj_get_height(title);
+ if (lv_obj_get_height(value) > rowHeight) {
+ rowHeight = lv_obj_get_height(value);
+ }
+ return y + rowHeight + 8;
}
static lv_obj_t *CreateCosmosVoteDetails(lv_obj_t *parent, const cJSON *message, lv_obj_t *lastView)
@@ -502,38 +515,54 @@ static lv_obj_t *CreateCosmosVoteDetails(lv_obj_t *parent, const cJSON *message,
lv_obj_align_to(container, lastView, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 16);
}
- CreateCosmosDetailInlineValue(container, "Proposal", GetCosmosJsonString(message, "Proposal"), 16, true);
- CreateCosmosDetailInlineValue(container, "Voted", GetCosmosJsonString(message, "Voted"), 54, true);
- CreateCosmosDetailInlineValue(container, "Method", GetCosmosJsonString(message, "Method"), 92, false);
+ uint16_t y = 16;
+ y = CreateCosmosDetailInlineValue(
+ container, "Proposal", GetCosmosJsonString(message, "Proposal"), y, true);
+ y = CreateCosmosDetailInlineValue(
+ container, "Voted", GetCosmosJsonString(message, "Voted"), y, true);
+ y = CreateCosmosDetailInlineValue(
+ container, "Method", GetCosmosJsonString(message, "Method"), y, false);
lv_obj_t *voterTitle = GuiCreateIllustrateLabel(container, _("Voter"));
- lv_obj_align(voterTitle, LV_ALIGN_TOP_LEFT, 24, 130);
+ lv_obj_align(voterTitle, LV_ALIGN_TOP_LEFT, 24, y);
lv_obj_set_style_text_opa(voterTitle, LV_OPA_64, LV_PART_MAIN);
const char *voter = GetCosmosJsonString(message, "Voter");
lv_obj_t *voterValue = GuiCreateIllustrateLabel(container, voter == NULL ? "" : voter);
lv_obj_set_width(voterValue, 360);
lv_label_set_long_mode(voterValue, LV_LABEL_LONG_WRAP);
- lv_obj_align(voterValue, LV_ALIGN_TOP_LEFT, 24, 168);
+ lv_obj_align(voterValue, LV_ALIGN_TOP_LEFT, 24, y + 38);
lv_obj_update_layout(voterValue);
- lv_obj_set_height(container, 168 + lv_obj_get_height(voterValue) + 16);
+ lv_obj_set_height(container, y + 38 + lv_obj_get_height(voterValue) + 16);
return container;
}
static lv_obj_t *CreateCosmosFeeDetails(lv_obj_t *parent, const cJSON *common, lv_obj_t *lastView)
{
+ const char *maxFee = GetCosmosJsonString(common, "Max Fee");
const char *fee = GetCosmosJsonString(common, "Fee");
const char *gasLimit = GetCosmosJsonString(common, "Gas Limit");
- if (fee == NULL && gasLimit == NULL) {
+ if (maxFee == NULL && fee == NULL && gasLimit == NULL) {
return lastView;
}
- lv_obj_t *container = CreateContentContainer(parent, 408, 100);
+ lv_obj_t *container = CreateContentContainer(parent, 408, 0);
if (lastView != NULL) {
lv_obj_align_to(container, lastView, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 16);
}
- CreateCosmosDetailInlineValue(container, "Fee", fee, 16, false);
- CreateCosmosDetailInlineValue(container, "Gas Limit", gasLimit, 54, false);
+ uint16_t y = 16;
+ y = CreateCosmosDetailInlineValue(container, "Max Fee", maxFee, y, false);
+ if (maxFee != NULL) {
+ lv_obj_t *description = GuiCreateLabelWithFont(
+ container, " · Max Fee Price * Gas Limit", &openSansDesc);
+ lv_obj_set_style_text_opa(description, LV_OPA_64, LV_PART_MAIN);
+ lv_obj_align(description, LV_ALIGN_TOP_LEFT, 24, y);
+ lv_obj_update_layout(description);
+ y += lv_obj_get_height(description) + 8;
+ }
+ y = CreateCosmosDetailInlineValue(container, "Fee", fee, y, false);
+ y = CreateCosmosDetailInlineValue(container, "Gas Limit", gasLimit, y, false);
+ lv_obj_set_height(container, y + 8);
return container;
}
@@ -545,12 +574,14 @@ static lv_obj_t *CreateCosmosNetworkDetails(lv_obj_t *parent, const cJSON *commo
return lastView;
}
- lv_obj_t *container = CreateContentContainer(parent, 408, 100);
+ lv_obj_t *container = CreateContentContainer(parent, 408, 0);
if (lastView != NULL) {
lv_obj_align_to(container, lastView, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 16);
}
- CreateCosmosDetailInlineValue(container, "Network", network, 16, false);
- CreateCosmosDetailInlineValue(container, "Chain ID", chainId, 54, false);
+ uint16_t y = 16;
+ y = CreateCosmosDetailInlineValue(container, "Network", network, y, false);
+ y = CreateCosmosDetailInlineValue(container, "Chain ID", chainId, y, false);
+ lv_obj_set_height(container, y + 8);
return container;
}
### src/ui/gui_chain/multi/web3/gui_eth.c
@@ -1105,37 +1105,62 @@ void GetEthPersonalMessageType(void *indata, void *param, uint32_t maxLen)
void GetMessageFrom(void *indata, void *param, uint32_t maxLen)
{
DisplayETHPersonalMessage *message = (DisplayETHPersonalMessage *)param;
- if (message->from == NULL) {
- strcpy_s((char *)indata, maxLen, "");
+ if (indata == NULL || maxLen == 0) {
+ return;
+ }
+ if (message == NULL || message->from == NULL) {
+ ((char *)indata)[0] = '\0';
return;
}
if (strlen(message->from) >= maxLen) {
- snprintf((char *)indata, maxLen - 3, "%s", message->from);
- strcat((char *)indata, "...");
+ if (maxLen <= 4) {
+ snprintf((char *)indata, maxLen, "%.*s", (int)(maxLen - 1), "...");
+ } else {
+ snprintf((char *)indata, maxLen, "%.*s...", (int)(maxLen - 4), message->from);
+ }
} else {
strcpy_s((char *)indata, maxLen, message->from);
}
}
void GetMessageUtf8(void *indata, void *param, uint32_t maxLen)
{
DisplayETHPersonalMessage *message = (DisplayETHPersonalMessage *)param;
+ if (indata == NULL || maxLen == 0) {
+ return;
+ }
+ if (message == NULL || message->utf8_message == NULL) {
+ ((char *)indata)[0] = '\0';
+ return;
+ }
if (strlen(message->utf8_message) >= maxLen) {
- snprintf((char *)indata, maxLen - 3, "%s", message->utf8_message);
- strcat((char *)indata, "...");
+ if (maxLen <= 4) {
+ snprintf((char *)indata, maxLen, "%.*s", (int)(maxLen - 1), "...");
+ } else {
+ snprintf((char *)indata, maxLen, "%.*s...", (int)(maxLen - 4), message->utf8_message);
+ }
} else {
snprintf((char *)indata, maxLen, "%s", message->utf8_message);
}
}
void GetMessageRaw(void *indata, void *param, uint32_t maxLen)
{
- int len = strlen("\n#F5C131 The data is not parseable. Please#\n#F5C131 refer to the software wallet interface#\n#F5C131 for viewing.#");
+ const char *warning = "\n#F5C131 The data is not parseable. Please#\n#F5C131 refer to the software wallet interface#\n#F5C131 for viewing.#";
+ size_t warningLen = strlen(warning);
DisplayETHPersonalMessage *message = (DisplayETHPersonalMessage *)param;
- if (strlen(message->raw_message) >= maxLen - len) {
- snprintf((char *)indata, maxLen - 3 - len, "%s", message->raw_message);
- strcat((char *)indata, "...");
+ if (indata == NULL || maxLen == 0) {
+ return;
+ }
+ if (message == NULL || message->raw_message == NULL) {
+ ((char *)indata)[0] = '\0';
+ return;
+ }
+ if (warningLen + 4 >= maxLen) {
+ snprintf((char *)indata, maxLen, "%.*s", (int)(maxLen - 1), "...");
+ } else if (strlen(message->raw_message) + warningLen >= maxLen) {
+ snprintf((char *)indata, maxLen, "%.*s...", (int)(maxLen - warningLen - 4), message->raw_message);
} else {
- snprintf((char *)indata, maxLen, "%s%s", message->raw_message, "\n#F5C131 The data is not parseable. Please#\n#F5C131 refer to the software wallet interface#\n#F5C131 for viewing.#");
+ snprintf((char *)indata, maxLen, "%s%s", message->raw_message, warning);
}
}
@@ -1290,7 +1315,7 @@ static lv_obj_t *CreateEthOverviewValueView(lv_obj_t *parent, DisplayETH *eth, l
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, 16);
lv_obj_set_style_text_opa(label, LV_OPA_64, LV_PART_MAIN);
- label = GuiCreateLittleTitleLabel(container, value);
+ label = GuiCreateLabelWithFont(container, value, GetOverviewAmountFont(value));
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, 50);
lv_obj_set_width(label, ETH_COMPONENT_CONTENT_WIDTH);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
@@ -1304,7 +1329,7 @@ static lv_obj_t *CreateEthOverviewValueView(lv_obj_t *parent, DisplayETH *eth, l
}
GetEthTxFee(value, eth, sizeof(value));
- nextY = CreateEthOverviewValueRow(container, _("MaxTxnFee"), value, nextY);
+ nextY = CreateEthOverviewValueRow(container, _("Max Txn Fee"), value, nextY);
lv_obj_set_height(container, nextY + 8);
lv_obj_update_layout(container);
return container;
@@ -1502,29 +1527,30 @@ static lv_obj_t *CreateEthDetailsFeeView(lv_obj_t *parent, DisplayETH *eth, lv_o
if (feeMarket) {
GetEthMaxFee(value, eth, sizeof(value));
- y = CreateEthDetailsPair(container, _("MaxFee"), value, y, false);
- y = CreateEthDetailsDescription(container, _("·MaxFeePrice*GasLimit"), y, NULL);
+ y = CreateEthDetailsPair(container, _("Max Fee"), value, y, false);
+ y = CreateEthDetailsDescription(
+ container, " · Max Fee Price * Gas Limit", y, NULL);
GetEthMaxPriority(value, eth, sizeof(value));
- y = CreateEthDetailsPair(container, _("MaxPriority"), value, y, false);
+ y = CreateEthDetailsPair(container, _("Max Priority Fee"), value, y, false);
y = CreateEthDetailsDescription(
- container, _("·MaxPriorityFeePrice*GasLimit"), y, NULL);
+ container, " · Max Priority Fee Price * Gas Limit", y, NULL);
GetEthMaxFeePrice(value, eth, sizeof(value));
- y = CreateEthDetailsPair(container, _("MaxFeePrice"), value, y, false);
+ y = CreateEthDetailsPair(container, _("Max Fee Price"), value, y, false);
GetEthMaxPriorityFeePrice(value, eth, sizeof(value));
- y = CreateEthDetailsPair(container, _("MaxPriorityFeePrice"), value, y, false);
- y = CreateEthDetailsPair(container, _("GasLimit"), eth->overview->gas_limit, y, false);
+ y = CreateEthDetailsPair(container, _("Max Priority Fee Price"), value, y, false);
+ y = CreateEthDetailsPair(container, _("Gas Limit"), eth->overview->gas_limit, y, false);
} else {
GetEthTxFee(value, eth, sizeof(value));
- y = CreateEthDetailsPair(container, _("MaxTxnFee"), value, y, false);
+ y = CreateEthDetailsPair(container, _("Max Txn Fee"), value, y, false);
y = CreateEthDetailsDescription(
- container, " \xE2\x80\xA2 Max Txn Fee = Gas Price * Gas Limit", y,
+ container, " · Max Txn Fee = Gas Price * Gas Limit", y,
&openSansDesc);
y = CreateEthDetailsPair(
- container, _("GasPrice"), eth->overview->gas_price, y, false);
+ container, _("Gas Price"), eth->overview->gas_price, y, false);
y = CreateEthDetailsPair(
- container, _("GasLimit"), eth->overview->gas_limit, y, false);
+ container, _("Gas Limit"), eth->overview->gas_limit, y, false);
}
lv_obj_set_height(container, y + 8);
return container;
### src/ui/gui_chain/multi/web3/gui_sol.c
@@ -9,7 +9,6 @@
#include "screen_manager.h"
#include "account_manager.h"
#include "assert.h"
-#include "cjson/cJSON.h"
#include "gui_qr_hintbox.h"
#define SQUADS_V4_CREATE_MULTISIG_CONTRACT_ADDRESS "5DH2e3cJmFpyi6mk65EGFediunm4ui6BiKNUNrhWtD1b"
@@ -172,10 +171,19 @@ void GetSolMessageType(void *indata, void *param, uint32_t maxLen)
void GetSolMessageFrom(void *indata, void *param, uint32_t maxLen)
{
DisplaySolanaMessage *message = (DisplaySolanaMessage *)param;
+ if (indata == NULL || maxLen == 0) {
+ return;
+ }
+ if (message == NULL || message->from == NULL) {
+ ((char *)indata)[0] = '\0';
+ return;
+ }
if (strlen(message->from) >= maxLen) {
- snprintf((char *)indata, maxLen - 3, "%s", message->from);
- strcat((char *)indata, "...");
- snprintf((char *)indata, maxLen, "%.*s...", maxLen - 4, message->from);
+ if (maxLen <= 4) {
+ snprintf((char *)indata, maxLen, "%.*s", (int)(maxLen - 1), "...");
+ } else {
+ snprintf((char *)indata, maxLen, "%.*s...", (int)(maxLen - 4), message->from);
+ }
} else {
strcpy_s((char *)indata, maxLen, message->from);
}
@@ -806,7 +814,8 @@ static void GuiShowSolTxSquadsProposalOverview(lv_obj_t *parent, PtrT_DisplaySol
if (strcmp(method, "Transfer") != 0) {
continue;
}
- lv_obj_t *feeContainer = GuiCreateAutoHeightContainer(parent, 408, 16);
+ lv_obj_t *feeContainer = GuiCreateAutoHeightContainer(
+ parent, SOL_COMPONENT_WIDTH, 16);
lv_obj_t *feeLabel = lv_label_create(feeContainer);
lv_label_set_text(feeLabel, "Fee");
lv_obj_set_style_text_color(feeLabel, WHITE_COLOR, LV_PART_MAIN);
@@ -1526,11 +1535,10 @@ void GuiShowSolTxOverview(lv_obj_t *parent, void *totalData)
static void GuiShowSolTxRawDetailCard(
lv_obj_t *parent,
PtrString txDetail,
- lv_obj_t *lastView,
- bool useParentScroll)
+ lv_obj_t *lastView)
{
lv_obj_t *cont = lv_obj_create(parent);
- lv_obj_set_size(cont, SOL_COMPONENT_WIDTH, 444);
+ lv_obj_set_size(cont, SOL_COMPONENT_WIDTH, LV_SIZE_CONTENT);
lv_obj_set_style_border_width(cont, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_clip_corner(cont, 0, 0);
lv_obj_set_style_radius(cont, 24, LV_PART_MAIN | LV_STATE_DEFAULT);
@@ -1542,30 +1550,19 @@ static void GuiShowSolTxRawDetailCard(
lv_obj_set_style_pad_left(cont, 24, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(cont, 24, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_align(cont, LV_ALIGN_TOP_LEFT, 0, 0);
- if (useParentScroll) {
- lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
- lv_obj_clear_flag(cont, LV_OBJ_FLAG_CLICKABLE);
- } else {
- lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
- lv_obj_add_flag(cont, LV_OBJ_FLAG_CLICKABLE);
- }
+ lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
+ lv_obj_clear_flag(cont, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF);
lv_obj_t *label = lv_label_create(cont);
const char *rawDetail = txDetail == NULL ? "" : txDetail;
- cJSON *root = useParentScroll ? NULL : cJSON_Parse(rawDetail);
- char *retStr = root == NULL ? NULL : cJSON_PrintBuffered(root, BUFFER_SIZE_1024, false);
- lv_label_set_text(label, retStr == NULL ? rawDetail : retStr);
- EXT_FREE(retStr);
- cJSON_Delete(root);
+ lv_label_set_text(label, rawDetail);
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
lv_obj_set_width(label, SOL_COMPONENT_CONTENT_WIDTH);
SetTitleLabelStyle(label);
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 0, 0);
- if (useParentScroll) {
- lv_obj_update_layout(label);
- lv_obj_set_height(cont, lv_obj_get_height(label) + 32);
- }
+ lv_obj_update_layout(label);
+ lv_obj_set_height(cont, lv_obj_get_height(label) + 32);
if (lastView == NULL) {
lv_obj_align(cont, LV_ALIGN_TOP_LEFT, 0, 0);
} else {
@@ -1581,18 +1578,12 @@ void GuiShowSolTxDetail(lv_obj_t *parent, void *totalData)
DisplaySolanaTx *txData = (DisplaySolanaTx*)totalData;
PtrT_DisplaySolanaTxOverview overviewData = txData->overview;
if (0 == strcmp(overviewData->display_type, "squads_multisig_create")) {
- // The specialized page contains multiple cards and a raw-detail card;
- // keep a fixed viewport so the complete page can be scrolled.
- lv_obj_set_height(parent, 444);
- lv_obj_add_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
- lv_obj_set_scrollbar_mode(parent, LV_SCROLLBAR_MODE_OFF);
GuiShowSolTxMultiSigCreateDetail(parent, overviewData);
lv_obj_update_layout(parent);
GuiShowSolTxRawDetailCard(
- parent, txData->detail, GuiGetSolTxBottomView(parent), true);
+ parent, txData->detail, GuiGetSolTxBottomView(parent));
lv_obj_update_layout(parent);
- lv_obj_scroll_to_y(parent, 0, LV_ANIM_OFF);
return;
}
- GuiShowSolTxRawDetailCard(parent, txData->detail, NULL, false);
+ GuiShowSolTxRawDetailCard(parent, txData->detail, NULL);
}
### src/ui/gui_wallet/multi/web3/gui_wallet.c
@@ -414,7 +414,7 @@ UREncodeResult *GuiGetADADataByIndex(char *walletName)
char* xpub = GetCurrentAccountPublicKey(GetAdaXPubTypeByIndexAndDerivationType(
GetConnectWalletPathIndex(walletName), index));
char path[BUFFER_SIZE_32] = {0};
- sprintf(path, "1852'/1815'/%u'", index);
+ snprintf(path, sizeof(path), "1852'/1815'/%u'", index);
ExtendedPublicKey xpubs[1];
xpubs[0].path = path;
xpubs[0].xpub = xpub;
@@ -765,4 +765,4 @@ UREncodeResult *GuiGetThorWalletData(void)
CHECK_CHAIN_PRINT(urEncode);
SRAM_FREE(public_keys);
return urEncode;
-}
\ No newline at end of file
+}
### src/ui/gui_widgets/btc_only/multi_sig/gui_multisig_transaction_signature_widgets.c
@@ -226,9 +226,9 @@ static void GuiMultisigTransactionSignatureContent(lv_obj_t *parent)
if (g_signStatus != NULL) {
char signStatus[64] = {0};
if (strncmp(g_signStatus, "Completed", 9) == 0) {
- sprintf(signStatus, "#00FF00 %s#", _("multi_signature_completed"));
+ snprintf(signStatus, sizeof(signStatus), "#00FF00 %s#", _("multi_signature_completed"));
} else {
- sprintf(signStatus, "#F5870A %s#", g_signStatus);
+ snprintf(signStatus, sizeof(signStatus), "#F5870A %s#", g_signStatus);
}
if (g_signStatusView != NULL) {
lv_obj_del(g_signStatusView);
@@ -293,4 +293,4 @@ void GuiMultisigTransactionSignaureWidgetsRefresh()
{
GuiMultisigTransactionSignatureContent(g_cont);
GuiAnimatingQRCodeControl(false);
-}
\ No newline at end of file
+}
### src/ui/gui_widgets/multi/gui_key_derivation_request_widgets.c
@@ -16,6 +16,8 @@
#include "account_public_info.h"
#include "gui_key_derivation_request_widgets.h"
+#define MAX_KEY_DERIVATION_SCHEMAS 24U
+
typedef struct KeyDerivationWidget {
uint8_t currentTile;
PageWidget_t *pageWidget;
@@ -80,7 +82,8 @@ static void GuiCreateQRCodeWidget(lv_obj_t *parent);
static void GuiCreateCommonHardWareCallQRCodeWidget(lv_obj_t *parent);
static void OnApproveHandler(lv_event_t *e);
static void OnReturnHandler(lv_event_t *e);
-static void ModelParseQRHardwareCall();
+static bool ModelParseQRHardwareCall(void);
+static void SetHardwareCallParamsCheckResult(HardwareCallResult_t result);
static UREncodeResult *ModelGenerateSyncUR(void);
static void OpenTutorialHandler(lv_event_t *e);
static void OpenMoreHandler(lv_event_t *e);
@@ -171,7 +174,13 @@ void GuiKeyDerivationRequestInit(bool isUsb)
SetNavBarLeftBtn(g_keyDerivationTileView.pageWidget->navBarWidget, NVS_BAR_RETURN, CloseCurrentViewHandler, NULL);
lv_obj_t *tileView = GuiCreateTileView(g_keyDerivationTileView.pageWidget->contentZone);
lv_obj_t *tile = lv_tileview_add_tile(tileView, TILE_APPROVE, 0, LV_DIR_HOR);
- ModelParseQRHardwareCall();
+ if (!ModelParseQRHardwareCall()) {
+ if (isUsb) {
+ const char *message = "Invalid hardware call parameters";
+ HandleURResultViaUSBAsyncFunc(message, strlen(message), GetCurrentUSParsingRequestID(), PRS_PARSING_ERROR);
+ }
+ return;
+ }
// choose different animate qr widget by hardware call version
if (strcmp("1", g_callData->version) == 0) {
GuiCreateHardwareCallApproveWidget(tile);
@@ -385,14 +394,38 @@ void UpdateAndParseHardwareCall(void)
free_Response_QRHardwareCallData(g_response);
g_response = NULL;
}
- ModelParseQRHardwareCall();
- HiddenKeyboardAndShowAnimateQR();
+ if (ModelParseQRHardwareCall()) {
+ HiddenKeyboardAndShowAnimateQR();
+ } else {
+ const char *message = "Invalid hardware call parameters";
+ HandleURResultViaUSBAsyncFunc(message, strlen(message), GetCurrentUSParsingRequestID(), PRS_PARSING_ERROR);
+ }
}
}
-static void ModelParseQRHardwareCall()
+static bool ModelParseQRHardwareCall(void)
{
+ if (g_data == NULL) {
+ g_callData = NULL;
+ SetHardwareCallParamsCheckResult((HardwareCallResult_t) {
+ false, _("invaild_schemas_size"), _("invaild_schemas_size_big")
+ });
+ return false;
+ }
+
Response_QRHardwareCallData *data = parse_qr_hardware_call(g_data);
+ if (data == NULL || data->error_code != 0 || data->data == NULL ||
+ data->data->key_derivation == NULL ||
+ data->data->key_derivation->schemas == NULL ||
+ data->data->key_derivation->schemas->data == NULL ||
+ data->data->version == NULL || data->data->origin == NULL) {
+ g_callData = NULL;
+ g_response = data;
+ SetHardwareCallParamsCheckResult((HardwareCallResult_t) {
+ false, _("invaild_schemas_size"), _("invaild_schemas_size_big")
+ });
+ return false;
+ }
g_callData = data->data;
g_response = data;
for (size_t i = 0; i < g_callData->key_derivation->schemas->size; i++) {
@@ -402,6 +435,7 @@ static void ModelParseQRHardwareCall()
g_hasAda = true;
}
CheckHardwareCallRequestIsLegal();
+ return true;
}
typedef enum {
@@ -479,7 +513,8 @@ static HardwareCallResult_t CheckHardWareCallV0AdaPathIsLegal(char *path)
static HardwareCallResult_t CheckHardwareCallRequestIsLegal(void)
{
- if (g_callData->key_derivation->schemas->size > 24) {
+ if (g_callData->key_derivation->schemas->size == 0U ||
+ g_callData->key_derivation->schemas->size > MAX_KEY_DERIVATION_SCHEMAS) {
SetHardwareCallParamsCheckResult((HardwareCallResult_t) {
false, _("invaild_schemas_size"), _("invaild_schemas_size_big")
});
@@ -513,9 +548,10 @@ static HardwareCallResult_t CheckHardwareCallRequestIsLegal(void)
});
return g_hardwareCallParamsCheckResult;
}
- // check path match the chainType
- Response_bool *response = check_hardware_call_path(g_response->data->key_derivation->schemas->data[i].key_path, g_response->data->key_derivation->schemas->data[i].chain_type);
- if (*response->data == false) {
+ // Check whether the requested derivation path is supported.
+ Response_bool *response = check_hardware_call_path(g_response->data->key_derivation->schemas->data[i].key_path);
+ if (response == NULL || response->error_code != 0 ||
+ response->data == NULL || *response->data == false) {
SetHardwareCallParamsCheckResult((HardwareCallResult_t) {
false, _("invaild_account_path"), _("invaild_account_path_notice")
});
@@ -532,6 +568,18 @@ static HardwareCallResult_t CheckHardwareCallRequestIsLegal(void)
static UREncodeResult *ModelGenerateSyncUR(void)
{
+ if (g_callData == NULL || g_callData->version == NULL ||
+ g_callData->key_derivation == NULL ||
+ g_callData->key_derivation->schemas == NULL ||
+ g_callData->key_derivation->schemas->data == NULL) {
+ return NULL;
+ }
+
+ size_t schemaCount = g_callData->key_derivation->schemas->size;
+ if (schemaCount == 0U || schemaCount > MAX_KEY_DERIVATION_SCHEMAS) {
+ return NULL;
+ }
+
bool enable = IsPreviousLockScreenEnable();
SetLockScreen(false);
CSliceFFI_ExtendedPublicKey keys;
@@ -545,9 +593,9 @@ static UREncodeResult *ModelGenerateSyncUR(void)
int seedLen = isSlip39 ? GetCurrentAccountEntropyLen() : sizeof(seed) ;
GetAccountSeed(GetCurrentAccountIndex(), seed, password);
- ExtendedPublicKey xpubs[24];
- SimpleResponse_c_char *pubkey[24];
- for (size_t i = 0; i < g_callData->key_derivation->schemas->size; i++) {
+ ExtendedPublicKey xpubs[MAX_KEY_DERIVATION_SCHEMAS] = {0};
+ SimpleResponse_c_char *pubkey[MAX_KEY_DERIVATION_SCHEMAS] = {0};
+ for (size_t i = 0; i < schemaCount; i++) {
uint8_t derivationType = GetDerivationTypeByCurveAndDeriveAlgo(g_callData->key_derivation->schemas->data[i].curve, g_callData->key_derivation->schemas->data[i].algo);
char *path = g_callData->key_derivation->schemas->data[i].key_path;
switch (derivationType) {
@@ -594,36 +642,55 @@ static UREncodeResult *ModelGenerateSyncUR(void)
default:
break;
}
+ if (pubkey[i] == NULL || pubkey[i]->data == NULL) {
+ for (size_t j = 0; j <= i; j++) {
+ if (pubkey[j] != NULL) {
+ free_simple_response_c_char(pubkey[j]);
+ }
+ }
+ memset_s(seed, sizeof(seed), 0, sizeof(seed));
+ SetLockScreen(enable);
+ return NULL;
+ }
xpubs[i].path = path;
xpubs[i].xpub = pubkey[i]->data;
}
keys.data = xpubs;
- keys.size = g_callData->key_derivation->schemas->size;
+ keys.size = schemaCount;
uint8_t mfp[4] = {0};
GetMasterFingerPrint(mfp);
// clean the cache after use
if (!g_isUsb) {
ClearSecretCache();
}
Ptr_UREncodeResult urResult = generate_key_derivation_ur(mfp, 4, &keys, firmwareVersion);
- for (size_t i = 0; i < g_callData->key_derivation->schemas->size; i++) {
+ for (size_t i = 0; i < schemaCount; i++) {
if (pubkey[i] != NULL) {
free_simple_response_c_char(pubkey[i]);
}
}
+ memset_s(seed, sizeof(seed), 0, sizeof(seed));
SetLockScreen(enable);
return urResult;
}
#ifdef WEB3_VERSION
- ExtendedPublicKey xpubs[24];
- for (size_t i = 0; i < g_callData->key_derivation->schemas->size; i++) {
+ ExtendedPublicKey xpubs[MAX_KEY_DERIVATION_SCHEMAS] = {0};
+ for (size_t i = 0; i < schemaCount; i++) {
KeyDerivationSchema schema = g_callData->key_derivation->schemas->data[i];
+ if (schema.key_path == NULL) {
+ SetLockScreen(enable);
+ return NULL;
+ }
char* xpub = GetCurrentAccountPublicKey(GetXPubIndexByPath(schema.key_path));
+ if (xpub == NULL) {
+ SetLockScreen(enable);
+ return NULL;
+ }
xpubs[i].path = schema.key_path;
xpubs[i].xpub = xpub;
}
keys.data = xpubs;
- keys.size = g_callData->key_derivation->schemas->size;
+ keys.size = schemaCount;
uint8_t mfp[4] = {0};
GetMasterFingerPrint(mfp);
// print keys
@@ -673,7 +740,7 @@ static void GuiCreateHardwareCallApproveWidget(lv_obj_t *parent)
lv_obj_align(cont, LV_ALIGN_TOP_LEFT, 0, 102 * i);
lv_obj_set_style_bg_opa(cont, LV_OPA_0, LV_PART_MAIN);
char title[BUFFER_SIZE_32] = {0};
- sprintf(title, "%s-%d", _("account_head"), i);
+ snprintf(title, sizeof(title), "%s-%u", _("account_head"), (unsigned int)i);
label = GuiCreateIllustrateLabel(cont, title);
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, 16);
char path[BUFFER_SIZE_64] = {0};
@@ -740,7 +807,7 @@ static void GuiCreateApproveWidget(lv_obj_t *parent)
lv_obj_align(cont, LV_ALIGN_TOP_LEFT, 0, 102 * i);
lv_obj_set_style_bg_opa(cont, LV_OPA_0, LV_PART_MAIN);
char title[BUFFER_SIZE_32] = {0};
- sprintf(title, "%s-%d", _("account_head"), i);
+ snprintf(title, sizeof(title), "%s-%u", _("account_head"), (unsigned int)i);
label = GuiCreateIllustrateLabel(cont, title);
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, 16);
char path[BUFFER_SIZE_64] = {0};
@@ -894,6 +961,17 @@ void GuiKeyDeriveUsbPullout(void)
void HiddenKeyboardAndShowAnimateQR()
{
+ HardwareCallResult_t checkResult = CheckHardwareCallRequestIsLegal();
+ if (!checkResult.isLegal) {
+ if (g_isUsb) {
+ const char *message = checkResult.message != NULL ? checkResult.message : "Invalid hardware call parameters";
+ HandleURResultViaUSBAsyncFunc(message, strlen(message), GetCurrentUSParsingRequestID(), PRS_PARSING_ERROR);
+ } else {
+ GuiCreateHardwareCallInvaildParamHintbox(checkResult.title, checkResult.message);
+ }
+ return;
+ }
+
// close password keyboard
if (g_isUsb) {
if (g_keyboardWidget != NULL) {
### src/ui/gui_widgets/multi/web3/gui_eth_batch_tx_widgets.c
@@ -92,7 +92,6 @@ static void GuiEthBatchTxNavBarRefresh();
static void GuiRenderCurrentTransaction(bool showSwapHint, bool showSignSlider);
static void GuiRenderTransactionFrame(lv_obj_t *parent);
static void GuiRenderBottomBtn(lv_obj_t *parent, bool showSignSlider);
-static const lv_font_t *GetEthBatchAmountFont(const char *value);
static bool HandleCurrentTransaction(uint32_t index);
static void HandleCurrentTransactionParseFail(uint32_t errorCode, const char *errorMessage);
@@ -204,7 +203,10 @@ static void HandleClickAddressChecker(lv_event_t *e)
if (code == LV_EVENT_CLICKED) {
char *address = lv_event_get_user_data(e);
char *text = malloc(BUFFER_SIZE_128);
- sprintf(text, "https://etherscan.io/address/%s", address);
+ if (text == NULL) {
+ return;
+ }
+ snprintf(text, BUFFER_SIZE_128, "https://etherscan.io/address/%s", address);
GuiQRCodeHintBoxOpen(text, _("Check the Address"), text);
}
}
@@ -521,10 +523,13 @@ static void GuiEthBatchTxNavBarInit()
static void GuiEthBatchTxNavBarRefresh()
{
char* text = malloc(BUFFER_SIZE_128);
+ if (text == NULL) {
+ return;
+ }
if (g_txCount > 1) {
- sprintf(text, "%s (%d/%d)", _("confirm_transaction"), g_currentTxIndex + 1, g_txCount);
+ snprintf(text, BUFFER_SIZE_128, "%s (%d/%d)", _("confirm_transaction"), g_currentTxIndex + 1, g_txCount);
} else {
- sprintf(text, "%s", _("confirm_transaction"));
+ snprintf(text, BUFFER_SIZE_128, "%s", _("confirm_transaction"));
}
SetCoinWallet(g_pageWidget->navBarWidget, CHAIN_ETH, text);
if (g_currentTxIndex == 0) {
@@ -555,18 +560,6 @@ static bool FormatAssetAmount(char *output, size_t outputSize, const char *amoun
return true;
}
-static const lv_font_t *GetEthBatchAmountFont(const char *value)
-{
- size_t length = strlen(value);
- if (length <= 24) {
- return g_defLittleTitleFont;
- }
- if (length <= 40) {
- return g_defTextFont;
- }
- return g_defIllustrateFont;
-}
-
// GUI Impelementation Part
static lv_obj_t* GuiRenderSwapSummary(lv_obj_t *parent, const char* from_asset, const char* from_amount, const char* to_asset)
{
@@ -806,7 +799,19 @@ static void GuiRenderGeneralOverview(lv_obj_t *parent)
lv_obj_t *last_view = NULL;
const char *valueTitle = strlen(g_currentTransaction->detail->input) > 0 ? _("Native Transfer") : _("Value");
- last_view = CreateTransactionOvewviewCard(parent, valueTitle, g_currentTransaction->overview->value, _("Max Txn Fee"), g_currentTransaction->overview->max_txn_fee);
+ char nativeValue[ETH_BATCH_ASSET_AMOUNT_BUFFER_SIZE] = {0};
+ char maxTxnFee[ETH_BATCH_ASSET_AMOUNT_BUFFER_SIZE] = {0};
+ bool nativeValueFormatted = FormatAssetAmount(
+ nativeValue, sizeof(nativeValue),
+ g_currentTransaction->overview->value, g_currentNetwork.symbol);
+ bool maxTxnFeeFormatted = FormatAssetAmount(
+ maxTxnFee, sizeof(maxTxnFee),
+ g_currentTransaction->overview->max_txn_fee, g_currentNetwork.symbol);
+ last_view = CreateTransactionOvewviewCard(
+ parent, valueTitle,
+ nativeValueFormatted ? nativeValue : _("Invalid Amount"),
+ _("Max Txn Fee"),
+ maxTxnFeeFormatted ? maxTxnFee : _("Invalid Amount"));
last_view = CreateTransactionItemView(parent, _("Network"), g_currentNetwork.name, last_view);
@@ -850,7 +855,9 @@ static lv_obj_t *GuiRenderDetailTransactionInfoCard(lv_obj_t *parent, lv_obj_t *
char value[ETH_BATCH_ASSET_AMOUNT_BUFFER_SIZE] = {0};
bool formatted = FormatAssetAmount(value, sizeof(value), g_currentTransaction->detail->value, g_currentNetwork.symbol);
const char *displayValue = formatted ? value : _("Invalid Amount");
- valueLabel = GuiCreateLabelWithFont(container, displayValue, GetEthBatchAmountFont(displayValue));
+ // Details values use the regular illustrate font. The larger adaptive
+ // amount fonts are reserved for overview emphasis cards.
+ valueLabel = GuiCreateIllustrateLabel(container, displayValue);
lv_obj_set_style_text_color(valueLabel, ORANGE_COLOR, LV_PART_MAIN);
lv_obj_update_layout(titleLabel);
lv_obj_update_layout(valueLabel);
@@ -872,7 +879,12 @@ static lv_obj_t *GuiRenderDetailTransactionInfoCard(lv_obj_t *parent, lv_obj_t *
lv_obj_set_style_text_opa(titleLabel, LV_OPA_64, LV_PART_MAIN);
lv_obj_align(titleLabel, LV_ALIGN_TOP_LEFT, 24, height);
- valueLabel = GuiCreateIllustrateLabel(container, g_currentTransaction->detail->max_txn_fee);
+ char maxTxnFee[ETH_BATCH_ASSET_AMOUNT_BUFFER_SIZE] = {0};
+ bool maxTxnFeeFormatted = FormatAssetAmount(
+ maxTxnFee, sizeof(maxTxnFee),
+ g_currentTransaction->detail->max_txn_fee, g_currentNetwork.symbol);
+ valueLabel = GuiCreateIllustrateLabel(
+ container, maxTxnFeeFormatted ? maxTxnFee : _("Invalid Amount"));
lv_obj_align_to(valueLabel, titleLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
height += 30 + 8;
@@ -883,16 +895,22 @@ static lv_obj_t *GuiRenderDetailTransactionInfoCard(lv_obj_t *parent, lv_obj_t *
height += 30 + 8;
if (g_currentTransaction->detail->max_priority != NULL) {
- titleLabel = GuiCreateIllustrateLabel(container, _("Max Priority"));
+ titleLabel = GuiCreateIllustrateLabel(container, _("Max Priority Fee"));
lv_obj_set_style_text_opa(titleLabel, LV_OPA_64, LV_PART_MAIN);
lv_obj_align(titleLabel, LV_ALIGN_TOP_LEFT, 24, height);
- valueLabel = GuiCreateIllustrateLabel(container, g_currentTransaction->detail->max_priority);
+ char maxPriorityFee[ETH_BATCH_ASSET_AMOUNT_BUFFER_SIZE] = {0};
+ bool maxPriorityFeeFormatted = FormatAssetAmount(
+ maxPriorityFee, sizeof(maxPriorityFee),
+ g_currentTransaction->detail->max_priority, g_currentNetwork.symbol);
+ valueLabel = GuiCreateIllustrateLabel(
+ container,
+ maxPriorityFeeFormatted ? maxPriorityFee : _("Invalid Amount"));
lv_obj_align_to(valueLabel, titleLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
height += 30 + 8;
- titleLabel = GuiCreateIllustrateLabel(container, " \xE2\x80\xA2 Max Priority Fee Price * Gas Limit");
+ titleLabel = GuiCreateIllustrateLabel(container, " · Max Priority Fee Price * Gas Limit");
lv_obj_align(titleLabel, LV_ALIGN_TOP_LEFT, 24, height);
height += 30 + 8;
@@ -984,14 +1002,17 @@ static lv_obj_t *GuiRenderDetailContractData(lv_obj_t *parent, lv_obj_t *last_vi
bool asset_is_eth = strcmp(param.value, "0x0000000000000000000000000000000000000000") == 0;
Erc20Contract_t *erc20Contract = FindErc20Contract(param.value);
char* text = malloc(BUFFER_SIZE_64);
+ if (text == NULL) {
+ continue;
+ }
if (erc20Contract != NULL) {
- sprintf(text, "%s (#1BE0C6 %s#)", param.value, erc20Contract->symbol);
+ snprintf(text, BUFFER_SIZE_64, "%s (#1BE0C6 %s#)", param.value, erc20Contract->symbol);
showAddressChecker = true;
} else if (asset_is_eth) {
- sprintf(text, "%s (#F5870A %s#)", param.value, g_currentNetwork.symbol);
+ snprintf(text, BUFFER_SIZE_64, "%s (#F5870A %s#)", param.value, g_currentNetwork.symbol);
showAddressChecker = false;
} else {
- sprintf(text, "%s", param.value);
+ snprintf(text, BUFFER_SIZE_64, "%s", param.value);
showAddressChecker = true;
}
label = GuiCreateIllustrateLabel(container, text);
### src/ui/lv_i18n/get_font_contain.py
@@ -2,9 +2,11 @@
# !/usr/bin/python
import argparse
-import pandas as pd
+import csv
import re
import os
+import shutil
+import subprocess
from pathlib import Path
@@ -36,32 +38,61 @@ def update_font_properties(file_path, font_size):
file.write(content)
print(f"Updated {file_path} for font_size {font_size} with line_height {line_height} and base_line {base_line}.")
-def build_lv_font_conv_command(bpp, size, font, symbols, output_file):
- command = "lv_font_conv"
- command += f" --bpp {bpp}"
- command += f" --size {size}"
- command += " --no-compress"
- command += f" --font {font}"
- command += f" --symbols {symbols}"
- command += " --format lvgl"
- command += f" -o {output_file}"
+def find_lv_font_conv():
+ configured = os.environ.get("LV_FONT_CONV")
+ if configured:
+ return configured
+
+ executable = shutil.which("lv_font_conv")
+ if executable:
+ return executable
+
+ nvm_root = Path.home() / ".nvm" / "versions" / "node"
+ candidates = sorted(nvm_root.glob("*/bin/lv_font_conv"), reverse=True)
+ if candidates:
+ return str(candidates[0])
+
+ raise FileNotFoundError(
+ "lv_font_conv was not found; install it or set LV_FONT_CONV"
+ )
- return command
+
+def build_lv_font_conv_command(bpp, size, font, symbols, output_file):
+ return [
+ find_lv_font_conv(),
+ "--bpp", str(bpp),
+ "--size", str(size),
+ "--no-compress",
+ "--font", font,
+ "--symbols", symbols,
+ "--format", "lvgl",
+ "-o", output_file,
+ ]
def parse_command_line(command_line="cmd_tool --bpp 8 --size 12 --font Arial.ttf --symbols ABCD --format xyz", font_size=None, language=None, unique_characters=None, label=None):
+ symbols = re.search(r"--symbols (.+?) --format", command_line).group(1)
options = {
'bpp': re.search(r"--bpp (\d+)", command_line).group(1),
'size': int(re.search(r"--size (\d+)", command_line).group(1)),
'font': re.search(r"--font ([\w-]+\.ttf)", command_line).group(1),
- 'symbols': re.search(r"--symbols (.+?) --format", command_line).group(1)
+ # Older generated files contain an unmatched quote plus padding spaces
+ # because the command used to be assembled through zsh.
+ 'symbols': symbols.strip().strip('"')
}
if font_size in [20, 24]:
bpp = 2
elif font_size in [28, 36]:
bpp = 1
- if options['symbols'] != unique_characters:
+ output_file = "../gui_assets/font/" + language + "/" + label
+ try:
+ with open(output_file, 'r', encoding='utf-8') as generated_font:
+ has_space_glyph = '/* U+0020 " " */' in generated_font.read()
+ except FileNotFoundError:
+ has_space_glyph = False
+
+ if options['symbols'] != unique_characters or not has_space_glyph:
font_mapping = {
'cn': 'NotoSansSC-Regular.ttf',
'ko': 'NotoSansKR-Regular.ttf',
@@ -70,16 +101,25 @@ def parse_command_line(command_line="cmd_tool --bpp 8 --size 12 --font Arial.ttf
'de': 'NotoSans-Regular.ttf',
'ja': 'NotoSansJP-Regular.ttf',
}
- if os.environ.get('SHELL') == '/bin/zsh':
- unique_characters = '\"' + '\\\"' + unique_characters + " " + "\""
- unique_characters = unique_characters.replace("`","\\`")
- else:
- unique_characters = '\"\"\"' + unique_characters + " " +'\"'
- build_command = build_lv_font_conv_command(bpp, font_size, font_mapping[language], unique_characters, "../gui_assets/font/" + language + "/" + label)
- cmd_result = os.system(build_command)
- if cmd_result != 0:
- exit(cmd_result)
- update_font_properties("../gui_assets/font/" + language + "/" + label, font_size)
+ # Space is intentionally removed from unique_characters below so it does
+ # not affect the symbols comparison. It still needs to be included in
+ # every generated font: LVGL does not automatically fall back to another
+ # font for U+0020, and a missing space is rendered as the missing-glyph
+ # box between translated words.
+ symbols_for_generation = unique_characters + " "
+ build_command = build_lv_font_conv_command(
+ bpp,
+ font_size,
+ font_mapping[language],
+ symbols_for_generation,
+ output_file,
+ )
+ cmd_result = subprocess.run(build_command, check=False)
+ if cmd_result.returncode != 0:
+ raise RuntimeError(
+ f"lv_font_conv failed with exit code {cmd_result.returncode}"
+ )
+ update_font_properties(output_file, font_size)
# raise ValueError("Unique characters do not match the symbols provided in the command line.")
return options, language
@@ -92,8 +132,14 @@ def extract_unique_characters(df, font_size, column):
36: "·QWERTYUIOPASDFGHJKLZXCVBNM,/:\";'[]<>~!@#$%^&*()_+=0987654321·qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM[]{}#%^*+=_\\|~<>€£¥·-/:;()$&`.?!'@",
}
unique_chars = set(additional_chars.get(font_size, additional_chars[28]))
- subset = df[df['font'] == font_size][column].dropna()
- subset.apply(lambda x: unique_chars.update(set(x)))
+ for row in df:
+ try:
+ row_font_size = int(row['font'])
+ except (KeyError, TypeError, ValueError):
+ continue
+ value = row.get(column)
+ if row_font_size == font_size and value:
+ unique_chars.update(set(value))
text = ''.join(sorted(unique_chars))
text = text.replace('\"', '')
text = text.replace('\n', '')
@@ -103,7 +149,8 @@ def extract_unique_characters(df, font_size, column):
def main():
for language in ['cn', 'ko', 'ru', 'es', 'de', 'ja']:
try:
- df = pd.read_csv('data.csv')
+ with open('data.csv', newline='', encoding='utf-8') as csv_file:
+ df = list(csv.DictReader(csv_file))
font_labels = {
20: f"{language}Illustrate",
24: f"{language}Text",
@@ -134,4 +181,4 @@ def main():
print("An error occurred:", e)
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
### src/ui/lv_i18n/lv_i18n.c
[binary or diff unavailable]
### src/utils/assert.c
@@ -24,7 +24,8 @@ LV_FONT_DECLARE(openSans_20);
void ShowAssert(const char *file, uint32_t len)
{
char assertStr[BUFFER_SIZE_256];
- PrintOnLcd(&openSans_20, 0xFFFF, "assert,file=%s\nline=%d\n\n", file, len);
+ snprintf_s(assertStr, BUFFER_SIZE_256, "assert,file=%s\nline=%d\n\n", file, len);
+ PrintOnLcd(&openSans_20, 0xFFFF, assertStr);
PrintErrorInfoOnLcd();
snprintf_s(assertStr, BUFFER_SIZE_256, "assert,file=%s,line=%d", file, len);
Gd25FlashWriteBufferNoMutex(SPI_FLASH_ADDR_ERR_INFO, (uint8_t *)assertStr, strnlen_s(assertStr, sizeof(assertStr) - 1) + 1);
### src/utils/log/log.c
@@ -96,7 +96,7 @@ void WriteLogFormat(uint32_t event, const char *format, ...)
va_list argList;
va_start(argList, format);
//printf("WriteLogFormat,event=%d\r\n", event);
- vsprintf(str, format, argList);
+ vsnprintf(str, LOG_MAX_STRING_LEN, format, argList);
LogData_t logData = {0};
logData.event = event;
logData.dataType = 1;
### src/utils/log/log_print.c
@@ -1,12 +1,15 @@
-#include "log_print.h"
-#include "stdio.h"
-#include "librust_c.h"
-
-#ifdef RUST_MEMORY_DEBUG
-#include "user_memory.h"
-#include "assert.h"
-#include "string.h"
-#include "safe_str_lib.h"
+#include "log_print.h"
+#include "stdio.h"
+#include "librust_c.h"
+
+#ifndef COMPILE_SIMULATOR
+#include "safe_str_lib.h"
+#endif
+
+#ifdef RUST_MEMORY_DEBUG
+#include "user_memory.h"
+#include "assert.h"
+#include "string.h"
#define MEM_DEBUG_BUF_SIZE 128
@@ -177,30 +180,32 @@ void LogRustPanic(char* panic_info)
#include "presetting.h"
#include "version.h"
#include "hardware_version.h"
+#include "define.h"
LV_FONT_DECLARE(openSans_20);
void LogRustPanic(char* panic_info)
{
- NVIC_SystemReset();
+ // Show only a fixed, user-facing error message on the LCD.
PrintOnLcd(&openSans_20, 0xFFFF, "The error was caused by a failed data request.\nYour assets remain safe.\n");
PrintErrorInfoOnLcd();
- uint32_t c = 0x666666;
- uint16_t color = (uint16_t)(((c & 0xF80000) >> 16) | ((c & 0xFC00) >> 13) | ((c & 0x1C00) << 3) | ((c & 0xF8) << 5));
- PrintOnLcd(&openSans_20, color, "Rust Panic: %s\r\n", panic_info);
- while (1);
+ NVIC_SystemReset();
}
void PrintErrorInfoOnLcd(void)
{
char serialNumber[SERIAL_NUMBER_MAX_LEN];
+ char line[BUFFER_SIZE_128];
PrintOnLcd(&openSans_20, 0xFFFF, "Request failed. Restart by long-pressing power\nbutton for 12 secs.\n");
PrintOnLcd(&openSans_20, 0xFFFF, "If issue persists, please contact\n");
PrintOnLcd(&openSans_20, 0x1927, "support@Keyst.one\n");
GetSerialNumber(serialNumber);
- PrintOnLcd(&openSans_20, 0xFFFF, "Serial No.%s\n", serialNumber);
- PrintOnLcd(&openSans_20, 0xFFFF, "Software:%s\n", GetSoftwareVersionString());
- PrintOnLcd(&openSans_20, 0xFFFF, "Hardware:%s\n", GetHardwareVersionString());
+ snprintf_s(line, sizeof(line), "Serial No.%s\n", serialNumber);
+ PrintOnLcd(&openSans_20, 0xFFFF, line);
+ snprintf_s(line, sizeof(line), "Software:%s\n", GetSoftwareVersionString());
+ PrintOnLcd(&openSans_20, 0xFFFF, line);
+ snprintf_s(line, sizeof(line), "Hardware:%s\n", GetHardwareVersionString());
+ PrintOnLcd(&openSans_20, 0xFFFF, line);
}
#endif
### src/webusb_protocol/general/eapdu_services/service_resolve_ur.c
@@ -27,24 +27,45 @@ static uint16_t g_requestID = REQUEST_ID_IDLE;
static void BasicHandlerFunc(const void *data, uint32_t data_len, uint16_t requestID, StatusEnum status)
{
- EAPDUResponsePayload_t *payload = (EAPDUResponsePayload_t *)SRAM_MALLOC(sizeof(EAPDUResponsePayload_t));
+ EAPDUResponsePayload_t *payload = NULL;
+ cJSON *root = NULL;
+ char *json_str = NULL;
+ (void)data_len;
+
+ payload = (EAPDUResponsePayload_t *)SRAM_MALLOC(sizeof(EAPDUResponsePayload_t));
+ if (payload == NULL) {
+ goto cleanup;
+ }
- cJSON *root = cJSON_CreateObject();
- cJSON_AddStringToObject(root, "payload", (char *)data);
- char *json_str = cJSON_PrintBuffered(root, BUFFER_SIZE_1024 * 4, false);
- cJSON_Delete(root);
+ root = cJSON_CreateObject();
+ if (root == NULL ||
+ cJSON_AddStringToObject(root, "payload", data != NULL ? (char *)data : "") == NULL) {
+ goto cleanup;
+ }
+ json_str = cJSON_PrintBuffered(root, BUFFER_SIZE_1024 * 4, false);
+ if (json_str == NULL) {
+ goto cleanup;
+ }
payload->data = (uint8_t *)json_str;
- payload->dataLen = strlen((char *)payload->data);
+ payload->dataLen = strlen(json_str);
payload->status = status;
payload->cla = EAPDU_PROTOCOL_HEADER;
payload->commandType = CMD_RESOLVE_UR;
payload->requestID = requestID;
SendEApduResponse(payload);
- EXT_FREE(json_str);
+cleanup:
+ if (root != NULL) {
+ cJSON_Delete(root);
+ }
+ if (json_str != NULL) {
+ EXT_FREE(json_str);
+ }
g_requestID = REQUEST_ID_IDLE;
- SRAM_FREE(payload);
+ if (payload != NULL) {
+ SRAM_FREE(payload);
+ }
};
void HandleURResultViaUSBFunc(const void *data, uint32_t data_len, uint16_t requestID, StatusEnum status)
@@ -169,6 +190,7 @@ static void HandleHardwareCall(struct URParseResult *urResult)
const char *data = "Export address is just allowed on specific pages";
HandleURResultViaUSBFunc(data, strlen(data), g_requestID, PRS_PARSING_DISALLOWED);
+ free_ur_parse_result(urResult);
g_requestID = REQUEST_ID_IDLE;
}
@@ -192,11 +214,12 @@ static bool HandleNormalCall(void)
static void HandleCheckResult(PtrT_TransactionCheckResult checkResult, UrViewType_t urViewType)
{
- if (checkResult != NULL && checkResult->error_code == 0) {
+ if (checkResult == NULL) {
+ GotoFailPage(PRS_PARSING_ERROR, "Transaction check failed");
+ } else if (checkResult->error_code == 0) {
PubValueMsg(UI_MSG_PREPARE_RECEIVE_UR_USB, urViewType.viewType);
- } else if (checkResult != NULL &&
- (checkResult->error_code == MasterFingerprintMismatch ||
- checkResult->error_code == BitcoinNoMyInputs)) {
+ } else if (checkResult->error_code == MasterFingerprintMismatch ||
+ checkResult->error_code == BitcoinNoMyInputs) {
const char *data = _("usb_transport_mismatched_wallet_desc");
GotoFailPage(PRS_PARSING_MISMATCHED_WALLET, data);
} else {
@@ -218,6 +241,7 @@ void ProcessURService(EAPDURequestPayload_t *payload)
urResult = parse_ur((char *)payload->data);
if (urResult->error_code != 0) {
HandleURResultViaUSBFunc(urResult->error_message, strlen(urResult->error_message), g_requestID, PRS_PARSING_ERROR);
+ free_ur_parse_result(urResult);
break;
}
@@ -231,15 +255,18 @@ void ProcessURService(EAPDURequestPayload_t *payload)
break;
}
if (!CheckURAcceptable()) {
+ free_ur_parse_result(urResult);
break;
}
if (!HandleNormalCall()) {
+ free_ur_parse_result(urResult);
break;
}
if (!CheckViewTypeIsAllow(urViewType.viewType)) {
const char *data = "this view type is not supported";
HandleURResultViaUSBFunc(data, strlen(data), g_requestID, RSP_FAILURE_CODE);
+ free_ur_parse_result(urResult);
break;
}
### src/webusb_protocol/general/eapdu_services/service_trans_usb_pubkey.c
@@ -11,6 +11,7 @@
#define COIN_TYPE_SIZE 4
#define SOLANA_COIN_TYPE 501U
+#define SOLANA_MAX_DERIVATION_DEPTH 4U
static bool ParseCoinType(const uint8_t *data, uint32_t len, uint32_t *coinType)
{
@@ -33,9 +34,12 @@ static bool ParseSolDerivationPath(const uint8_t *data, uint32_t len, char *path
}
uint8_t depth = data[0];
+ if (depth == 0 || depth > SOLANA_MAX_DERIVATION_DEPTH) {
+ return false;
+ }
uint32_t expectedLen = 1 + (depth * 4);
- if (len < expectedLen) {
+ if (len != expectedLen) {
return false;
}
@@ -55,10 +59,16 @@ static bool ParseSolDerivationPath(const uint8_t *data, uint32_t len, char *path
}
component &= 0x7FFFFFFF;
- if (strlen(path) == 0) {
- snprintf(path, pathSize, "%u'", component);
+ size_t used = strlen(path);
+ size_t available = pathSize - used;
+ int written;
+ if (used == 0) {
+ written = snprintf(path, pathSize, "%u'", component);
} else {
- snprintf(path + strlen(path), pathSize - strlen(path), "/%u'", component);
+ written = snprintf(path + used, available, "/%u'", component);
+ }
+ if (written < 0 || (size_t)written >= available) {
+ return false;
}
}
### ui_simulator/simulator_model.c
@@ -23,7 +23,7 @@ bool g_reboot = false;
bool g_otpProtect = false;
// Comment out this macro if you need to retrieve data from the file
-// #define GET_QR_DATA_FROM_SCREEN
+#define GET_QR_DATA_FROM_SCREEN
void OTP_PowerOn(void)
{
@@ -70,10 +70,11 @@ void NftLockDecodeTouchQuit()
int32_t GetUpdatePubKey(uint8_t *pubKey)
{
- sprintf(pubKey, "%02x", 0x4);
+ pubKey[0] = 0x04;
for (int i = 1; i < 65; i++) {
- sprintf(&pubKey[i], "%02x", i);
+ pubKey[i] = (uint8_t)i;
}
+ return 0;
}
void TrngGet(void *buf, uint32_t len)Why this scored 59/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.