diff options
| author | Bananeweizen <bananeweizen@gmx.de> | 2013-01-05 11:03:58 +0100 |
|---|---|---|
| committer | Bananeweizen <bananeweizen@gmx.de> | 2013-01-05 11:03:58 +0100 |
| commit | 68069dc6982f3a2c87690eb9171f5820064ebbab (patch) | |
| tree | 0be0bf26f5d3d272224d048d82fc32abef37a188 /main/src/cgeo | |
| parent | 656e92453fcf0e9d7da137cd4c3551b6530e9969 (diff) | |
| download | cgeo-68069dc6982f3a2c87690eb9171f5820064ebbab.zip cgeo-68069dc6982f3a2c87690eb9171f5820064ebbab.tar.gz cgeo-68069dc6982f3a2c87690eb9171f5820064ebbab.tar.bz2 | |
fix #2328: Have a wrapper around Matcher to avoid String related memory
issues
Diffstat (limited to 'main/src/cgeo')
| -rw-r--r-- | main/src/cgeo/geocaching/CacheDetailActivity.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/LogEntry.java | 4 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgCache.java | 12 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCParser.java | 69 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/Login.java | 6 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/GPXParser.java | 12 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/files/LocParser.java | 16 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/gcvote/GCVote.java | 14 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/geopoint/DistanceParser.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/geopoint/GeopointParser.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java | 10 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/utils/MatcherWrapper.java | 91 |
13 files changed, 169 insertions, 84 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index b0398a1..73675de 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -34,6 +34,7 @@ import cgeo.geocaching.utils.GeoDirHandler; import cgeo.geocaching.utils.HtmlUtils; import cgeo.geocaching.utils.ImageHelper; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import cgeo.geocaching.utils.TranslationUtils; import cgeo.geocaching.utils.UnknownTagsHandler; @@ -102,7 +103,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -1926,7 +1926,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc backcolor = color.darker_gray; } else { - Matcher matcher = DARK_COLOR_PATTERN.matcher(text); + MatcherWrapper matcher = new MatcherWrapper(DARK_COLOR_PATTERN, text); if (matcher.find()) { backcolor = color.darker_gray; } diff --git a/main/src/cgeo/geocaching/LogEntry.java b/main/src/cgeo/geocaching/LogEntry.java index b625bb5..1cb3de3 100644 --- a/main/src/cgeo/geocaching/LogEntry.java +++ b/main/src/cgeo/geocaching/LogEntry.java @@ -2,6 +2,7 @@ package cgeo.geocaching; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.utils.DateUtils; +import cgeo.geocaching.utils.MatcherWrapper; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -10,7 +11,6 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; -import java.util.regex.Matcher; import java.util.regex.Pattern; public final class LogEntry { @@ -107,7 +107,7 @@ public final class LogEntry { */ public String getDisplayText() { if (Settings.getPlainLogs()) { - Matcher matcher = PATTERN_REMOVE_COLORS.matcher(log); + MatcherWrapper matcher = new MatcherWrapper(PATTERN_REMOVE_COLORS, log); return matcher.replaceAll(""); } return log; diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index 0f5315e..9fae23b 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -27,6 +27,7 @@ import cgeo.geocaching.utils.LazyInitializedList; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import cgeo.geocaching.utils.LogTemplateProvider.LogContext; +import cgeo.geocaching.utils.MatcherWrapper; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -47,7 +48,6 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -757,7 +757,7 @@ public class cgCache implements ICache, IWaypoint { @Override public String getNameForSorting() { if (null == nameForSorting) { - final Matcher matcher = NUMBER_PATTERN.matcher(name); + final MatcherWrapper matcher = new MatcherWrapper(NUMBER_PATTERN, name); if (matcher.find()) { nameForSorting = name.replace(matcher.group(), StringUtils.leftPad(matcher.group(), 6, '0')); } @@ -1315,7 +1315,7 @@ public class cgCache implements ICache, IWaypoint { final Pattern coordPattern = Pattern.compile("\\b[nNsS]{1}\\s*\\d"); // begin of coordinates int count = 1; String note = getPersonalNote(); - Matcher matcher = coordPattern.matcher(note); + MatcherWrapper matcher = new MatcherWrapper(coordPattern, note); while (matcher.find()) { try { final Geopoint point = new Geopoint(note.substring(matcher.start())); @@ -1332,7 +1332,7 @@ public class cgCache implements ICache, IWaypoint { } note = note.substring(matcher.start() + 1); - matcher = coordPattern.matcher(note); + matcher = new MatcherWrapper(coordPattern, note); } } catch (Exception e) { Log.e("cgCache.parseWaypointsFromNote: " + e.toString()); @@ -1574,7 +1574,7 @@ public class cgCache implements ICache, IWaypoint { } // 12:34 final Pattern time = Pattern.compile("\\b(\\d{1,2})\\:(\\d\\d)\\b"); - final Matcher matcher = time.matcher(getDescription()); + final MatcherWrapper matcher = new MatcherWrapper(time, getDescription()); while (matcher.find()) { try { final int hours = Integer.valueOf(matcher.group(1)); @@ -1590,7 +1590,7 @@ public class cgCache implements ICache, IWaypoint { final String hourLocalized = cgeoapplication.getInstance().getString(R.string.cache_time_full_hours); if (StringUtils.isNotBlank(hourLocalized)) { final Pattern fullHours = Pattern.compile("\\b(\\d{1,2})\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE); - final Matcher matcherHours = fullHours.matcher(getDescription()); + final MatcherWrapper matcherHours = new MatcherWrapper(fullHours, getDescription()); if (matcherHours.find()) { try { final int hours = Integer.valueOf(matcherHours.group(1)); diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index 5243f18..91b0ddd 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -31,6 +31,7 @@ import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.LazyInitializedList; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import ch.boye.httpclientandroidlib.HttpResponse; @@ -54,7 +55,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Set; -import java.util.regex.Matcher; public abstract class GCParser { private final static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009 @@ -128,7 +128,7 @@ public abstract class GCParser { } try { - final Matcher matcherGuidAndDisabled = GCConstants.PATTERN_SEARCH_GUIDANDDISABLED.matcher(row); + final MatcherWrapper matcherGuidAndDisabled = new MatcherWrapper(GCConstants.PATTERN_SEARCH_GUIDANDDISABLED, row); while (matcherGuidAndDisabled.find()) { if (matcherGuidAndDisabled.groupCount() > 0) { @@ -169,7 +169,7 @@ public abstract class GCParser { } // cache inventory - final Matcher matcherTbs = GCConstants.PATTERN_SEARCH_TRACKABLES.matcher(row); + final MatcherWrapper matcherTbs = new MatcherWrapper(GCConstants.PATTERN_SEARCH_TRACKABLES, row); String inventoryPre = null; while (matcherTbs.find()) { if (matcherTbs.groupCount() > 0) { @@ -183,7 +183,7 @@ public abstract class GCParser { } if (StringUtils.isNotBlank(inventoryPre)) { - final Matcher matcherTbsInside = GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE.matcher(inventoryPre); + final MatcherWrapper matcherTbsInside = new MatcherWrapper(GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE, inventoryPre); while (matcherTbsInside.find()) { if (matcherTbsInside.groupCount() == 2 && matcherTbsInside.group(2) != null && @@ -500,7 +500,7 @@ public abstract class GCParser { try { final String attributesPre = BaseUtils.getMatch(page, GCConstants.PATTERN_ATTRIBUTES, true, null); if (null != attributesPre) { - final Matcher matcherAttributesInside = GCConstants.PATTERN_ATTRIBUTESINSIDE.matcher(attributesPre); + final MatcherWrapper matcherAttributesInside = new MatcherWrapper(GCConstants.PATTERN_ATTRIBUTESINSIDE, attributesPre); final ArrayList<String> attributes = new ArrayList<String>(); while (matcherAttributesInside.find()) { @@ -534,24 +534,20 @@ public abstract class GCParser { } CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers); - final Matcher matcherSpoilersInside = GCConstants.PATTERN_SPOILER_IMAGE.matcher(page); + final MatcherWrapper matcherSpoilersInside = new MatcherWrapper(GCConstants.PATTERN_SPOILER_IMAGE, page); while (matcherSpoilersInside.find()) { // the original spoiler URL (include .../display/... contains a low-resolution image // if we shorten the URL we get the original-resolution image - // - // Create a new string to avoid referencing the whole page though the matcher (@see BaseUtils.getMatch()) - String url = new String(matcherSpoilersInside.group(1).replace("/display", "")); + String url = matcherSpoilersInside.group(1).replace("/display", ""); String title = null; if (matcherSpoilersInside.group(3) != null) { - // Create a new string to avoid referencing the whole page though the matcher (@see BaseUtils.getMatch()) - title = new String(matcherSpoilersInside.group(3)); + title = matcherSpoilersInside.group(3); } String description = null; if (matcherSpoilersInside.group(4) != null) { - // Create a new string to avoid referencing the whole page though the matcher (@see BaseUtils.getMatch()) - description = new String(matcherSpoilersInside.group(4)); + description = matcherSpoilersInside.group(4); } cache.addSpoiler(new cgImage(url, title, description)); } @@ -564,7 +560,7 @@ public abstract class GCParser { try { cache.setInventoryItems(0); - final Matcher matcherInventory = GCConstants.PATTERN_INVENTORY.matcher(page); + final MatcherWrapper matcherInventory = new MatcherWrapper(GCConstants.PATTERN_INVENTORY, page); if (matcherInventory.find()) { if (cache.getInventory() == null) { cache.setInventory(new ArrayList<cgTrackable>()); @@ -574,15 +570,13 @@ public abstract class GCParser { final String inventoryPre = matcherInventory.group(2); if (StringUtils.isNotBlank(inventoryPre)) { - final Matcher matcherInventoryInside = GCConstants.PATTERN_INVENTORYINSIDE.matcher(inventoryPre); + final MatcherWrapper matcherInventoryInside = new MatcherWrapper(GCConstants.PATTERN_INVENTORYINSIDE, inventoryPre); while (matcherInventoryInside.find()) { if (matcherInventoryInside.groupCount() > 0) { final cgTrackable inventoryItem = new cgTrackable(); - // Create a new string to avoid referencing the whole page though the matcher (@see BaseUtils.getMatch()) - inventoryItem.setGuid(new String(matcherInventoryInside.group(1))); - // Create a new string to avoid referencing the whole page though the matcher (@see BaseUtils.getMatch()) - inventoryItem.setName(new String(matcherInventoryInside.group(2))); + inventoryItem.setGuid(matcherInventoryInside.group(1)); + inventoryItem.setName(matcherInventoryInside.group(2)); cache.getInventory().add(inventoryItem); cache.setInventoryItems(cache.getInventoryItems() + 1); @@ -597,14 +591,12 @@ public abstract class GCParser { } // cache logs counts - try - { + try { final String countlogs = BaseUtils.getMatch(page, GCConstants.PATTERN_COUNTLOGS, true, null); if (null != countlogs) { - final Matcher matcherLog = GCConstants.PATTERN_COUNTLOG.matcher(countlogs); + final MatcherWrapper matcherLog = new MatcherWrapper(GCConstants.PATTERN_COUNTLOG, countlogs); - while (matcherLog.find()) - { + while (matcherLog.find()) { String typeStr = matcherLog.group(1); String countStr = matcherLog.group(2).replaceAll("[.,]", ""); @@ -615,8 +607,7 @@ public abstract class GCParser { } } } - } catch (Exception e) - { + } catch (Exception e) { // failed to parse logs Log.w("GCParser.parseCache: Failed to parse cache log count"); } @@ -1003,7 +994,7 @@ public abstract class GCParser { // maintenance, archived needs to be confirmed - final Matcher matcher = GCConstants.PATTERN_MAINTENANCE.matcher(page); + final MatcherWrapper matcher = new MatcherWrapper(GCConstants.PATTERN_MAINTENANCE, page); try { if (matcher.find() && matcher.groupCount() > 0) { @@ -1052,7 +1043,7 @@ public abstract class GCParser { try { - final Matcher matcherOk = GCConstants.PATTERN_OK1.matcher(page); + final MatcherWrapper matcherOk = new MatcherWrapper(GCConstants.PATTERN_OK1, page); if (matcherOk.find()) { Log.i("Log successfully posted to cache #" + cacheid); @@ -1121,7 +1112,7 @@ public abstract class GCParser { try { - final Matcher matcherOk = GCConstants.PATTERN_OK2.matcher(page); + final MatcherWrapper matcherOk = new MatcherWrapper(GCConstants.PATTERN_OK2, page); if (matcherOk.find()) { Log.i("Log successfully posted to trackable #" + trackingCode); return StatusCode.NO_ERROR; @@ -1292,7 +1283,7 @@ public abstract class GCParser { // trackable owner name try { - final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page); + final MatcherWrapper matcherOwner = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_OWNER, page); if (matcherOwner.find() && matcherOwner.groupCount() > 0) { trackable.setOwnerGuid(matcherOwner.group(1)); trackable.setOwner(matcherOwner.group(2).trim()); @@ -1307,14 +1298,14 @@ public abstract class GCParser { // trackable spotted try { - final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(page); + final MatcherWrapper matcherSpottedCache = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE, page); if (matcherSpottedCache.find() && matcherSpottedCache.groupCount() > 0) { trackable.setSpottedGuid(matcherSpottedCache.group(1)); trackable.setSpottedName(matcherSpottedCache.group(2).trim()); trackable.setSpottedType(cgTrackable.SPOTTED_CACHE); } - final Matcher matcherSpottedUser = GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER.matcher(page); + final MatcherWrapper matcherSpottedUser = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER, page); if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) { trackable.setSpottedGuid(matcherSpottedUser.group(1)); trackable.setSpottedName(matcherSpottedUser.group(2).trim()); @@ -1357,7 +1348,7 @@ public abstract class GCParser { // trackable details & image try { - final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page); + final MatcherWrapper matcherDetailsImage = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE, page); if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) { final String image = StringUtils.trim(matcherDetailsImage.group(3)); final String details = StringUtils.trim(matcherDetailsImage.group(4)); @@ -1376,7 +1367,7 @@ public abstract class GCParser { // trackable logs try { - final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page); + final MatcherWrapper matcherLogs = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_LOG, page); /* * 1. Type (image) * 2. Date @@ -1406,7 +1397,7 @@ public abstract class GCParser { // Apply the pattern for images in a trackable log entry against each full log (group(0)) final String logEntry = matcherLogs.group(0); - final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(logEntry); + final MatcherWrapper matcherLogImages = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE_LOG_IMAGES, logEntry); /* * 1. Image URL * 2. Image title @@ -1456,7 +1447,7 @@ public abstract class GCParser { String rawResponse; if (!getDataFromPage) { - final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN.matcher(page); + final MatcherWrapper userTokenMatcher = new MatcherWrapper(GCConstants.PATTERN_USERTOKEN, page); if (!userTokenMatcher.find()) { Log.e("GCParser.loadLogsFromDetails: unable to extract userToken"); return null; @@ -1555,7 +1546,7 @@ public abstract class GCParser { final List<LogType> types = new ArrayList<LogType>(); - final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page); + final MatcherWrapper typeBoxMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPEBOX, page); String typesText = null; if (typeBoxMatcher.find()) { if (typeBoxMatcher.groupCount() > 0) { @@ -1565,7 +1556,7 @@ public abstract class GCParser { if (typesText != null) { - final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText); + final MatcherWrapper typeMatcher = new MatcherWrapper(GCConstants.PATTERN_TYPE2, typesText); while (typeMatcher.find()) { if (typeMatcher.groupCount() > 1) { try { @@ -1603,7 +1594,7 @@ public abstract class GCParser { final List<TrackableLog> trackableLogs = new ArrayList<TrackableLog>(); - final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page); + final MatcherWrapper trackableMatcher = new MatcherWrapper(GCConstants.PATTERN_TRACKABLE, page); while (trackableMatcher.find()) { if (trackableMatcher.groupCount() > 0) { diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java index 494bcee..9a60f65 100644 --- a/main/src/cgeo/geocaching/connector/gc/Login.java +++ b/main/src/cgeo/geocaching/connector/gc/Login.java @@ -10,6 +10,7 @@ import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import ch.boye.httpclientandroidlib.HttpResponse; @@ -26,7 +27,6 @@ import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; -import java.util.regex.Matcher; public abstract class Login { @@ -349,7 +349,7 @@ public abstract class Login { } int count = 1; - final Matcher matcherViewstateCount = GCConstants.PATTERN_VIEWSTATEFIELDCOUNT.matcher(page); + final MatcherWrapper matcherViewstateCount = new MatcherWrapper(GCConstants.PATTERN_VIEWSTATEFIELDCOUNT, page); if (matcherViewstateCount.find()) { try { count = Integer.parseInt(matcherViewstateCount.group(1)); @@ -361,7 +361,7 @@ public abstract class Login { String[] viewstates = new String[count]; // Get the viewstates - final Matcher matcherViewstates = GCConstants.PATTERN_VIEWSTATES.matcher(page); + final MatcherWrapper matcherViewstates = new MatcherWrapper(GCConstants.PATTERN_VIEWSTATES, page); while (matcherViewstates.find()) { String sno = matcherViewstates.group(1); // number of viewstate int no; diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java index e34d277..5965fff 100644 --- a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java +++ b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java @@ -1,6 +1,7 @@ package cgeo.geocaching.connector.gc; -import java.util.regex.Matcher; +import cgeo.geocaching.utils.MatcherWrapper; + import java.util.regex.Pattern; @@ -35,7 +36,7 @@ public final class UTFGridPosition { * @return */ static UTFGridPosition fromString(String key) { - final Matcher matcher = UTFGridPosition.PATTERN_JSON_KEY.matcher(key); + final MatcherWrapper matcher = new MatcherWrapper(UTFGridPosition.PATTERN_JSON_KEY, key); try { if (matcher.matches()) { final int x = Integer.parseInt(matcher.group(1)); diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index 2ac19bb..e2d7205 100644 --- a/main/src/cgeo/geocaching/files/GPXParser.java +++ b/main/src/cgeo/geocaching/files/GPXParser.java @@ -19,6 +19,7 @@ import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import org.apache.commons.lang3.StringUtils; import org.xml.sax.Attributes; @@ -42,7 +43,6 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.Locale; import java.util.Set; -import java.util.regex.Matcher; import java.util.regex.Pattern; public abstract class GPXParser extends FileParser { @@ -209,7 +209,7 @@ public abstract class GPXParser extends FileParser { return null; } // cut out baseName - final Matcher m = BASENAME_PATTERN.matcher(stringName); + final MatcherWrapper m = new MatcherWrapper(BASENAME_PATTERN, stringName); if (!m.matches()) { return null; } @@ -235,7 +235,7 @@ public abstract class GPXParser extends FileParser { static Date parseDate(String inputUntrimmed) throws ParseException { String input = inputUntrimmed.trim(); // remove milliseconds to reduce number of needed patterns - final Matcher matcher = PATTERN_MILLISECONDS.matcher(input); + final MatcherWrapper matcher = new MatcherWrapper(PATTERN_MILLISECONDS, input); input = matcher.replaceFirst(""); if (input.contains("Z")) { return formatSimpleZ.parse(input); @@ -432,14 +432,14 @@ public abstract class GPXParser extends FileParser { @Override public void end(String url) { - final Matcher matcher = patternGuid.matcher(url); + final MatcherWrapper matcher = new MatcherWrapper(patternGuid, url); if (matcher.matches()) { final String guid = matcher.group(1); if (StringUtils.isNotBlank(guid)) { cache.setGuid(guid); } } - final Matcher matcherCode = patternUrlGeocode.matcher(url); + final MatcherWrapper matcherCode = new MatcherWrapper(patternUrlGeocode, url); if (matcherCode.matches()) { String geocode = matcherCode.group(1); cache.setGeocode(geocode); @@ -836,7 +836,7 @@ public abstract class GPXParser extends FileParser { return; } final String trimmed = input.trim(); - final Matcher matcherGeocode = patternGeocode.matcher(trimmed); + final MatcherWrapper matcherGeocode = new MatcherWrapper(patternGeocode, trimmed); if (matcherGeocode.find()) { final String geocode = matcherGeocode.group(1); // a geocode should not be part of a word diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java index 9c24d39..730e224 100644 --- a/main/src/cgeo/geocaching/files/LocParser.java +++ b/main/src/cgeo/geocaching/files/LocParser.java @@ -9,6 +9,7 @@ import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import org.apache.commons.lang3.StringUtils; @@ -22,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.regex.Matcher; import java.util.regex.Pattern; public final class LocParser extends FileParser { @@ -148,12 +148,12 @@ public final class LocParser extends FileParser { public static cgCache parseCache(final String pointString) { final cgCache cache = new cgCache(); - final Matcher matcherGeocode = patternGeocode.matcher(pointString); + final MatcherWrapper matcherGeocode = new MatcherWrapper(patternGeocode, pointString); if (matcherGeocode.find()) { cache.setGeocode(matcherGeocode.group(1).trim()); } - final Matcher matcherName = patternName.matcher(pointString); + final MatcherWrapper matcherName = new MatcherWrapper(patternName, pointString); if (matcherName.find()) { final String name = matcherName.group(1).trim(); cache.setName(StringUtils.substringBeforeLast(name, " by ").trim()); @@ -161,24 +161,24 @@ public final class LocParser extends FileParser { cache.setName(cache.getGeocode()); } - final Matcher matcherLat = patternLat.matcher(pointString); - final Matcher matcherLon = patternLon.matcher(pointString); + final MatcherWrapper matcherLat = new MatcherWrapper(patternLat, pointString); + final MatcherWrapper matcherLon = new MatcherWrapper(patternLon, pointString); if (matcherLat.find() && matcherLon.find()) { cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim())); } - final Matcher matcherDifficulty = patternDifficulty.matcher(pointString); + final MatcherWrapper matcherDifficulty = new MatcherWrapper(patternDifficulty, pointString); try { if (matcherDifficulty.find()) { cache.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim())); } - final Matcher matcherTerrain = patternTerrain.matcher(pointString); + final MatcherWrapper matcherTerrain = new MatcherWrapper(patternTerrain, pointString); if (matcherTerrain.find()) { cache.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim())); } - final Matcher matcherContainer = patternContainer.matcher(pointString); + final MatcherWrapper matcherContainer = new MatcherWrapper(patternContainer, pointString); if (matcherContainer.find()) { final int size = Integer.parseInt(matcherContainer.group(1).trim()); if (size >= 1 && size <= 8) { diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java index 3d87724..e98ba56 100644 --- a/main/src/cgeo/geocaching/gcvote/GCVote.java +++ b/main/src/cgeo/geocaching/gcvote/GCVote.java @@ -6,6 +6,7 @@ import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.LeastRecentlyUsedMap; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -15,7 +16,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; import java.util.regex.Pattern; public final class GCVote { @@ -98,7 +98,7 @@ public final class GCVote { return null; } - final Matcher matcherVoteElement = patternVoteElement.matcher(page); + final MatcherWrapper matcherVoteElement = new MatcherWrapper(patternVoteElement, page); while (matcherVoteElement.find()) { String voteData = matcherVoteElement.group(1); if (voteData == null) { @@ -107,7 +107,7 @@ public final class GCVote { String guid = null; try { - final Matcher matcherGuid = patternGuid.matcher(voteData); + final MatcherWrapper matcherGuid = new MatcherWrapper(patternGuid, voteData); if (matcherGuid.find()) { if (matcherGuid.groupCount() > 0) { guid = matcherGuid.group(1); @@ -122,7 +122,7 @@ public final class GCVote { boolean loggedIn = false; try { - final Matcher matcherLoggedIn = patternLogIn.matcher(page); + final MatcherWrapper matcherLoggedIn = new MatcherWrapper(patternLogIn, page); if (matcherLoggedIn.find()) { if (matcherLoggedIn.groupCount() > 0) { if (matcherLoggedIn.group(1).equalsIgnoreCase("true")) { @@ -136,7 +136,7 @@ public final class GCVote { float rating = 0; try { - final Matcher matcherRating = patternRating.matcher(voteData); + final MatcherWrapper matcherRating = new MatcherWrapper(patternRating, voteData); if (matcherRating.find()) { rating = Float.parseFloat(matcherRating.group(1)); } @@ -149,7 +149,7 @@ public final class GCVote { int votes = -1; try { - final Matcher matcherVotes = patternVotes.matcher(voteData); + final MatcherWrapper matcherVotes = new MatcherWrapper(patternVotes, voteData); if (matcherVotes.find()) { votes = Integer.parseInt(matcherVotes.group(1)); } @@ -163,7 +163,7 @@ public final class GCVote { float myVote = 0; if (loggedIn) { try { - final Matcher matcherVote = patternVote.matcher(voteData); + final MatcherWrapper matcherVote = new MatcherWrapper(patternVote, voteData); if (matcherVote.find()) { myVote = Float.parseFloat(matcherVote.group(1)); } diff --git a/main/src/cgeo/geocaching/geopoint/DistanceParser.java b/main/src/cgeo/geocaching/geopoint/DistanceParser.java index d8db8e4..e1692f4 100644 --- a/main/src/cgeo/geocaching/geopoint/DistanceParser.java +++ b/main/src/cgeo/geocaching/geopoint/DistanceParser.java @@ -1,9 +1,10 @@ package cgeo.geocaching.geopoint; +import cgeo.geocaching.utils.MatcherWrapper; + import org.apache.commons.lang3.StringUtils; import java.util.Locale; -import java.util.regex.Matcher; import java.util.regex.Pattern; public final class DistanceParser { @@ -22,7 +23,7 @@ public final class DistanceParser { * if the given number is invalid */ public static float parseDistance(String distanceText, final boolean metricUnit) { - final Matcher matcher = pattern.matcher(distanceText); + final MatcherWrapper matcher = new MatcherWrapper(pattern, distanceText); if (!matcher.find()) { throw new NumberFormatException(distanceText); diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/geopoint/GeopointParser.java index 7604b9d..97a9ec8 100644 --- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java +++ b/main/src/cgeo/geocaching/geopoint/GeopointParser.java @@ -1,9 +1,10 @@ package cgeo.geocaching.geopoint; +import cgeo.geocaching.utils.MatcherWrapper; + import org.apache.commons.lang3.StringUtils; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -105,7 +106,7 @@ class GeopointParser { { final Pattern pattern = LatLon.LAT == latlon ? patternLat : patternLon; - final Matcher matcher = pattern.matcher(text); + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); if (matcher.find()) { final double sign = matcher.group(1).equalsIgnoreCase("S") || matcher.group(1).equalsIgnoreCase("W") ? -1.0 : 1.0; diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index 96edebf..61478b5 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -7,6 +7,7 @@ import cgeo.geocaching.network.Network; import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity; import ch.boye.httpclientandroidlib.util.EntityUtils; @@ -24,7 +25,6 @@ import android.view.View; import android.widget.Button; import android.widget.EditText; -import java.util.regex.Matcher; import java.util.regex.Pattern; public class TwitterAuthorizationActivity extends AbstractActivity { @@ -142,11 +142,11 @@ public class TwitterAuthorizationActivity extends AbstractActivity { if (StringUtils.isNotBlank(line)) { - final Matcher paramsMatcher1 = paramsPattern1.matcher(line); + final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); if (paramsMatcher1.find()) { OAtoken = paramsMatcher1.group(1); } - final Matcher paramsMatcher2 = paramsPattern2.matcher(line); + final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); if (paramsMatcher2.find()) { OAtokenSecret = paramsMatcher2.group(1); } @@ -189,11 +189,11 @@ public class TwitterAuthorizationActivity extends AbstractActivity { OAtoken = ""; OAtokenSecret = ""; - final Matcher paramsMatcher1 = paramsPattern1.matcher(line); + final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); if (paramsMatcher1.find()) { OAtoken = paramsMatcher1.group(1); } - final Matcher paramsMatcher2 = paramsPattern2.matcher(line); + final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) { OAtokenSecret = paramsMatcher2.group(1); } diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java new file mode 100644 index 0000000..c3c1663 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java @@ -0,0 +1,91 @@ +package cgeo.geocaching.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Wrapper around the regex {@link Matcher} class. This implementation optimizes the memory usage of the matched + * Strings. + * + */ +public class MatcherWrapper { + private final Matcher matcher; + + public MatcherWrapper(Pattern pattern, String input) { + this.matcher = pattern.matcher(input); + } + + /** + * see {@link Matcher#find()} + */ + public boolean find() { + return matcher.find(); + } + + /** + * see {@link Matcher#group(int)} + */ + public String group(int index) { + return newString(matcher.group(index)); + } + + /** + * This method explicitly creates a new String instance from an already existing String. This is necessary to avoid + * huge memory leaks in our parser. If we do regular expression matching on large Strings, the returned matches are + * otherwise memory mapped substrings of the huge original String, therefore blocking the garbage collector from + * removing the huge input String. + * <p> + * Do not change this method, even if Findbugs and other tools will report a violation for that line! + * + * @param input + * @return + */ + private static String newString(String input) { + if (input == null) { + return null; + } + return new String(input); // DON'T REMOVE THE "new String" HERE! + } + + /** + * see {@link Matcher#groupCount()} + */ + public int groupCount() { + return matcher.groupCount(); + } + + /** + * see {@link Matcher#group()} + */ + public String group() { + return newString(matcher.group()); + } + + /** + * see {@link Matcher#start()} + */ + public int start() { + return matcher.start(); + } + + /** + * see {@link Matcher#replaceAll(String)} + */ + public String replaceAll(String replacement) { + return newString(matcher.replaceAll(replacement)); + } + + /** + * see {@link Matcher#matches()} + */ + public boolean matches() { + return matcher.matches(); + } + + /** + * see {@link Matcher#replaceFirst(String)} + */ + public String replaceFirst(String replacement) { + return newString(matcher.replaceFirst(replacement)); + } +} |
