Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions Resources/iOSEinstein Storyboards-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@
<string>iOSEinstein</string>
<key>CFBundleExecutable</key>
<string>iOSEinstein</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>Newton Package Data</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.newton-inc.pkg</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>Newton ROM Image</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.newton-inc.rom</string>
</array>
</dict>
</array>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
Expand All @@ -31,8 +54,12 @@
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>UISupportsDocumentBrowser</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>
<key>UIMainStoryboardFile</key>
Expand All @@ -48,5 +75,49 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Newton Package Data</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>com.newton-inc.pkg</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>pkg</string>
<string>PKG</string>
<string>newtonpkg</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Newton ROM Image</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>com.newton-inc.rom</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>rom</string>
<string>ROM</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
4 changes: 4 additions & 0 deletions Resources/iOSEinstein-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@
<string>MainWindow</string>
<key>NSMainNibFile~ipad</key>
<string>MainWindow_iPad</string>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>UISupportsDocumentBrowser</key>
<true/>
<key>UIStatusBarHidden</key>
<false/>
</dict>
Expand Down
83 changes: 83 additions & 0 deletions app/iEinstein/Classes/iEinsteinAppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(N
[window makeKeyAndVisible];
#endif

// Check if app was launched by opening a file
NSURL *url = launchOptions[UIApplicationLaunchOptionsURLKey];
if (url) {
fprintf(stderr, "App launched with URL: %s\n", [[url absoluteString] UTF8String]);
// Handle the file immediately before emulator initialization
[self handleIncomingFile:url];
}

NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
bool clearFlash = [(NSNumber*) [prefs objectForKey:@"clear_flash_ram"] boolValue];
if (clearFlash)
Expand All @@ -88,13 +96,88 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(N
return YES;
}

- (void)handleIncomingFile:(NSURL *)url
{
if (![url.scheme isEqualToString:@"file"]) {
return;
}

[url startAccessingSecurityScopedResource];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *srcPath = url.path;
NSString *filename = [srcPath lastPathComponent];
NSString *dstPath = [documentsDirectory stringByAppendingPathComponent:filename];
NSError *error = nil;

// Determine file type
NSString *fileExtension = [[filename pathExtension] lowercaseString];
BOOL isROMFile = [fileExtension isEqualToString:@"rom"];
BOOL isPkgFile = [fileExtension isEqualToString:@"pkg"] || [fileExtension isEqualToString:@"newtonpkg"];

if(![srcPath isEqualToString:dstPath]) {
if ([[NSFileManager defaultManager] fileExistsAtPath:dstPath]) {
[[NSFileManager defaultManager] removeItemAtPath:dstPath error:&error];
if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
else{
NSLog(@"File removed.");
}
}
[[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:dstPath error:&error];
}

if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
Comment on lines +119 to +134
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Reset error before copyItemAtPath to avoid logging stale errors.

If removeItemAtPath: fails (setting error), then copyItemAtPath: succeeds (not touching error), the stale error will still be logged at line 132-134, incorrectly suggesting the copy failed.

 		if(error){
 			NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
 		}
 		else{
 			NSLog(@"File removed.");
 		}
+		error = nil;
 	}
 	[[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:dstPath error:&error];
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if(![srcPath isEqualToString:dstPath]) {
if ([[NSFileManager defaultManager] fileExistsAtPath:dstPath]) {
[[NSFileManager defaultManager] removeItemAtPath:dstPath error:&error];
if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
else{
NSLog(@"File removed.");
}
}
[[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:dstPath error:&error];
}
if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
if(![srcPath isEqualToString:dstPath]) {
if ([[NSFileManager defaultManager] fileExistsAtPath:dstPath]) {
[[NSFileManager defaultManager] removeItemAtPath:dstPath error:&error];
if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
else{
NSLog(@"File removed.");
}
error = nil;
}
[[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:dstPath error:&error];
}
if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
🤖 Prompt for AI Agents
In app/iEinstein/Classes/iEinsteinAppDelegate.mm around lines 119 to 134, the
NSError *error value from removeItemAtPath: can remain set and later be
misinterpreted after copyItemAtPath:—reset the error to nil before calling
copyItemAtPath: (or declare and use a separate NSError variable for the copy
call) and check/log each call's error immediately after that specific API
returns so stale errors are never logged for a subsequent operation.

else if (isPkgFile) {
NSLog(@"Pkg File copied.");
[viewController installNewPackages];

// Remove the pkg file after installation
[[NSFileManager defaultManager] removeItemAtPath:dstPath error:&error];
if(error){
NSLog(@"%@ %ld %@",[error domain],(long)[error code],[[error userInfo] description]);
}
else{
NSLog(@"Installed Pkg file removed.");
}
}
else if (isROMFile) {
NSLog(@"ROM File copied to Documents directory: %@", filename);
// Dismiss the "missing ROM" action sheet if it's showing and restart the emulator
[viewController checkForROMImage];
}

[url stopAccessingSecurityScopedResource];
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
if ([url.scheme isEqualToString:@"file"]) {
[self handleIncomingFile:url];
return YES;
}
else {
[[UIApplication sharedApplication] openURL:url options:options completionHandler:nil];
return YES;
}
return NO;
}
Comment on lines +157 to +168
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix unreachable code and reconsider URL forwarding logic.

Line 167 (return NO) is unreachable since both branches return YES. Additionally, forwarding unknown URL schemes to openURL: in the else branch may cause unexpected behavior or infinite loops if the system routes it back.

 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
 {
 	if ([url.scheme isEqualToString:@"file"]) {
 		[self handleIncomingFile:url];
 		return YES;
 	}
-	else {
-		[[UIApplication sharedApplication] openURL:url options:options completionHandler:nil];
-		return YES;
-	}
-	return NO;
+	return NO;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
if ([url.scheme isEqualToString:@"file"]) {
[self handleIncomingFile:url];
return YES;
}
else {
[[UIApplication sharedApplication] openURL:url options:options completionHandler:nil];
return YES;
}
return NO;
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
if ([url.scheme isEqualToString:@"file"]) {
[self handleIncomingFile:url];
return YES;
}
return NO;
}


- (void)applicationWillResignActive:(UIApplication*)application
{
[viewController stopEmulator];
}

- (void)applicationDidBecomeActive:(UIApplication*)application
{
// Check if ROM was added while app was in background
// This will dismiss the missing ROM sheet if ROM is now available
[viewController checkForROMImage];
Comment on lines 175 to +179
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the checkForROMImage method implementation
fd "\.mm$|\.h$" | xargs rg -A 15 "checkForROMImage" --color=never | head -100

Repository: pguyot/Einstein

Length of output: 5923


🏁 Script executed:

#!/bin/bash
# Find the loadROMImage method
fd "\.mm$|\.h$" | xargs rg -A 10 "loadROMImage" --color=never | head -100

Repository: pguyot/Einstein

Length of output: 3724


🏁 Script executed:

#!/bin/bash
# Check how viewController is initialized in the delegate
rg -A 20 "applicationDidFinishLaunching|viewController\s*=" app/iEinstein/Classes/iEinsteinAppDelegate.mm | head -80

Repository: pguyot/Einstein

Length of output: 1591


🏁 Script executed:

#!/bin/bash
# Check the full context around line 175-179
sed -n '160,190p' app/iEinstein/Classes/iEinsteinAppDelegate.mm

Repository: pguyot/Einstein

Length of output: 951


🏁 Script executed:

#!/bin/bash
# Find mLog initialization in iEinsteinViewController
rg "mLog\s*=" app/iEinstein/Classes/iEinsteinViewController.mm | head -20

Repository: pguyot/Einstein

Length of output: 127


🏁 Script executed:

#!/bin/bash
# Find viewDidLoad and init methods in iEinsteinViewController to see initialization order
rg -A 30 "(viewDidLoad|^- \(id\)init)" app/iEinstein/Classes/iEinsteinViewController.mm | head -80

Repository: pguyot/Einstein

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Search for where mLog is declared and any guards around its usage
rg "mLog" app/iEinstein/Classes/iEinsteinViewController.h

Repository: pguyot/Einstein

Length of output: 71


🏁 Script executed:

#!/bin/bash
# Find the context where mLog is initialized with TStdOutLog
rg -B 10 -A 5 "mLog = new TStdOutLog" app/iEinstein/Classes/iEinsteinViewController.mm

Repository: pguyot/Einstein

Length of output: 360


🏁 Script executed:

#!/bin/bash
# Look at the full viewDidLoad and viewWillAppear methods
sed -n '1,500p' app/iEinstein/Classes/iEinsteinViewController.mm | rg -A 40 "viewDidLoad|viewWillAppear"

Repository: pguyot/Einstein

Length of output: 2681


🏁 Script executed:

#!/bin/bash
# Check if there are any nil-safety checks or guards before checkForROMImage call
rg -B 5 "checkForROMImage" app/iEinstein/Classes/iEinsteinAppDelegate.mm

Repository: pguyot/Einstein

Length of output: 504


🏁 Script executed:

#!/bin/bash
# Look for any initialization of viewController besides the storyboard assignment
rg "viewController" app/iEinstein/Classes/iEinsteinAppDelegate.mm | head -30

Repository: pguyot/Einstein

Length of output: 834


Add a nil check before calling checkForROMImage in applicationDidBecomeActive.

While the iOS lifecycle typically ensures viewController and its mLog are initialized before this method runs, the code lacks defensive guards. Consider checking that viewController is non-nil and initialized before proceeding, or add a nil check within loadROMImage to guard mLog access.

🤖 Prompt for AI Agents
In app/iEinstein/Classes/iEinsteinAppDelegate.mm around lines 175 to 179, the
code calls [viewController checkForROMImage] without verifying viewController is
non-nil which can lead to messaging nil-dependent state; add a defensive nil
check before invoking the method (for example, if (viewController) {
[viewController checkForROMImage]; }) or, alternatively, add a nil guard inside
loadROMImage to ensure mLog is valid before use so the call is safe when
viewController or its mLog is not yet initialized.


if (![viewController allResourcesFound])
return;

Expand Down
2 changes: 2 additions & 0 deletions app/iEinstein/Classes/iEinsteinViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class TLog;
TPlatformManager* mPlatformManager;
TLog* mLog;
int lastKnownScreenResolution;
UIAlertView* mMissingROMAlertView;
}

@property (retain, nonatomic) IBOutlet iEinsteinView* einsteinView;
Expand Down Expand Up @@ -95,6 +96,7 @@ class TLog;

- (void)verifyDeleteFlashRAM:(int)withTag;
- (void)explainMissingROM;
- (BOOL)checkForROMImage;
//- (void)openEinsteinMenu;

- (int)allResourcesFound;
Expand Down
Loading