react-native-pdf-jsi 3.3.1 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -6
- package/android/src/main/java/org/wonday/pdf/FileManager.java +2 -0
- package/android/src/main/java/org/wonday/pdf/MemoryMappedCache.java +1 -1
- package/android/src/main/java/org/wonday/pdf/PDFExporter.java +0 -54
- package/android/src/main/java/org/wonday/pdf/PdfManager.java +5 -0
- package/android/src/main/java/org/wonday/pdf/PdfView.java +12 -2
- package/android/src/main/java/org/wonday/pdf/RNPDFJSIPackage.java +50 -0
- package/android/src/main/java/org/wonday/pdf/RNPDFPackage.java +0 -1
- package/fabric/RNPDFPdfNativeComponent.js +8 -3
- package/index.js +148 -23
- package/ios/RNPDFPdf/RNPDFPdfView.h +19 -1
- package/ios/RNPDFPdf/RNPDFPdfView.mm +154 -44
- package/package.json +11 -6
- package/src/PDFJSI.js +29 -4
- package/src/components/AnalyticsPanel.jsx +22 -9
- package/src/managers/AnalyticsManager.js +1 -5
- package/src/managers/BookmarkManager.js +2 -10
- package/src/managers/CacheManager.js +14 -1
- package/src/managers/ExportManager.js +5 -20
- package/src/utils/ErrorHandler.js +0 -11
- package/src/utils/PDFTextExtractor.js +82 -0
- package/android/.gradle/5.6.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/5.6.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/5.6.1/gc.properties +0 -0
- package/android/.gradle/8.5/checksums/checksums.lock +0 -0
- package/android/.gradle/8.5/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.5/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/8.5/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.5/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.5/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.5/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.5/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/src/main/java/org/wonday/pdf/LicenseVerifier.java +0 -311
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PDFTextExtractor - Text Extraction from PDF Files
|
|
3
|
+
*
|
|
4
|
+
* Handles extracting text content from PDF files for export functionality
|
|
5
|
+
*
|
|
6
|
+
* @author Punith M
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* PDFTextExtractor Class
|
|
12
|
+
*/
|
|
13
|
+
class PDFTextExtractor {
|
|
14
|
+
/**
|
|
15
|
+
* Check if text extraction is available
|
|
16
|
+
* @returns {boolean} True if text extraction is available
|
|
17
|
+
*/
|
|
18
|
+
static isTextExtractionAvailable() {
|
|
19
|
+
// For development: Always return true
|
|
20
|
+
// In production, this would check if native modules are available
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Extract text from a specific page
|
|
26
|
+
* @param {string} filePath - Path to PDF file
|
|
27
|
+
* @param {number} pageNumber - Page number (0-indexed)
|
|
28
|
+
* @returns {Promise<string>} Extracted text content
|
|
29
|
+
*/
|
|
30
|
+
static async extractTextFromPage(filePath, pageNumber) {
|
|
31
|
+
// For development: Return placeholder text
|
|
32
|
+
// In production, this would use native modules to extract text
|
|
33
|
+
console.warn(`📄 PDFTextExtractor: Text extraction not fully implemented. Returning placeholder for page ${pageNumber}`);
|
|
34
|
+
return `[Text extraction from page ${pageNumber + 1} not yet implemented]`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Extract text from multiple pages
|
|
39
|
+
* @param {string} filePath - Path to PDF file
|
|
40
|
+
* @param {Array<number>} pageIndices - Array of page indices (0-indexed)
|
|
41
|
+
* @returns {Promise<Object>} Map of page index to extracted text
|
|
42
|
+
*/
|
|
43
|
+
static async extractTextFromPages(filePath, pageIndices) {
|
|
44
|
+
const textMap = {};
|
|
45
|
+
|
|
46
|
+
for (const pageIndex of pageIndices) {
|
|
47
|
+
textMap[pageIndex] = await this.extractTextFromPage(filePath, pageIndex);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return textMap;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Extract text from all pages
|
|
55
|
+
* @param {string} filePath - Path to PDF file
|
|
56
|
+
* @returns {Promise<Object>} Map of page index to extracted text
|
|
57
|
+
*/
|
|
58
|
+
static async extractAllText(filePath) {
|
|
59
|
+
// For development: Return placeholder for first few pages
|
|
60
|
+
// In production, this would extract from all pages
|
|
61
|
+
console.warn('📄 PDFTextExtractor: Full text extraction not yet implemented. Returning placeholder data.');
|
|
62
|
+
|
|
63
|
+
// Return placeholder data structure
|
|
64
|
+
return {
|
|
65
|
+
0: '[Text extraction from all pages not yet implemented]',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get page count
|
|
71
|
+
* @param {string} filePath - Path to PDF file
|
|
72
|
+
* @returns {Promise<number>} Number of pages
|
|
73
|
+
*/
|
|
74
|
+
static async getPageCount(filePath) {
|
|
75
|
+
// Placeholder implementation
|
|
76
|
+
// In production, this would use native modules
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default PDFTextExtractor;
|
|
82
|
+
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
package org.wonday.pdf;
|
|
2
|
-
|
|
3
|
-
import android.content.Context;
|
|
4
|
-
import android.content.pm.ApplicationInfo;
|
|
5
|
-
import android.content.pm.PackageManager;
|
|
6
|
-
import android.util.Log;
|
|
7
|
-
|
|
8
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
9
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
10
|
-
import com.facebook.react.bridge.ReactMethod;
|
|
11
|
-
import com.facebook.react.bridge.Promise;
|
|
12
|
-
import com.facebook.react.bridge.ReadableMap;
|
|
13
|
-
import com.facebook.react.bridge.WritableMap;
|
|
14
|
-
import com.facebook.react.bridge.Arguments;
|
|
15
|
-
|
|
16
|
-
import java.security.MessageDigest;
|
|
17
|
-
import java.security.NoSuchAlgorithmException;
|
|
18
|
-
import java.util.HashMap;
|
|
19
|
-
import java.util.Map;
|
|
20
|
-
|
|
21
|
-
import javax.crypto.Mac;
|
|
22
|
-
import javax.crypto.spec.SecretKeySpec;
|
|
23
|
-
|
|
24
|
-
public class LicenseVerifier extends ReactContextBaseJavaModule {
|
|
25
|
-
private static final String TAG = "LicenseVerifier";
|
|
26
|
-
|
|
27
|
-
// License info cache
|
|
28
|
-
private String currentLicenseKey = null;
|
|
29
|
-
private String currentTier = null;
|
|
30
|
-
private long expiryTimestamp = 0;
|
|
31
|
-
private String currentEmail = null;
|
|
32
|
-
|
|
33
|
-
// Secret key for HMAC verification (from app config)
|
|
34
|
-
private String secretKey = null;
|
|
35
|
-
|
|
36
|
-
public LicenseVerifier(ReactApplicationContext reactContext) {
|
|
37
|
-
super(reactContext);
|
|
38
|
-
loadSecretKey();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@Override
|
|
42
|
-
public String getName() {
|
|
43
|
-
return "LicenseVerifier";
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Load secret key from AndroidManifest meta-data
|
|
48
|
-
*/
|
|
49
|
-
private void loadSecretKey() {
|
|
50
|
-
try {
|
|
51
|
-
Context context = getReactApplicationContext();
|
|
52
|
-
ApplicationInfo appInfo = context.getPackageManager()
|
|
53
|
-
.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
|
|
54
|
-
|
|
55
|
-
if (appInfo.metaData != null) {
|
|
56
|
-
secretKey = appInfo.metaData.getString("com.reactnativepdf.license.secret");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (secretKey == null) {
|
|
60
|
-
Log.w(TAG, "License secret not found in AndroidManifest");
|
|
61
|
-
secretKey = "default-secret-change-in-production";
|
|
62
|
-
}
|
|
63
|
-
} catch (Exception e) {
|
|
64
|
-
Log.e(TAG, "Error loading license secret", e);
|
|
65
|
-
secretKey = "default-secret-change-in-production";
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Set license information from JS
|
|
71
|
-
*/
|
|
72
|
-
@ReactMethod
|
|
73
|
-
public void setLicenseInfo(ReadableMap licenseInfo, Promise promise) {
|
|
74
|
-
try {
|
|
75
|
-
if (licenseInfo == null) {
|
|
76
|
-
promise.reject("INVALID_LICENSE", "License info is null");
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
String licenseKey = licenseInfo.getString("key");
|
|
81
|
-
String tier = licenseInfo.getString("tier");
|
|
82
|
-
String email = licenseInfo.getString("email");
|
|
83
|
-
String expiresAt = licenseInfo.getString("expiresAt");
|
|
84
|
-
|
|
85
|
-
if (licenseKey == null || tier == null) {
|
|
86
|
-
promise.reject("INVALID_LICENSE", "Missing required license fields");
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Verify license key format and checksum
|
|
91
|
-
if (!verifyLicenseKey(licenseKey)) {
|
|
92
|
-
promise.reject("INVALID_LICENSE", "Invalid license key format or checksum");
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Parse expiry timestamp
|
|
97
|
-
long expiry = 0;
|
|
98
|
-
if (expiresAt != null && !expiresAt.isEmpty()) {
|
|
99
|
-
try {
|
|
100
|
-
expiry = java.time.Instant.parse(expiresAt).toEpochMilli();
|
|
101
|
-
} catch (Exception e) {
|
|
102
|
-
Log.w(TAG, "Invalid expiry date format", e);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Cache license info
|
|
107
|
-
this.currentLicenseKey = licenseKey;
|
|
108
|
-
this.currentTier = tier;
|
|
109
|
-
this.currentEmail = email;
|
|
110
|
-
this.expiryTimestamp = expiry;
|
|
111
|
-
|
|
112
|
-
Log.i(TAG, "License set: " + tier + " for " + email);
|
|
113
|
-
promise.resolve(true);
|
|
114
|
-
|
|
115
|
-
} catch (Exception e) {
|
|
116
|
-
Log.e(TAG, "Error setting license info", e);
|
|
117
|
-
promise.reject("LICENSE_ERROR", e.getMessage());
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Require Pro license for a feature
|
|
123
|
-
*/
|
|
124
|
-
@ReactMethod
|
|
125
|
-
public void requirePro(String featureName, Promise promise) {
|
|
126
|
-
try {
|
|
127
|
-
if (!isProActive()) {
|
|
128
|
-
WritableMap error = Arguments.createMap();
|
|
129
|
-
error.putString("code", "LICENSE_REQUIRED");
|
|
130
|
-
error.putString("feature", featureName);
|
|
131
|
-
error.putString("message", featureName + " requires a Pro license");
|
|
132
|
-
promise.reject("LICENSE_REQUIRED", error);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
promise.resolve(true);
|
|
137
|
-
} catch (Exception e) {
|
|
138
|
-
Log.e(TAG, "Error checking Pro license", e);
|
|
139
|
-
promise.reject("LICENSE_ERROR", e.getMessage());
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Check if Pro license is active
|
|
145
|
-
*/
|
|
146
|
-
public boolean isProActive() {
|
|
147
|
-
// 🧪 TESTING MODE: Always return true for testing
|
|
148
|
-
Log.i(TAG, "🧪 TESTING MODE: isProActive() returning true for testing");
|
|
149
|
-
return true;
|
|
150
|
-
|
|
151
|
-
/* PRODUCTION CODE (commented out for testing):
|
|
152
|
-
if (currentLicenseKey == null || currentTier == null) {
|
|
153
|
-
Log.w(TAG, "No license set");
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Check if license is expired
|
|
158
|
-
if (expiryTimestamp > 0 && System.currentTimeMillis() > expiryTimestamp) {
|
|
159
|
-
Log.w(TAG, "License expired");
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Check if tier is Pro or higher
|
|
164
|
-
return isProTier(currentTier);
|
|
165
|
-
*/
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Check if tier is Pro or higher
|
|
170
|
-
*/
|
|
171
|
-
private boolean isProTier(String tier) {
|
|
172
|
-
if (tier == null) return false;
|
|
173
|
-
|
|
174
|
-
switch (tier.toLowerCase()) {
|
|
175
|
-
case "solo":
|
|
176
|
-
case "professional":
|
|
177
|
-
case "team":
|
|
178
|
-
case "enterprise":
|
|
179
|
-
return true;
|
|
180
|
-
default:
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Get current license tier
|
|
187
|
-
*/
|
|
188
|
-
@ReactMethod
|
|
189
|
-
public void getTier(Promise promise) {
|
|
190
|
-
try {
|
|
191
|
-
if (currentTier == null) {
|
|
192
|
-
promise.resolve("free");
|
|
193
|
-
} else {
|
|
194
|
-
promise.resolve(currentTier);
|
|
195
|
-
}
|
|
196
|
-
} catch (Exception e) {
|
|
197
|
-
Log.e(TAG, "Error getting tier", e);
|
|
198
|
-
promise.reject("LICENSE_ERROR", e.getMessage());
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Check if license is expired
|
|
204
|
-
*/
|
|
205
|
-
@ReactMethod
|
|
206
|
-
public void isExpired(Promise promise) {
|
|
207
|
-
try {
|
|
208
|
-
boolean expired = expiryTimestamp > 0 && System.currentTimeMillis() > expiryTimestamp;
|
|
209
|
-
promise.resolve(expired);
|
|
210
|
-
} catch (Exception e) {
|
|
211
|
-
Log.e(TAG, "Error checking expiry", e);
|
|
212
|
-
promise.reject("LICENSE_ERROR", e.getMessage());
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Verify license key format and checksum
|
|
218
|
-
*/
|
|
219
|
-
private boolean verifyLicenseKey(String licenseKey) {
|
|
220
|
-
if (licenseKey == null || licenseKey.length() != 19) {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Check format: X###-####-####-####
|
|
225
|
-
if (!licenseKey.matches("^[SPTE][A-F0-9]{3}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}$")) {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Verify checksum
|
|
230
|
-
try {
|
|
231
|
-
String[] parts = licenseKey.split("-");
|
|
232
|
-
String prefix = parts[0].substring(0, 1);
|
|
233
|
-
String seg1 = parts[0].substring(1);
|
|
234
|
-
String seg2 = parts[1];
|
|
235
|
-
String seg3 = parts[2];
|
|
236
|
-
String checksum = parts[3];
|
|
237
|
-
|
|
238
|
-
String data = prefix + seg1 + seg2 + seg3;
|
|
239
|
-
String expectedChecksum = generateChecksum(data);
|
|
240
|
-
|
|
241
|
-
return checksum.equals(expectedChecksum);
|
|
242
|
-
} catch (Exception e) {
|
|
243
|
-
Log.e(TAG, "Error verifying license key", e);
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Generate checksum for license key
|
|
250
|
-
*/
|
|
251
|
-
private String generateChecksum(String data) {
|
|
252
|
-
try {
|
|
253
|
-
Mac mac = Mac.getInstance("HmacSHA256");
|
|
254
|
-
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
|
|
255
|
-
mac.init(secretKeySpec);
|
|
256
|
-
|
|
257
|
-
byte[] hash = mac.doFinal(data.getBytes());
|
|
258
|
-
StringBuilder hexString = new StringBuilder();
|
|
259
|
-
|
|
260
|
-
for (byte b : hash) {
|
|
261
|
-
String hex = Integer.toHexString(0xff & b);
|
|
262
|
-
if (hex.length() == 1) {
|
|
263
|
-
hexString.append('0');
|
|
264
|
-
}
|
|
265
|
-
hexString.append(hex);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return hexString.toString().toUpperCase().substring(0, 4);
|
|
269
|
-
} catch (Exception e) {
|
|
270
|
-
Log.e(TAG, "Error generating checksum", e);
|
|
271
|
-
return "0000";
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Get license info for debugging
|
|
277
|
-
*/
|
|
278
|
-
@ReactMethod
|
|
279
|
-
public void getLicenseInfo(Promise promise) {
|
|
280
|
-
try {
|
|
281
|
-
WritableMap info = Arguments.createMap();
|
|
282
|
-
info.putString("key", currentLicenseKey);
|
|
283
|
-
info.putString("tier", currentTier);
|
|
284
|
-
info.putString("email", currentEmail);
|
|
285
|
-
info.putDouble("expiresAt", expiryTimestamp);
|
|
286
|
-
info.putBoolean("isPro", isProActive());
|
|
287
|
-
promise.resolve(info);
|
|
288
|
-
} catch (Exception e) {
|
|
289
|
-
Log.e(TAG, "Error getting license info", e);
|
|
290
|
-
promise.reject("LICENSE_ERROR", e.getMessage());
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Clear license info
|
|
296
|
-
*/
|
|
297
|
-
@ReactMethod
|
|
298
|
-
public void clearLicense(Promise promise) {
|
|
299
|
-
try {
|
|
300
|
-
currentLicenseKey = null;
|
|
301
|
-
currentTier = null;
|
|
302
|
-
currentEmail = null;
|
|
303
|
-
expiryTimestamp = 0;
|
|
304
|
-
Log.i(TAG, "License cleared");
|
|
305
|
-
promise.resolve(true);
|
|
306
|
-
} catch (Exception e) {
|
|
307
|
-
Log.e(TAG, "Error clearing license", e);
|
|
308
|
-
promise.reject("LICENSE_ERROR", e.getMessage());
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|