项目结构调整

This commit is contained in:
艾竹
2023-04-16 20:11:40 +08:00
parent cbfbf96033
commit 81f91f3f35
2124 changed files with 218 additions and 5516 deletions

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary> <p>See
/// <a href="http://www.nttdocomo.co.jp/english/service/imode/make/content/barcode/about/s2.html">
/// DoCoMo's documentation</a> about the result types represented by subclasses of this class.</p>
///
/// <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
/// on exception-based mechanisms during parsing.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
abstract class AbstractDoCoMoResultParser : ResultParser
{
internal static String[] matchDoCoMoPrefixedField(String prefix, String rawText)
{
return matchPrefixedField(prefix, rawText, ';', true);
}
internal static String matchSingleDoCoMoPrefixedField(String prefix, String rawText, bool trim)
{
return matchSinglePrefixedField(prefix, rawText, ';', trim);
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing.Client.Result
{
/// <summary> Implements KDDI AU's address book format. See
/// <a href="http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html">
/// http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html</a>.
/// (Thanks to Yuzo for translating!)
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class AddressBookAUResultParser : ResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
var rawText = result.Text;
// MEMORY is mandatory; seems like a decent indicator, as does end-of-record separator CR/LF
if (rawText == null || rawText.IndexOf("MEMORY") < 0 || rawText.IndexOf("\r\n") < 0)
{
return null;
}
// NAME1 and NAME2 have specific uses, namely written name and pronunciation, respectively.
// Therefore we treat them specially instead of as an array of names.
var name = matchSinglePrefixedField("NAME1:", rawText, '\r', true);
var pronunciation = matchSinglePrefixedField("NAME2:", rawText, '\r', true);
var phoneNumbers = matchMultipleValuePrefix("TEL", rawText);
var emails = matchMultipleValuePrefix("MAIL", rawText);
var note = matchSinglePrefixedField("MEMORY:", rawText, '\r', false);
var address = matchSinglePrefixedField("ADD:", rawText, '\r', true);
var addresses = address == null ? null : new[] { address };
return new AddressBookParsedResult(maybeWrap(name),
null,
pronunciation,
phoneNumbers,
null,
emails,
null,
null,
note,
addresses,
null,
null,
null,
null,
null,
null);
}
private static String[] matchMultipleValuePrefix(String prefix, String rawText)
{
IList<string> values = null;
// For now, always 3, and always trim
for (int i = 1; i <= 3; i++)
{
var value = matchSinglePrefixedField(prefix + i + ':', rawText, '\r', true);
if (value == null)
{
break;
}
if (values == null)
{
values = new List<string>();
}
values.Add(value);
}
if (values == null)
{
return null;
}
return SupportClass.toStringArray(values);
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary> Implements the "MECARD" address book entry format.
///
/// Supported keys: N, SOUND, TEL, EMAIL, NOTE, ADR, BDAY, URL, plus ORG
/// Unsupported keys: TEL-AV, NICKNAME
///
/// Except for TEL, multiple values for keys are also not supported;
/// the first one found takes precedence.
///
/// Our understanding of the MECARD format is based on this document:
///
/// http://www.mobicode.org.tw/files/OMIA%20Mobile%20Bar%20Code%20Standard%20v3.2.1.doc
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class AddressBookDoCoMoResultParser : AbstractDoCoMoResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null || !rawText.StartsWith("MECARD:"))
{
return null;
}
String[] rawName = matchDoCoMoPrefixedField("N:", rawText);
if (rawName == null)
{
return null;
}
String name = parseName(rawName[0]);
String pronunciation = matchSingleDoCoMoPrefixedField("SOUND:", rawText, true);
String[] phoneNumbers = matchDoCoMoPrefixedField("TEL:", rawText);
String[] emails = matchDoCoMoPrefixedField("EMAIL:", rawText);
String note = matchSingleDoCoMoPrefixedField("NOTE:", rawText, false);
String[] addresses = matchDoCoMoPrefixedField("ADR:", rawText);
String birthday = matchSingleDoCoMoPrefixedField("BDAY:", rawText, true);
if (!isStringOfDigits(birthday, 8))
{
// No reason to throw out the whole card because the birthday is formatted wrong.
birthday = null;
}
String[] urls = matchDoCoMoPrefixedField("URL:", rawText);
// Although ORG may not be strictly legal in MECARD, it does exist in VCARD and we might as well
// honor it when found in the wild.
String org = matchSingleDoCoMoPrefixedField("ORG:", rawText, true);
return new AddressBookParsedResult(maybeWrap(name),
null,
pronunciation,
phoneNumbers,
null,
emails,
null,
null,
note,
addresses,
null,
org,
birthday,
null,
urls,
null);
}
private static String parseName(String name)
{
int comma = name.IndexOf(',');
if (comma >= 0)
{
// Format may be last,first; switch it around
return name.Substring(comma + 1) + ' ' + name.Substring(0, comma);
}
return name;
}
}
}

View File

@@ -0,0 +1,293 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes contact information, like that in an address book entry.
/// </summary>
/// <author>Sean Owen</author>
public sealed class AddressBookParsedResult : ParsedResult
{
private readonly String[] names;
private readonly String[] nicknames;
private readonly String pronunciation;
private readonly String[] phoneNumbers;
private readonly String[] phoneTypes;
private readonly String[] emails;
private readonly String[] emailTypes;
private readonly String instantMessenger;
private readonly String note;
private readonly String[] addresses;
private readonly String[] addressTypes;
private readonly String org;
private readonly String birthday;
private readonly String title;
private readonly String[] urls;
private readonly String[] geo;
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="names"></param>
/// <param name="phoneNumbers"></param>
/// <param name="phoneTypes"></param>
/// <param name="emails"></param>
/// <param name="emailTypes"></param>
/// <param name="addresses"></param>
/// <param name="addressTypes"></param>
public AddressBookParsedResult(String[] names,
String[] phoneNumbers,
String[] phoneTypes,
String[] emails,
String[] emailTypes,
String[] addresses,
String[] addressTypes)
: this(names,
null,
null,
phoneNumbers,
phoneTypes,
emails,
emailTypes,
null,
null,
addresses,
addressTypes,
null,
null,
null,
null,
null)
{
}
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="names"></param>
/// <param name="nicknames"></param>
/// <param name="pronunciation"></param>
/// <param name="phoneNumbers"></param>
/// <param name="phoneTypes"></param>
/// <param name="emails"></param>
/// <param name="emailTypes"></param>
/// <param name="instantMessenger"></param>
/// <param name="note"></param>
/// <param name="addresses"></param>
/// <param name="addressTypes"></param>
/// <param name="org"></param>
/// <param name="birthday"></param>
/// <param name="title"></param>
/// <param name="urls"></param>
/// <param name="geo"></param>
public AddressBookParsedResult(String[] names,
String[] nicknames,
String pronunciation,
String[] phoneNumbers,
String[] phoneTypes,
String[] emails,
String[] emailTypes,
String instantMessenger,
String note,
String[] addresses,
String[] addressTypes,
String org,
String birthday,
String title,
String[] urls,
String[] geo)
: base(ParsedResultType.ADDRESSBOOK)
{
if (phoneNumbers != null && phoneTypes != null && phoneNumbers.Length != phoneTypes.Length)
{
throw new ArgumentException("Phone numbers and types lengths differ");
}
if (emails != null && emailTypes != null && emails.Length != emailTypes.Length)
{
throw new ArgumentException("Emails and types lengths differ");
}
if (addresses != null && addressTypes != null && addresses.Length != addressTypes.Length)
{
throw new ArgumentException("Addresses and types lengths differ");
}
this.names = names;
this.nicknames = nicknames;
this.pronunciation = pronunciation;
this.phoneNumbers = phoneNumbers;
this.phoneTypes = phoneTypes;
this.emails = emails;
this.emailTypes = emailTypes;
this.instantMessenger = instantMessenger;
this.note = note;
this.addresses = addresses;
this.addressTypes = addressTypes;
this.org = org;
this.birthday = birthday;
this.title = title;
this.urls = urls;
this.geo = geo;
displayResultValue = getDisplayResult();
}
/// <summary>
/// the names
/// </summary>
public String[] Names
{
get { return names; }
}
/// <summary>
/// the nicknames
/// </summary>
public String[] Nicknames
{
get { return nicknames; }
}
/// <summary>
/// In Japanese, the name is written in kanji, which can have multiple readings. Therefore a hint
/// is often provided, called furigana, which spells the name phonetically.
/// </summary>
/// <return>The pronunciation of the getNames() field, often in hiragana or katakana.</return>
public String Pronunciation
{
get { return pronunciation; }
}
/// <summary>
/// the phone numbers
/// </summary>
public String[] PhoneNumbers
{
get { return phoneNumbers; }
}
/// <return>optional descriptions of the type of each phone number. It could be like "HOME", but,
/// there is no guaranteed or standard format.</return>
public String[] PhoneTypes
{
get { return phoneTypes; }
}
/// <summary>
/// the e-mail addresses
/// </summary>
public String[] Emails
{
get { return emails; }
}
/// <return>optional descriptions of the type of each e-mail. It could be like "WORK", but,
/// there is no guaranteed or standard format.</return>
public String[] EmailTypes
{
get { return emailTypes; }
}
/// <summary>
/// the instant messenger addresses
/// </summary>
public String InstantMessenger
{
get { return instantMessenger; }
}
/// <summary>
/// the note field
/// </summary>
public String Note
{
get { return note; }
}
/// <summary>
/// the addresses
/// </summary>
public String[] Addresses
{
get { return addresses; }
}
/// <return>optional descriptions of the type of each e-mail. It could be like "WORK", but,
/// there is no guaranteed or standard format.</return>
public String[] AddressTypes
{
get { return addressTypes; }
}
/// <summary>
/// the title
/// </summary>
public String Title
{
get { return title; }
}
/// <summary>
/// the organisations
/// </summary>
public String Org
{
get { return org; }
}
/// <summary>
/// the urls
/// </summary>
public String[] URLs
{
get { return urls; }
}
/// <return>birthday formatted as yyyyMMdd (e.g. 19780917)</return>
public String Birthday
{
get { return birthday; }
}
/// <return>a location as a latitude/longitude pair</return>
public String[] Geo
{
get { return geo; }
}
private String getDisplayResult()
{
var result = new StringBuilder(100);
maybeAppend(names, result);
maybeAppend(nicknames, result);
maybeAppend(pronunciation, result);
maybeAppend(title, result);
maybeAppend(org, result);
maybeAppend(addresses, result);
maybeAppend(phoneNumbers, result);
maybeAppend(emails, result);
maybeAppend(instantMessenger, result);
maybeAppend(urls, result);
maybeAppend(birthday, result);
maybeAppend(geo, result);
maybeAppend(note, result);
return result.ToString();
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing.Client.Result
{
/// <summary> Implements the "BIZCARD" address book entry format, though this has been
/// largely reverse-engineered from examples observed in the wild -- still
/// looking for a definitive reference.
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class BizcardResultParser : AbstractDoCoMoResultParser
{
// Yes, we extend AbstractDoCoMoResultParser since the format is very much
// like the DoCoMo MECARD format, but this is not technically one of
// DoCoMo's proposed formats
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null || !rawText.StartsWith("BIZCARD:"))
{
return null;
}
String firstName = matchSingleDoCoMoPrefixedField("N:", rawText, true);
String lastName = matchSingleDoCoMoPrefixedField("X:", rawText, true);
String fullName = buildName(firstName, lastName);
String title = matchSingleDoCoMoPrefixedField("T:", rawText, true);
String org = matchSingleDoCoMoPrefixedField("C:", rawText, true);
String[] addresses = matchDoCoMoPrefixedField("A:", rawText);
String phoneNumber1 = matchSingleDoCoMoPrefixedField("B:", rawText, true);
String phoneNumber2 = matchSingleDoCoMoPrefixedField("M:", rawText, true);
String phoneNumber3 = matchSingleDoCoMoPrefixedField("F:", rawText, true);
String email = matchSingleDoCoMoPrefixedField("E:", rawText, true);
return new AddressBookParsedResult(maybeWrap(fullName),
null,
null,
buildPhoneNumbers(phoneNumber1, phoneNumber2, phoneNumber3),
null,
maybeWrap(email),
null,
null,
null,
addresses,
null,
org,
null,
title,
null,
null);
}
private static String[] buildPhoneNumbers(String number1, String number2, String number3)
{
var numbers = new List<string>();
if (number1 != null)
{
numbers.Add(number1);
}
if (number2 != null)
{
numbers.Add(number2);
}
if (number3 != null)
{
numbers.Add(number3);
}
var size = numbers.Count;
if (size == 0)
{
return null;
}
return SupportClass.toStringArray(numbers);
}
private static String buildName(String firstName, String lastName)
{
if (firstName == null)
{
return lastName;
}
return lastName == null ? firstName : firstName + ' ' + lastName;
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class BookmarkDoCoMoResultParser : AbstractDoCoMoResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null || !rawText.StartsWith("MEBKM:"))
{
return null;
}
String title = matchSingleDoCoMoPrefixedField("TITLE:", rawText, true);
String[] rawUri = matchDoCoMoPrefixedField("URL:", rawText);
if (rawUri == null)
{
return null;
}
String uri = rawUri[0];
if (!URIResultParser.isBasicallyValidURI(uri))
{
return null;
}
return new URIParsedResult(uri, title);
}
}
}

View File

@@ -0,0 +1,300 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes a calendar event at a certain time, optionally with attendees and a location.
/// </summary>
///<author>Sean Owen</author>
public sealed class CalendarParsedResult : ParsedResult
{
private static readonly Regex RFC2445_DURATION =
new Regex(@"\A(?:" + "P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?" + @")\z"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
private static readonly long[] RFC2445_DURATION_FIELD_UNITS =
{
7*24*60*60*1000L, // 1 week
24*60*60*1000L, // 1 day
60*60*1000L, // 1 hour
60*1000L, // 1 minute
1000L, // 1 second
};
private static readonly Regex DATE_TIME = new Regex(@"\A(?:" + "[0-9]{8}(T[0-9]{6}Z?)?" + @")\z"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
private readonly String summary;
private readonly DateTime start;
private readonly bool startAllDay;
private readonly DateTime? end;
private readonly bool endAllDay;
private readonly String location;
private readonly String organizer;
private readonly String[] attendees;
private readonly String description;
private readonly double latitude;
private readonly double longitude;
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="summary"></param>
/// <param name="startString"></param>
/// <param name="endString"></param>
/// <param name="durationString"></param>
/// <param name="location"></param>
/// <param name="organizer"></param>
/// <param name="attendees"></param>
/// <param name="description"></param>
/// <param name="latitude"></param>
/// <param name="longitude"></param>
public CalendarParsedResult(String summary,
String startString,
String endString,
String durationString,
String location,
String organizer,
String[] attendees,
String description,
double latitude,
double longitude)
: base(ParsedResultType.CALENDAR)
{
this.summary = summary;
try
{
this.start = parseDate(startString);
}
catch (Exception pe)
{
throw new ArgumentException(pe.ToString());
}
if (endString == null)
{
long durationMS = parseDurationMS(durationString);
end = durationMS < 0L ? null : (DateTime?)start + new TimeSpan(0, 0, 0, 0, (int)durationMS);
}
else
{
try
{
this.end = parseDate(endString);
}
catch (Exception pe)
{
throw new ArgumentException(pe.ToString());
}
}
this.startAllDay = startString.Length == 8;
this.endAllDay = endString != null && endString.Length == 8;
this.location = location;
this.organizer = organizer;
this.attendees = attendees;
this.description = description;
this.latitude = latitude;
this.longitude = longitude;
var result = new StringBuilder(100);
maybeAppend(summary, result);
maybeAppend(format(startAllDay, start), result);
maybeAppend(format(endAllDay, end), result);
maybeAppend(location, result);
maybeAppend(organizer, result);
maybeAppend(attendees, result);
maybeAppend(description, result);
displayResultValue = result.ToString();
}
/// <summary>
/// summary
/// </summary>
public String Summary
{
get { return summary; }
}
/// <summary>
/// Gets the start.
/// </summary>
public DateTime Start
{
get { return start; }
}
/// <summary>
/// Determines whether [is start all day].
/// </summary>
/// <returns>if start time was specified as a whole day</returns>
public bool isStartAllDay()
{
return startAllDay;
}
/// <summary>
/// event end <see cref="DateTime"/>, or null if event has no duration
/// </summary>
public DateTime? End
{
get { return end; }
}
/// <summary>
/// Gets a value indicating whether this instance is end all day.
/// </summary>
/// <value>true if end time was specified as a whole day</value>
public bool isEndAllDay
{
get { return endAllDay; }
}
/// <summary>
/// location
/// </summary>
public String Location
{
get { return location; }
}
/// <summary>
/// organizer
/// </summary>
public String Organizer
{
get { return organizer; }
}
/// <summary>
/// attendees
/// </summary>
public String[] Attendees
{
get { return attendees; }
}
/// <summary>
/// description
/// </summary>
public String Description
{
get { return description; }
}
/// <summary>
/// latitude
/// </summary>
public double Latitude
{
get { return latitude; }
}
/// <summary>
/// longitude
/// </summary>
public double Longitude
{
get { return longitude; }
}
/// <summary>
/// Parses a string as a date. RFC 2445 allows the start and end fields to be of type DATE (e.g. 20081021)
/// or DATE-TIME (e.g. 20081021T123000 for local time, or 20081021T123000Z for UTC).
/// </summary>
/// <param name="when">The string to parse</param>
/// <returns></returns>
/// <exception cref="ArgumentException">if not a date formatted string</exception>
private static DateTime parseDate(String when)
{
if (!DATE_TIME.Match(when).Success)
{
throw new ArgumentException(String.Format("no date format: {0}", when));
}
if (when.Length == 8)
{
// Show only year/month/day
// For dates without a time, for purposes of interacting with Android, the resulting timestamp
// needs to be midnight of that day in GMT. See:
// http://code.google.com/p/android/issues/detail?id=8330
// format.setTimeZone(TimeZone.getTimeZone("GMT"));
return DateTime.ParseExact(when, "yyyyMMdd", CultureInfo.InvariantCulture);
}
// The when string can be local time, or UTC if it ends with a Z
if (when.Length == 16 && when[15] == 'Z')
{
var milliseconds = parseDateTimeString(when.Substring(0, 15));
//Calendar calendar = new GregorianCalendar();
// Account for time zone difference
//milliseconds += calendar.get(Calendar.ZONE_OFFSET);
// Might need to correct for daylight savings time, but use target time since
// now might be in DST but not then, or vice versa
//calendar.setTime(new Date(milliseconds));
//return milliseconds + calendar.get(Calendar.DST_OFFSET);
milliseconds = TimeZoneInfo.ConvertTime(milliseconds, TimeZoneInfo.Local);
return milliseconds;
}
return parseDateTimeString(when);
}
private static String format(bool allDay, DateTime? date)
{
if (date == null)
{
return null;
}
if (allDay)
return date.Value.ToString("D", CultureInfo.CurrentCulture);
return date.Value.ToString("F", CultureInfo.CurrentCulture);
}
private static long parseDurationMS(String durationString)
{
if (durationString == null)
{
return -1L;
}
var m = RFC2445_DURATION.Match(durationString);
if (!m.Success)
{
return -1L;
}
long durationMS = 0L;
for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.Length; i++)
{
String fieldValue = m.Groups[i + 1].Value;
if (!String.IsNullOrEmpty(fieldValue))
{
durationMS += RFC2445_DURATION_FIELD_UNITS[i] * Int32.Parse(fieldValue);
}
}
return durationMS;
}
private static DateTime parseDateTimeString(String dateTimeString)
{
return DateTime.ParseExact(dateTimeString, "yyyyMMdd'T'HHmmss", CultureInfo.InvariantCulture);
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes an email message including recipients, subject and body text.
/// </summary>
/// <author>Sean Owen</author>
public sealed class EmailAddressParsedResult : ParsedResult
{
/// <summary>
/// the email address
/// </summary>
public String EmailAddress
{
get
{
return Tos == null || Tos.Length == 0 ? null : Tos[0];
}
}
/// <summary>
/// the TOs
/// </summary>
public String[] Tos { get; private set; }
/// <summary>
/// the CCs
/// </summary>
public String[] CCs { get; private set; }
/// <summary>
/// the BCCs
/// </summary>
public String[] BCCs { get; private set; }
/// <summary>
/// the subject
/// </summary>
public String Subject { get; private set; }
/// <summary>
/// the body
/// </summary>
public String Body { get; private set; }
/// <summary>
/// the mailto: uri
/// </summary>
[Obsolete("deprecated without replacement")]
public String MailtoURI { get { return "mailto:"; } }
internal EmailAddressParsedResult(String to)
: this(new[] { to }, null, null, null, null)
{
}
internal EmailAddressParsedResult(String[] tos,
String[] ccs,
String[] bccs,
String subject,
String body)
: base(ParsedResultType.EMAIL_ADDRESS)
{
Tos = tos;
CCs = ccs;
BCCs = bccs;
Subject = subject;
Body = body;
var result = new StringBuilder(30);
maybeAppend(Tos, result);
maybeAppend(CCs, result);
maybeAppend(BCCs, result);
maybeAppend(Subject, result);
maybeAppend(Body, result);
displayResultValue = result.ToString();
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a result that encodes an e-mail address, either as a plain address
/// like "joe@example.org" or a mailto: URL like "mailto:joe@example.org".
/// </summary>
/// <author>Sean Owen</author>
internal sealed class EmailAddressResultParser : ResultParser
{
private static readonly Regex COMMA = new Regex(","
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
public override ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null)
{
return null;
}
if (rawText.ToLower().StartsWith("mailto:"))
{
// If it starts with mailto:, assume it is definitely trying to be an email address
String hostEmail = rawText.Substring(7);
int queryStart = hostEmail.IndexOf('?');
if (queryStart >= 0)
{
hostEmail = hostEmail.Substring(0, queryStart);
}
hostEmail = urlDecode(hostEmail);
String[] tos = null;
if (!String.IsNullOrEmpty(hostEmail))
{
tos = COMMA.Split(hostEmail);
}
var nameValues = parseNameValuePairs(rawText);
String[] ccs = null;
String[] bccs = null;
String subject = null;
String body = null;
if (nameValues != null)
{
if (tos == null)
{
String tosString;
if (nameValues.TryGetValue("to", out tosString) && tosString != null)
{
tos = COMMA.Split(tosString);
}
}
String ccString;
if (nameValues.TryGetValue("cc", out ccString) && ccString != null)
{
ccs = COMMA.Split(ccString);
}
String bccString;
if (nameValues.TryGetValue("bcc", out bccString) && bccString != null)
{
bccs = COMMA.Split(bccString);
}
nameValues.TryGetValue("subject", out subject);
nameValues.TryGetValue("body", out body);
}
return new EmailAddressParsedResult(tos, ccs, bccs, subject, body);
}
if (!EmailDoCoMoResultParser.isBasicallyValidEmailAddress(rawText))
{
return null;
}
return new EmailAddressParsedResult(rawText);
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary>
/// Implements the "MATMSG" email message entry format.
///
/// Supported keys: TO, SUB, BODY
/// </summary>
/// <author>Sean Owen</author>
internal sealed class EmailDoCoMoResultParser : AbstractDoCoMoResultParser
{
private static readonly Regex ATEXT_ALPHANUMERIC = new Regex(@"\A(?:" + "[a-zA-Z0-9@.!#$%&'*+\\-/=?^_`{|}~]+" + @")\z"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
public override ParsedResult parse(ZXing.Result result)
{
var rawText = result.Text;
if (!rawText.StartsWith("MATMSG:"))
{
return null;
}
var tos = matchDoCoMoPrefixedField("TO:", rawText);
if (tos == null)
{
return null;
}
for (var index = 0; index < tos.Length; index++)
{
var to = tos[index];
if (!isBasicallyValidEmailAddress(to))
{
return null;
}
}
var subject = matchSingleDoCoMoPrefixedField("SUB:", rawText, false);
var body = matchSingleDoCoMoPrefixedField("BODY:", rawText, false);
return new EmailAddressParsedResult(tos, null, null, subject, body);
}
/// <summary>
/// This implements only the most basic checking for an email address's validity -- that it contains
/// an '@' and contains no characters disallowed by RFC 2822. This is an overly lenient definition of
/// validity. We want to generally be lenient here since this class is only intended to encapsulate what's
/// in a barcode, not "judge" it.
/// </summary>
/// <param name="email">The email.</param>
/// <returns>
/// <c>true</c> if it is basically a valid email address; otherwise, <c>false</c>.
/// </returns>
internal static bool isBasicallyValidEmailAddress(String email)
{
return email != null && ATEXT_ALPHANUMERIC.Match(email).Success && email.IndexOf('@') >= 0;
}
}
}

View File

@@ -0,0 +1,328 @@
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
using System;
using System.Collections.Generic;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes extended product information as encoded by the RSS format, like weight, price, dates, etc.
/// </summary>
/// <author> Antonio Manuel Benjumea Conde, Servinform, S.A.</author>
/// <author> Agustín Delgado, Servinform, S.A.</author>
public class ExpandedProductParsedResult : ParsedResult
{
/// <summary>
/// extension for kilogram weight type
/// </summary>
public static String KILOGRAM = "KG";
/// <summary>
/// extension for pounds weight type
/// </summary>
public static String POUND = "LB";
private readonly String rawText;
private readonly String productID;
private readonly String sscc;
private readonly String lotNumber;
private readonly String productionDate;
private readonly String packagingDate;
private readonly String bestBeforeDate;
private readonly String expirationDate;
private readonly String weight;
private readonly String weightType;
private readonly String weightIncrement;
private readonly String price;
private readonly String priceIncrement;
private readonly String priceCurrency;
// For AIS that not exist in this object
private readonly IDictionary<String, String> uncommonAIs;
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="rawText"></param>
/// <param name="productID"></param>
/// <param name="sscc"></param>
/// <param name="lotNumber"></param>
/// <param name="productionDate"></param>
/// <param name="packagingDate"></param>
/// <param name="bestBeforeDate"></param>
/// <param name="expirationDate"></param>
/// <param name="weight"></param>
/// <param name="weightType"></param>
/// <param name="weightIncrement"></param>
/// <param name="price"></param>
/// <param name="priceIncrement"></param>
/// <param name="priceCurrency"></param>
/// <param name="uncommonAIs"></param>
public ExpandedProductParsedResult(String rawText,
String productID,
String sscc,
String lotNumber,
String productionDate,
String packagingDate,
String bestBeforeDate,
String expirationDate,
String weight,
String weightType,
String weightIncrement,
String price,
String priceIncrement,
String priceCurrency,
IDictionary<String, String> uncommonAIs)
: base(ParsedResultType.PRODUCT)
{
this.rawText = rawText;
this.productID = productID;
this.sscc = sscc;
this.lotNumber = lotNumber;
this.productionDate = productionDate;
this.packagingDate = packagingDate;
this.bestBeforeDate = bestBeforeDate;
this.expirationDate = expirationDate;
this.weight = weight;
this.weightType = weightType;
this.weightIncrement = weightIncrement;
this.price = price;
this.priceIncrement = priceIncrement;
this.priceCurrency = priceCurrency;
this.uncommonAIs = uncommonAIs;
displayResultValue = productID;
}
/// <summary>
///
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
public override bool Equals(Object o)
{
if (!(o is ExpandedProductParsedResult))
{
return false;
}
var other = (ExpandedProductParsedResult)o;
return equalsOrNull(productID, other.productID)
&& equalsOrNull(sscc, other.sscc)
&& equalsOrNull(lotNumber, other.lotNumber)
&& equalsOrNull(productionDate, other.productionDate)
&& equalsOrNull(bestBeforeDate, other.bestBeforeDate)
&& equalsOrNull(expirationDate, other.expirationDate)
&& equalsOrNull(weight, other.weight)
&& equalsOrNull(weightType, other.weightType)
&& equalsOrNull(weightIncrement, other.weightIncrement)
&& equalsOrNull(price, other.price)
&& equalsOrNull(priceIncrement, other.priceIncrement)
&& equalsOrNull(priceCurrency, other.priceCurrency)
&& equalsOrNull(uncommonAIs, other.uncommonAIs);
}
private static bool equalsOrNull(Object o1, Object o2)
{
return o1 == null ? o2 == null : o1.Equals(o2);
}
private static bool equalsOrNull(IDictionary<String, String> o1, IDictionary<String, String> o2)
{
if (o1 == null)
return o2 == null;
if (o1.Count != o2.Count)
return false;
foreach (var entry in o1)
{
if (!o2.ContainsKey(entry.Key))
return false;
if (!entry.Value.Equals(o2[entry.Key]))
return false;
}
return true;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
int hash = 0;
hash ^= hashNotNull(productID);
hash ^= hashNotNull(sscc);
hash ^= hashNotNull(lotNumber);
hash ^= hashNotNull(productionDate);
hash ^= hashNotNull(bestBeforeDate);
hash ^= hashNotNull(expirationDate);
hash ^= hashNotNull(weight);
hash ^= hashNotNull(weightType);
hash ^= hashNotNull(weightIncrement);
hash ^= hashNotNull(price);
hash ^= hashNotNull(priceIncrement);
hash ^= hashNotNull(priceCurrency);
hash ^= hashNotNull(uncommonAIs);
return hash;
}
private static int hashNotNull(Object o)
{
return o == null ? 0 : o.GetHashCode();
}
/// <summary>
/// the raw text
/// </summary>
public String RawText
{
get { return rawText; }
}
/// <summary>
/// the product id
/// </summary>
public String ProductID
{
get { return productID; }
}
/// <summary>
/// the sscc
/// </summary>
public String Sscc
{
get { return sscc; }
}
/// <summary>
/// the lot number
/// </summary>
public String LotNumber
{
get { return lotNumber; }
}
/// <summary>
/// the production date
/// </summary>
public String ProductionDate
{
get { return productionDate; }
}
/// <summary>
/// the packaging date
/// </summary>
public String PackagingDate
{
get { return packagingDate; }
}
/// <summary>
/// the best before date
/// </summary>
public String BestBeforeDate
{
get { return bestBeforeDate; }
}
/// <summary>
/// the expiration date
/// </summary>
public String ExpirationDate
{
get { return expirationDate; }
}
/// <summary>
/// the weight
/// </summary>
public String Weight
{
get { return weight; }
}
/// <summary>
/// the weight type
/// </summary>
public String WeightType
{
get { return weightType; }
}
/// <summary>
/// the weight increment
/// </summary>
public String WeightIncrement
{
get { return weightIncrement; }
}
/// <summary>
/// the price
/// </summary>
public String Price
{
get { return price; }
}
/// <summary>
/// the price increment
/// </summary>
public String PriceIncrement
{
get { return priceIncrement; }
}
/// <summary>
/// the price currency
/// </summary>
public String PriceCurrency
{
get { return priceCurrency; }
}
/// <summary>
/// the uncommon AIs
/// </summary>
public IDictionary<String, String> UncommonAIs
{
get { return uncommonAIs; }
}
/// <summary>
/// the display representation (raw text)
/// </summary>
public override string DisplayResult
{
get
{
return rawText;
}
}
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Parses strings of digits that represent a RSS Extended code.
/// </summary>
/// <author>Antonio Manuel Benjumea Conde, Servinform, S.A.</author>
/// <author>Agustín Delgado, Servinform, S.A.</author>
public class ExpandedProductResultParser : ResultParser
{
/// <summary>
/// tries to parse a text representation to a specific result object
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public override ParsedResult parse(ZXing.Result result)
{
BarcodeFormat format = result.BarcodeFormat;
if (format != BarcodeFormat.RSS_EXPANDED)
{
// ExtendedProductParsedResult NOT created. Not a RSS Expanded barcode
return null;
}
String rawText = result.Text;
String productID = null;
String sscc = null;
String lotNumber = null;
String productionDate = null;
String packagingDate = null;
String bestBeforeDate = null;
String expirationDate = null;
String weight = null;
String weightType = null;
String weightIncrement = null;
String price = null;
String priceIncrement = null;
String priceCurrency = null;
var uncommonAIs = new Dictionary<String, String>();
int i = 0;
while (i < rawText.Length)
{
String ai = findAIvalue(i, rawText);
if (ai == null)
{
// Error. Code doesn't match with RSS expanded pattern
// ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern
return null;
}
i += ai.Length + 2;
String value = findValue(i, rawText);
i += value.Length;
if ("00".Equals(ai))
{
sscc = value;
}
else if ("01".Equals(ai))
{
productID = value;
}
else if ("10".Equals(ai))
{
lotNumber = value;
}
else if ("11".Equals(ai))
{
productionDate = value;
}
else if ("13".Equals(ai))
{
packagingDate = value;
}
else if ("15".Equals(ai))
{
bestBeforeDate = value;
}
else if ("17".Equals(ai))
{
expirationDate = value;
}
else if ("3100".Equals(ai) || "3101".Equals(ai)
|| "3102".Equals(ai) || "3103".Equals(ai)
|| "3104".Equals(ai) || "3105".Equals(ai)
|| "3106".Equals(ai) || "3107".Equals(ai)
|| "3108".Equals(ai) || "3109".Equals(ai))
{
weight = value;
weightType = ExpandedProductParsedResult.KILOGRAM;
weightIncrement = ai.Substring(3);
}
else if ("3200".Equals(ai) || "3201".Equals(ai)
|| "3202".Equals(ai) || "3203".Equals(ai)
|| "3204".Equals(ai) || "3205".Equals(ai)
|| "3206".Equals(ai) || "3207".Equals(ai)
|| "3208".Equals(ai) || "3209".Equals(ai))
{
weight = value;
weightType = ExpandedProductParsedResult.POUND;
weightIncrement = ai.Substring(3);
}
else if ("3920".Equals(ai) || "3921".Equals(ai)
|| "3922".Equals(ai) || "3923".Equals(ai))
{
price = value;
priceIncrement = ai.Substring(3);
}
else if ("3930".Equals(ai) || "3931".Equals(ai)
|| "3932".Equals(ai) || "3933".Equals(ai))
{
if (value.Length < 4)
{
// The value must have more of 3 symbols (3 for currency and
// 1 at least for the price)
// ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern
return null;
}
price = value.Substring(3);
priceCurrency = value.Substring(0, 3);
priceIncrement = ai.Substring(3);
}
else
{
// No match with common AIs
uncommonAIs[ai] = value;
}
}
return new ExpandedProductParsedResult(rawText,
productID,
sscc,
lotNumber,
productionDate,
packagingDate,
bestBeforeDate,
expirationDate,
weight,
weightType,
weightIncrement,
price,
priceIncrement,
priceCurrency,
uncommonAIs);
}
private static String findAIvalue(int i, String rawText)
{
char c = rawText[i];
// First character must be a open parenthesis.If not, ERROR
if (c != '(')
{
return null;
}
var rawTextAux = rawText.Substring(i + 1);
var buf = new StringBuilder();
for (int index = 0; index < rawTextAux.Length; index++)
{
char currentChar = rawTextAux[index];
if (currentChar == ')')
{
return buf.ToString();
}
if (currentChar < '0' || currentChar > '9')
{
return null;
}
buf.Append(currentChar);
}
return buf.ToString();
}
private static String findValue(int i, String rawText)
{
var buf = new StringBuilder();
var rawTextAux = rawText.Substring(i);
for (int index = 0; index < rawTextAux.Length; index++)
{
char c = rawTextAux[index];
if (c == '(')
{
// We look for a new AI. If it doesn't exist (ERROR), we continue
// with the iteration
if (findAIvalue(index, rawTextAux) != null)
{
break;
}
buf.Append('(');
}
else
{
buf.Append(c);
}
}
return buf.ToString();
}
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes a geographic coordinate, with latitude, longitude and altitude.
/// </summary>
/// <author>Sean Owen</author>
public sealed class GeoParsedResult : ParsedResult
{
internal GeoParsedResult(double latitude, double longitude, double altitude, String query)
: base(ParsedResultType.GEO)
{
Latitude = latitude;
Longitude = longitude;
Altitude = altitude;
Query = query;
GeoURI = getGeoURI();
GoogleMapsURI = getGoogleMapsURI();
displayResultValue = getDisplayResult();
}
/// <returns> latitude in degrees
/// </returns>
public double Latitude { get; private set; }
/// <returns> longitude in degrees
/// </returns>
public double Longitude { get; private set; }
/// <returns> altitude in meters. If not specified, in the geo URI, returns 0.0
/// </returns>
public double Altitude { get; private set; }
/// <return> query string associated with geo URI or null if none exists</return>
public String Query { get; private set; }
/// <summary>
/// the geo URI
/// </summary>
public String GeoURI { get; private set; }
/// <returns> a URI link to Google Maps which display the point on the Earth described
/// by this instance, and sets the zoom level in a way that roughly reflects the
/// altitude, if specified
/// </returns>
public String GoogleMapsURI { get; private set; }
private String getDisplayResult()
{
var result = new StringBuilder(20);
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Latitude);
result.Append(", ");
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Longitude);
if (Altitude > 0.0)
{
result.Append(", ");
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Altitude);
result.Append('m');
}
if (Query != null)
{
result.Append(" (");
result.Append(Query);
result.Append(')');
}
return result.ToString();
}
private String getGeoURI()
{
var result = new StringBuilder();
result.Append("geo:");
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Latitude);
result.Append(',');
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Longitude);
if (Altitude > 0)
{
result.Append(',');
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Altitude);
}
if (Query != null)
{
result.Append('?');
result.Append(Query);
}
return result.ToString();
}
private String getGoogleMapsURI()
{
var result = new StringBuilder(50);
result.Append("http://maps.google.com/?ll=");
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Latitude);
result.Append(',');
result.AppendFormat(CultureInfo.InvariantCulture, "{0:0.0###########}", Longitude);
if (Altitude > 0.0f)
{
// Map altitude to zoom level, cleverly. Roughly, zoom level 19 is like a
// view from 1000ft, 18 is like 2000ft, 17 like 4000ft, and so on.
double altitudeInFeet = Altitude * 3.28;
int altitudeInKFeet = (int)(altitudeInFeet / 1000.0);
// No Math.log() available here, so compute log base 2 the old fashioned way
// Here logBaseTwo will take on a value between 0 and 18 actually
int logBaseTwo = 0;
while (altitudeInKFeet > 1 && logBaseTwo < 18)
{
altitudeInKFeet >>= 1;
logBaseTwo++;
}
int zoom = 19 - logBaseTwo;
result.Append("&z=");
result.Append(zoom);
}
return result.ToString();
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Globalization;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary> Parses a "geo:" URI result, which specifies a location on the surface of
/// the Earth as well as an optional altitude above the surface. See
/// <a href="http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00">
/// http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00</a>.
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class GeoResultParser : ResultParser
{
private static readonly Regex GEO_URL_PATTERN = new Regex(@"\A(?:" + "geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?" + @")\z"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled | RegexOptions.IgnoreCase);
#else
, RegexOptions.IgnoreCase);
#endif
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null)
{
return null;
}
var matcher = GEO_URL_PATTERN.Match(rawText);
if (!matcher.Success)
{
return null;
}
String query = matcher.Groups[4].Value;
if (String.IsNullOrEmpty(query))
query = null;
double latitude;
double longitude;
double altitude = 0.0;
#if WindowsCE
try { latitude = Double.Parse(matcher.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture); }
catch { return null; }
#else
if (!Double.TryParse(matcher.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out latitude))
return null;
#endif
if (latitude > 90.0 || latitude < -90.0)
{
return null;
}
#if WindowsCE
try { longitude = Double.Parse(matcher.Groups[2].Value, NumberStyles.Float, CultureInfo.InvariantCulture); }
catch { return null; }
#else
if (!Double.TryParse(matcher.Groups[2].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out longitude))
return null;
#endif
if (longitude > 180.0 || longitude < -180.0)
{
return null;
}
if (!String.IsNullOrEmpty(matcher.Groups[3].Value))
{
#if WindowsCE
try { altitude = Double.Parse(matcher.Groups[3].Value, NumberStyles.Float, CultureInfo.InvariantCulture); }
catch { return null; }
#else
if (!Double.TryParse(matcher.Groups[3].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out altitude))
return null;
#endif
if (altitude < 0.0)
{
return null;
}
}
return new GeoParsedResult(latitude, longitude, altitude, query);
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes a product ISBN number.
/// </summary>
/// <author>jbreiden@google.com (Jeff Breidenbach)</author>
public sealed class ISBNParsedResult : ParsedResult
{
internal ISBNParsedResult(String isbn)
: base(ParsedResultType.ISBN)
{
ISBN = isbn;
displayResultValue = isbn;
}
/// <summary>
/// the ISBN number
/// </summary>
public String ISBN { get; private set; }
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary> Parses strings of digits that represent a ISBN.
///
/// </summary>
/// <author> jbreiden@google.com (Jeff Breidenbach)
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public class ISBNResultParser : ResultParser
{
/// <summary>
/// See <a href="http://www.bisg.org/isbn-13/for.dummies.html">ISBN-13 For Dummies</a>
/// </summary>
/// <param name="result">The result.</param>
/// <returns></returns>
override public ParsedResult parse(ZXing.Result result)
{
BarcodeFormat format = result.BarcodeFormat;
if (format != BarcodeFormat.EAN_13)
{
return null;
}
String rawText = result.Text;
int length = rawText.Length;
if (length != 13)
{
return null;
}
if (!rawText.StartsWith("978") && !rawText.StartsWith("979"))
{
return null;
}
return new ISBNParsedResult(rawText);
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary> <p>Abstract class representing the result of decoding a barcode, as more than
/// a String -- as some type of structured data. This might be a subclass which represents
/// a URL, or an e-mail address. {@link ResultParser#parseResult(Result)} will turn a raw
/// decoded string into the most appropriate type of structured representation.</p>
///
/// <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
/// on exception-based mechanisms during parsing.</p>
/// </summary>
/// <author>Sean Owen</author>
public abstract class ParsedResult
{
/// <summary>
/// user friendly value
/// </summary>
protected string displayResultValue;
/// <summary>
/// gets the type of the parsed result
/// </summary>
public virtual ParsedResultType Type { get; private set; }
/// <summary>
/// user friendly value
/// </summary>
public virtual String DisplayResult { get { return displayResultValue; } }
/// <summary>
/// constructor
/// </summary>
/// <param name="type"></param>
protected ParsedResult(ParsedResultType type)
{
Type = type;
}
/// <summary>
/// gets a user friendly value
/// </summary>
/// <returns></returns>
public override String ToString()
{
return DisplayResult;
}
/// <summary>
/// compare two objects
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
var other = obj as ParsedResult;
if (other == null)
return false;
return other.Type.Equals(Type) && other.DisplayResult.Equals(DisplayResult);
}
/// <summary>
/// gets the hashcode
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return Type.GetHashCode() + DisplayResult.GetHashCode();
}
/// <summary>
/// append to result if not null or empty
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
public static void maybeAppend(String value, StringBuilder result)
{
if (String.IsNullOrEmpty(value))
return;
// Don't add a newline before the first value
if (result.Length > 0)
{
result.Append('\n');
}
result.Append(value);
}
/// <summary>
/// append to result if not null or empty
/// </summary>
/// <param name="values"></param>
/// <param name="result"></param>
public static void maybeAppend(String[] values, StringBuilder result)
{
if (values != null)
{
foreach (String value in values)
{
maybeAppend(value, result);
}
}
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Client.Result
{
/// <summary>
/// Represents the type of data encoded by a barcode -- from plain text, to a
/// URI, to an e-mail address, etc.
/// </summary>
/// <author>Sean Owen</author>
public enum ParsedResultType
{
/// <summary>
/// address book
/// </summary>
ADDRESSBOOK,
/// <summary>
/// email address
/// </summary>
EMAIL_ADDRESS,
/// <summary>
/// product
/// </summary>
PRODUCT,
/// <summary>
/// URI
/// </summary>
URI,
/// <summary>
/// Text
/// </summary>
TEXT,
/// <summary>
/// geo coordinates
/// </summary>
GEO,
/// <summary>
/// telefon
/// </summary>
TEL,
/// <summary>
/// sms
/// </summary>
SMS,
/// <summary>
/// calendar
/// </summary>
CALENDAR,
/// <summary>
/// wifi
/// </summary>
WIFI,
/// <summary>
/// ISBN
/// </summary>
ISBN,
/// <summary>
/// VIN
/// </summary>
VIN
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes a product by an identifier of some kind.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public sealed class ProductParsedResult : ParsedResult
{
internal ProductParsedResult(String productID)
: this(productID, productID)
{
}
internal ProductParsedResult(String productID, String normalizedProductID)
: base(ParsedResultType.PRODUCT)
{
ProductID = productID;
NormalizedProductID = normalizedProductID;
displayResultValue = productID;
}
/// <summary>
/// product id
/// </summary>
public String ProductID { get; private set; }
/// <summary>
/// normalized product id
/// </summary>
public String NormalizedProductID { get; private set; }
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.OneD;
namespace ZXing.Client.Result
{
/// <summary>
/// Parses strings of digits that represent a UPC code.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
internal sealed class ProductResultParser : ResultParser
{
// Treat all UPC and EAN variants as UPCs, in the sense that they are all product barcodes.
public override ParsedResult parse(ZXing.Result result)
{
BarcodeFormat format = result.BarcodeFormat;
if (!(format == BarcodeFormat.UPC_A || format == BarcodeFormat.UPC_E ||
format == BarcodeFormat.EAN_8 || format == BarcodeFormat.EAN_13))
{
return null;
}
// Really neither of these should happen:
String rawText = result.Text;
if (rawText == null)
{
return null;
}
if (!isStringOfDigits(rawText, rawText.Length))
{
return null;
}
// Not actually checking the checksum again here
String normalizedProductID;
// Expand UPC-E for purposes of searching
if (format == BarcodeFormat.UPC_E && rawText.Length == 8)
{
normalizedProductID = UPCEReader.convertUPCEtoUPCA(rawText);
}
else
{
normalizedProductID = rawText;
}
return new ProductParsedResult(rawText, normalizedProductID);
}
}
}

View File

@@ -0,0 +1,408 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary> <p>Abstract class representing the result of decoding a barcode, as more than
/// a String -- as some type of structured data. This might be a subclass which represents
/// a URL, or an e-mail address. {@link #parseResult(com.google.zxing.Result)} will turn a raw
/// decoded string into the most appropriate type of structured representation.</p>
///
/// <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
/// on exception-based mechanisms during parsing.</p>
/// </summary>
/// <author>Sean Owen</author>
public abstract class ResultParser
{
private static readonly ResultParser[] PARSERS =
{
new BookmarkDoCoMoResultParser(),
new AddressBookDoCoMoResultParser(),
new EmailDoCoMoResultParser(),
new AddressBookAUResultParser(),
new VCardResultParser(),
new BizcardResultParser(),
new VEventResultParser(),
new EmailAddressResultParser(),
new SMTPResultParser(),
new TelResultParser(),
new SMSMMSResultParser(),
new SMSTOMMSTOResultParser(),
new GeoResultParser(),
new WifiResultParser(),
new URLTOResultParser(),
new URIResultParser(),
new ISBNResultParser(),
new ProductResultParser(),
new ExpandedProductResultParser(),
new VINResultParser(),
};
#if SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2
private static readonly Regex DIGITS = new Regex(@"\A(?:" + "\\d+" + @")\z");
private static readonly Regex AMPERSAND = new Regex("&");
private static readonly Regex EQUALS = new Regex("=");
#else
private static readonly Regex DIGITS = new Regex(@"\A(?:" + "\\d+" + @")\z", RegexOptions.Compiled);
private static readonly Regex AMPERSAND = new Regex("&", RegexOptions.Compiled);
private static readonly Regex EQUALS = new Regex("=", RegexOptions.Compiled);
#endif
/// <summary>
/// Attempts to parse the raw {@link Result}'s contents as a particular type
/// of information (email, URL, etc.) and return a {@link ParsedResult} encapsulating
/// the result of parsing.
/// </summary>
/// <param name="theResult">the raw <see cref="Result"/> to parse</param>
/// <returns><see cref="ParsedResult" /> encapsulating the parsing result</returns>
public abstract ParsedResult parse(ZXing.Result theResult);
/// <summary>
/// Parses the result.
/// </summary>
/// <param name="theResult">The result.</param>
/// <returns></returns>
public static ParsedResult parseResult(ZXing.Result theResult)
{
foreach (var parser in PARSERS)
{
var result = parser.parse(theResult);
if (result != null)
{
return result;
}
}
return new TextParsedResult(theResult.Text, null);
}
/// <summary>
/// append value to result, if not null
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
protected static void maybeAppend(String value, System.Text.StringBuilder result)
{
if (value != null)
{
result.Append('\n');
result.Append(value);
}
}
/// <summary>
/// append value to result, if not null
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
protected static void maybeAppend(String[] value, System.Text.StringBuilder result)
{
if (value != null)
{
for (int i = 0; i < value.Length; i++)
{
result.Append('\n');
result.Append(value[i]);
}
}
}
/// <summary>
/// wrap, if not null
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
protected static String[] maybeWrap(String value)
{
return value == null ? null : new[] { value };
}
/// <summary>
/// unescape backslash
/// </summary>
/// <param name="escaped"></param>
/// <returns></returns>
protected static String unescapeBackslash(String escaped)
{
if (escaped != null)
{
int backslash = escaped.IndexOf('\\');
if (backslash >= 0)
{
int max = escaped.Length;
var unescaped = new System.Text.StringBuilder(max - 1);
unescaped.Append(escaped.ToCharArray(), 0, backslash);
bool nextIsEscaped = false;
for (int i = backslash; i < max; i++)
{
char c = escaped[i];
if (nextIsEscaped || c != '\\')
{
unescaped.Append(c);
nextIsEscaped = false;
}
else
{
nextIsEscaped = true;
}
}
return unescaped.ToString();
}
}
return escaped;
}
/// <summary>
/// parse hex digit
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
protected static int parseHexDigit(char c)
{
if (c >= 'a')
{
if (c <= 'f')
{
return 10 + (c - 'a');
}
}
else if (c >= 'A')
{
if (c <= 'F')
{
return 10 + (c - 'A');
}
}
else if (c >= '0')
{
if (c <= '9')
{
return c - '0';
}
}
return -1;
}
internal static bool isStringOfDigits(String value, int length)
{
return value != null && length > 0 && length == value.Length && DIGITS.Match(value).Success;
}
internal static bool isSubstringOfDigits(String value, int offset, int length)
{
if (value == null || length <= 0)
{
return false;
}
int max = offset + length;
return value.Length >= max && DIGITS.Match(value, offset, length).Success;
}
internal static IDictionary<string, string> parseNameValuePairs(String uri)
{
int paramStart = uri.IndexOf('?');
if (paramStart < 0)
{
return null;
}
var result = new Dictionary<String, String>(3);
foreach (var keyValue in AMPERSAND.Split(uri.Substring(paramStart + 1)))
{
appendKeyValue(keyValue, result);
}
return result;
}
private static void appendKeyValue(String keyValue, IDictionary<String, String> result)
{
String[] keyValueTokens = EQUALS.Split(keyValue, 2);
if (keyValueTokens.Length == 2)
{
String key = keyValueTokens[0];
String value = keyValueTokens[1];
try
{
//value = URLDecoder.decode(value, "UTF-8");
value = urlDecode(value);
result[key] = value;
}
catch (Exception uee)
{
throw new InvalidOperationException("url decoding failed", uee); // can't happen
}
result[key] = value;
}
}
internal static String[] matchPrefixedField(String prefix, String rawText, char endChar, bool trim)
{
IList<string> matches = null;
int i = 0;
int max = rawText.Length;
while (i < max)
{
i = rawText.IndexOf(prefix, i);
if (i < 0)
{
break;
}
i += prefix.Length; // Skip past this prefix we found to start
int start = i; // Found the start of a match here
bool done = false;
while (!done)
{
i = rawText.IndexOf(endChar, i);
if (i < 0)
{
// No terminating end character? uh, done. Set i such that loop terminates and break
i = rawText.Length;
done = true;
}
else if (countPrecedingBackslashes(rawText, i) % 2 != 0)
{
// semicolon was escaped (odd count of preceding backslashes) so continue
i++;
}
else
{
// found a match
if (matches == null)
{
matches = new List<string>();
}
String element = unescapeBackslash(rawText.Substring(start, (i) - (start)));
if (trim)
{
element = element.Trim();
}
if (!String.IsNullOrEmpty(element))
{
matches.Add(element);
}
i++;
done = true;
}
}
}
if (matches == null || (matches.Count == 0))
{
return null;
}
return SupportClass.toStringArray(matches);
}
private static int countPrecedingBackslashes(String s, int pos)
{
int count = 0;
for (int i = pos - 1; i >= 0; i--)
{
if (s[i] == '\\')
{
count++;
}
else
{
break;
}
}
return count;
}
internal static String matchSinglePrefixedField(String prefix, String rawText, char endChar, bool trim)
{
String[] matches = matchPrefixedField(prefix, rawText, endChar, trim);
return matches == null ? null : matches[0];
}
/// <summary>
/// decodes url
/// </summary>
/// <param name="escaped"></param>
/// <returns></returns>
protected static String urlDecode(String escaped)
{
// Should we better use HttpUtility.UrlDecode?
// Is HttpUtility.UrlDecode available for all platforms?
// What about encoding like UTF8?
if (escaped == null)
{
return null;
}
char[] escapedArray = escaped.ToCharArray();
int first = findFirstEscape(escapedArray);
if (first < 0)
{
return escaped;
}
int max = escapedArray.Length;
// final length is at most 2 less than original due to at least 1 unescaping
var unescaped = new System.Text.StringBuilder(max - 2);
// Can append everything up to first escape character
unescaped.Append(escapedArray, 0, first);
for (int i = first; i < max; i++)
{
char c = escapedArray[i];
if (c == '+')
{
// + is translated directly into a space
unescaped.Append(' ');
}
else if (c == '%')
{
// Are there even two more chars? if not we will just copy the escaped sequence and be done
if (i >= max - 2)
{
unescaped.Append('%'); // append that % and move on
}
else
{
int firstDigitValue = parseHexDigit(escapedArray[++i]);
int secondDigitValue = parseHexDigit(escapedArray[++i]);
if (firstDigitValue < 0 || secondDigitValue < 0)
{
// bad digit, just move on
unescaped.Append('%');
unescaped.Append(escapedArray[i - 1]);
unescaped.Append(escapedArray[i]);
}
unescaped.Append((char)((firstDigitValue << 4) + secondDigitValue));
}
}
else
{
unescaped.Append(c);
}
}
return unescaped.ToString();
}
private static int findFirstEscape(char[] escapedArray)
{
int max = escapedArray.Length;
for (int i = 0; i < max; i++)
{
char c = escapedArray[i];
if (c == '+' || c == '%')
{
return i;
}
}
return -1;
}
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing.Client.Result
{
/// <summary> <p>Parses an "sms:" URI result, which specifies a number to SMS and optional
/// "via" number. See <a href="http://gbiv.com/protocols/uri/drafts/draft-antti-gsm-sms-url-04.txt">
/// the IETF draft</a> on this.</p>
///
/// <p>This actually also parses URIs starting with "mms:", "smsto:", "mmsto:", "SMSTO:", and
/// "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI
/// for purposes of forwarding to the platform.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class SMSMMSResultParser : ResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null ||
!(rawText.StartsWith("sms:") || rawText.StartsWith("SMS:") ||
rawText.StartsWith("mms:") || rawText.StartsWith("MMS:")))
{
return null;
}
// Check up front if this is a URI syntax string with query arguments
var nameValuePairs = parseNameValuePairs(rawText);
String subject = null;
String body = null;
var querySyntax = false;
if (nameValuePairs != null && nameValuePairs.Count != 0)
{
subject = nameValuePairs["subject"];
body = nameValuePairs["body"];
querySyntax = true;
}
// Drop sms, query portion
//UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'"
var queryStart = rawText.IndexOf('?', 4);
String smsURIWithoutQuery;
// If it's not query syntax, the question mark is part of the subject or message
if (queryStart < 0 || !querySyntax)
{
smsURIWithoutQuery = rawText.Substring(4);
}
else
{
smsURIWithoutQuery = rawText.Substring(4, (queryStart) - (4));
}
int lastComma = -1;
int comma;
var numbers = new List<String>(1);
var vias = new List<String>(1);
while ((comma = smsURIWithoutQuery.IndexOf(',', lastComma + 1)) > lastComma)
{
String numberPart = smsURIWithoutQuery.Substring(lastComma + 1, comma);
addNumberVia(numbers, vias, numberPart);
lastComma = comma;
}
addNumberVia(numbers, vias, smsURIWithoutQuery.Substring(lastComma + 1));
return new SMSParsedResult(SupportClass.toStringArray(numbers),
SupportClass.toStringArray(vias),
subject,
body);
}
private static void addNumberVia(ICollection<String> numbers,
ICollection<String> vias,
String numberPart)
{
int numberEnd = numberPart.IndexOf(';');
if (numberEnd < 0)
{
numbers.Add(numberPart);
vias.Add(null);
}
else
{
numbers.Add(numberPart.Substring(0, numberEnd));
String maybeVia = numberPart.Substring(numberEnd + 1);
String via;
if (maybeVia.StartsWith("via="))
{
via = maybeVia.Substring(4);
}
else
{
via = null;
}
vias.Add(via);
}
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes an SMS message, including recipients, subject and body text.
/// </summary>
/// <author>Sean Owen</author>
public sealed class SMSParsedResult : ParsedResult
{
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="number"></param>
/// <param name="via"></param>
/// <param name="subject"></param>
/// <param name="body"></param>
public SMSParsedResult(String number,
String via,
String subject,
String body)
: this(new[] { number }, new[] { via }, subject, body)
{
}
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="numbers"></param>
/// <param name="vias"></param>
/// <param name="subject"></param>
/// <param name="body"></param>
public SMSParsedResult(String[] numbers,
String[] vias,
String subject,
String body)
: base(ParsedResultType.SMS)
{
Numbers = numbers;
Vias = vias;
Subject = subject;
Body = body;
SMSURI = getSMSURI();
var result = new StringBuilder(100);
maybeAppend(Numbers, result);
maybeAppend(Subject, result);
maybeAppend(Body, result);
displayResultValue = result.ToString();
}
private String getSMSURI()
{
var result = new StringBuilder();
result.Append("sms:");
bool first = true;
for (int i = 0; i < Numbers.Length; i++)
{
if (first)
{
first = false;
}
else
{
result.Append(',');
}
result.Append(Numbers[i]);
if (Vias != null && Vias[i] != null)
{
result.Append(";via=");
result.Append(Vias[i]);
}
}
bool hasBody = Body != null;
bool hasSubject = Subject != null;
if (hasBody || hasSubject)
{
result.Append('?');
if (hasBody)
{
result.Append("body=");
result.Append(Body);
}
if (hasSubject)
{
if (hasBody)
{
result.Append('&');
}
result.Append("subject=");
result.Append(Subject);
}
}
return result.ToString();
}
/// <summary>
/// numbers
/// </summary>
public String[] Numbers { get; private set; }
/// <summary>
/// vias
/// </summary>
public String[] Vias { get; private set; }
/// <summary>
/// subject
/// </summary>
public String Subject { get; private set; }
/// <summary>
/// body
/// </summary>
public String Body { get; private set; }
/// <summary>
/// sms uri
/// </summary>
public String SMSURI { get; private set; }
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// <p>Parses an "smsto:" URI result, whose format is not standardized but appears to be like:
/// {@code smsto:number(:body)}.</p>
/// <p>This actually also parses URIs starting with "smsto:", "mmsto:", "SMSTO:", and
/// "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI
/// for purposes of forwarding to the platform.</p>
/// </summary>
/// <author>Sean Owen</author>
public class SMSTOMMSTOResultParser : ResultParser
{
/// <summary>
/// attempt to parse the raw result to the specific type
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public override ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (!(rawText.StartsWith("smsto:") || rawText.StartsWith("SMSTO:") ||
rawText.StartsWith("mmsto:") || rawText.StartsWith("MMSTO:")))
{
return null;
}
// Thanks to dominik.wild for suggesting this enhancement to support
// smsto:number:body URIs
String number = rawText.Substring(6);
String body = null;
int bodyStart = number.IndexOf(':');
if (bodyStart >= 0)
{
body = number.Substring(bodyStart + 1);
number = number.Substring(0, bodyStart);
}
return new SMSParsedResult(number, null, null, body);
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// <p>Parses an "smtp:" URI result, whose format is not standardized but appears to be like:
/// <code>smtp[:subject[:body]]}</code>.</p>
/// <p>See http://code.google.com/p/zxing/issues/detail?id=536</p>
/// </summary>
/// <author>Sean Owen</author>
public class SMTPResultParser : ResultParser
{
/// <summary>
/// attempt to parse the raw result to the specific type
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public override ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (!(rawText.StartsWith("smtp:") || rawText.StartsWith("SMTP:")))
{
return null;
}
String emailAddress = rawText.Substring(5);
String subject = null;
String body = null;
int colon = emailAddress.IndexOf(':');
if (colon >= 0)
{
subject = emailAddress.Substring(colon + 1);
emailAddress = emailAddress.Substring(0, colon);
colon = subject.IndexOf(':');
if (colon >= 0)
{
body = subject.Substring(colon + 1);
subject = subject.Substring(0, colon);
}
}
return new EmailAddressParsedResult(new[] { emailAddress },
null,
null,
subject,
body);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes a telephone number.
/// </summary>
/// <author>Sean Owen</author>
public sealed class TelParsedResult : ParsedResult
{
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="number"></param>
/// <param name="telURI"></param>
/// <param name="title"></param>
public TelParsedResult(String number, String telURI, String title)
: base(ParsedResultType.TEL)
{
Number = number;
TelURI = telURI;
Title = title;
var result = new System.Text.StringBuilder(20);
maybeAppend(number, result);
maybeAppend(title, result);
displayResultValue = result.ToString();
}
/// <summary>
/// number
/// </summary>
public String Number { get; private set; }
/// <summary>
/// URI
/// </summary>
public String TelURI { get; private set; }
/// <summary>
/// title
/// </summary>
public String Title { get; private set; }
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// Parses a "tel:" URI result, which specifies a phone number.
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class TelResultParser : ResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null ||
(!rawText.StartsWith("tel:") && !rawText.StartsWith("TEL:")))
{
return null;
}
// Normalize "TEL:" to "tel:"
String telURI = rawText.StartsWith("TEL:") ? "tel:" + rawText.Substring(4) : rawText;
// Drop tel, query portion
//UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'"
int queryStart = rawText.IndexOf('?', 4);
String number = queryStart < 0 ? rawText.Substring(4) : rawText.Substring(4, (queryStart) - (4));
return new TelParsedResult(number, telURI, null);
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// A simple result type encapsulating a string that has no further interpretation.
/// </summary>
/// <author>Sean Owen</author>
public sealed class TextParsedResult : ParsedResult
{
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="text"></param>
/// <param name="language"></param>
public TextParsedResult(String text, String language)
: base(ParsedResultType.TEXT)
{
Text = text;
Language = language;
displayResultValue = text;
}
/// <summary>
/// text
/// </summary>
public String Text { get; private set; }
/// <summary>
/// language
/// </summary>
public String Language { get; private set; }
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// A simple result type encapsulating a URI that has no further interpretation.
/// </summary>
/// <author>Sean Owen</author>
public sealed class URIParsedResult : ParsedResult
{
/// <summary>
/// URI
/// </summary>
public String URI { get; private set; }
/// <summary>
/// title
/// </summary>
public String Title { get; private set; }
/// <returns> true if the URI contains suspicious patterns that may suggest it intends to
/// mislead the user about its true nature. At the moment this looks for the presence
/// of user/password syntax in the host/authority portion of a URI which may be used
/// in attempts to make the URI's host appear to be other than it is. Example:
/// http://yourbank.com@phisher.com This URI connects to phisher.com but may appear
/// to connect to yourbank.com at first glance.
/// </returns>
[Obsolete("deprecated, see {@link URIResultParser#isPossiblyMaliciousURI(String)")]
public bool PossiblyMaliciousURI { get; private set; }
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="uri"></param>
/// <param name="title"></param>
public URIParsedResult(String uri, String title)
: base(ParsedResultType.URI)
{
URI = massageURI(uri);
Title = title;
PossiblyMaliciousURI = URIResultParser.isPossiblyMaliciousURI(uri);
var result = new System.Text.StringBuilder(30);
maybeAppend(Title, result);
maybeAppend(URI, result);
displayResultValue = result.ToString();
}
/// <summary> Transforms a string that represents a URI into something more proper, by adding or canonicalizing
/// the protocol.
/// </summary>
private static String massageURI(String uri)
{
int protocolEnd = uri.IndexOf(':');
if (protocolEnd < 0 || isColonFollowedByPortNumber(uri, protocolEnd))
{
// No protocol, or found a colon, but it looks like it is after the host, so the protocol is still missing,
// so assume http
uri = "http://" + uri;
}
return uri;
}
private static bool isColonFollowedByPortNumber(String uri, int protocolEnd)
{
int start = protocolEnd + 1;
int nextSlash = uri.IndexOf('/', start);
if (nextSlash < 0)
{
nextSlash = uri.Length;
}
return ResultParser.isSubstringOfDigits(uri, start, nextSlash - start);
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary>
/// Tries to parse results that are a URI of some kind.
/// </summary>
/// <author>Sean Owen</author>
sealed class URIResultParser : ResultParser
{
private static readonly Regex ALLOWED_URI_CHARS_PATTERN = new Regex("^[-._~:/?#\\[\\]@!$&'()*+,;=%A-Za-z0-9]+$"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
private static readonly Regex USER_IN_HOST = new Regex(":/*([^/@]+)@[^/]+"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
// See http://www.ietf.org/rfc/rfc2396.txt
private static readonly Regex URL_WITH_PROTOCOL_PATTERN = new Regex("[a-zA-Z][a-zA-Z0-9+-.]+:"
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
private static readonly Regex URL_WITHOUT_PROTOCOL_PATTERN = new Regex(
"([a-zA-Z0-9\\-]+\\.){1,6}[a-zA-Z]{2,}" + // host name elements
"(:\\d{1,5})?" + // maybe port
"(/|\\?|$)" // query, path or nothing
#if !(SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2)
, RegexOptions.Compiled);
#else
);
#endif
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
// We specifically handle the odd "URL" scheme here for simplicity and add "URI" for fun
// Assume anything starting this way really means to be a URI
if (rawText.StartsWith("URL:") || rawText.StartsWith("URI:"))
{
return new URIParsedResult(rawText.Substring(4).Trim(), null);
}
rawText = rawText.Trim();
if (!isBasicallyValidURI(rawText) || isPossiblyMaliciousURI(rawText))
{
return null;
}
return new URIParsedResult(rawText, null);
}
/**
* @return true if the URI contains suspicious patterns that may suggest it intends to
* mislead the user about its true nature. At the moment this looks for the presence
* of user/password syntax in the host/authority portion of a URI which may be used
* in attempts to make the URI's host appear to be other than it is. Example:
* http://yourbank.com@phisher.com This URI connects to phisher.com but may appear
* to connect to yourbank.com at first glance.
*/
internal static bool isPossiblyMaliciousURI(String uri)
{
return !ALLOWED_URI_CHARS_PATTERN.Match(uri).Success || USER_IN_HOST.Match(uri).Success;
}
internal static bool isBasicallyValidURI(String uri)
{
if (uri.IndexOf(" ") >= 0)
{
// Quick hack check for a common case
return false;
}
var m = URL_WITH_PROTOCOL_PATTERN.Match(uri);
if (m.Success && m.Index == 0)
{
// match at start only
return true;
}
m = URL_WITHOUT_PROTOCOL_PATTERN.Match(uri);
return m.Success && m.Index == 0;
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary> Parses the "URLTO" result format, which is of the form "URLTO:[title]:[url]".
/// This seems to be used sometimes, but I am not able to find documentation
/// on its origin or official format?
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class URLTOResultParser : ResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
var rawText = result.Text;
if (rawText == null ||
(!rawText.StartsWith("urlto:") && !rawText.StartsWith("URLTO:")))
{
return null;
}
//UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'"
int titleEnd = rawText.IndexOf(':', 6);
if (titleEnd < 0)
{
return null;
}
var title = titleEnd <= 6 ? null : rawText.Substring(6, (titleEnd) - (6));
var uri = rawText.Substring(titleEnd + 1);
return new URIParsedResult(uri, title);
}
}
}

View File

@@ -0,0 +1,490 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary>
/// Parses contact information formatted according to the VCard (2.1) format. This is not a complete
/// implementation but should parse information as commonly encoded in 2D barcodes.
/// </summary>
/// <author>Sean Owen</author>
sealed class VCardResultParser : ResultParser
{
#if SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2
private static readonly Regex BEGIN_VCARD = new Regex("BEGIN:VCARD", RegexOptions.IgnoreCase);
private static readonly Regex VCARD_LIKE_DATE = new Regex(@"\A(?:" + "\\d{4}-?\\d{2}-?\\d{2}" + @")\z");
private static readonly Regex CR_LF_SPACE_TAB = new Regex("\r\n[ \t]");
private static readonly Regex NEWLINE_ESCAPE = new Regex("\\\\[nN]");
private static readonly Regex VCARD_ESCAPES = new Regex("\\\\([,;\\\\])");
private static readonly Regex EQUALS = new Regex("=");
private static readonly Regex SEMICOLON = new Regex(";");
private static readonly Regex UNESCAPED_SEMICOLONS = new Regex("(?<!\\\\);+");
private static readonly Regex COMMA = new Regex(",");
private static readonly Regex SEMICOLON_OR_COMMA = new Regex("[;,]");
#else
private static readonly Regex BEGIN_VCARD = new Regex("BEGIN:VCARD", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex VCARD_LIKE_DATE = new Regex(@"\A(?:" + "\\d{4}-?\\d{2}-?\\d{2}" + @")\z", RegexOptions.Compiled);
private static readonly Regex CR_LF_SPACE_TAB = new Regex("\r\n[ \t]", RegexOptions.Compiled);
private static readonly Regex NEWLINE_ESCAPE = new Regex("\\\\[nN]", RegexOptions.Compiled);
private static readonly Regex VCARD_ESCAPES = new Regex("\\\\([,;\\\\])", RegexOptions.Compiled);
private static readonly Regex EQUALS = new Regex("=", RegexOptions.Compiled);
private static readonly Regex SEMICOLON = new Regex(";", RegexOptions.Compiled);
private static readonly Regex UNESCAPED_SEMICOLONS = new Regex("(?<!\\\\);+", RegexOptions.Compiled);
private static readonly Regex COMMA = new Regex(",", RegexOptions.Compiled);
private static readonly Regex SEMICOLON_OR_COMMA = new Regex("[;,]", RegexOptions.Compiled);
#endif
override public ParsedResult parse(ZXing.Result result)
{
// Although we should insist on the raw text ending with "END:VCARD", there's no reason
// to throw out everything else we parsed just because this was omitted. In fact, Eclair
// is doing just that, and we can't parse its contacts without this leniency.
String rawText = result.Text;
var m = BEGIN_VCARD.Match(rawText);
if (!m.Success || m.Index != 0)
{
return null;
}
List<List<String>> names = matchVCardPrefixedField("FN", rawText, true, false);
if (names == null)
{
// If no display names found, look for regular name fields and format them
names = matchVCardPrefixedField("N", rawText, true, false);
formatNames(names);
}
List<String> nicknameString = matchSingleVCardPrefixedField("NICKNAME", rawText, true, false);
String[] nicknames = nicknameString == null ? null : COMMA.Split(nicknameString[0]);
List<List<String>> phoneNumbers = matchVCardPrefixedField("TEL", rawText, true, false);
List<List<String>> emails = matchVCardPrefixedField("EMAIL", rawText, true, false);
List<String> note = matchSingleVCardPrefixedField("NOTE", rawText, false, false);
List<List<String>> addresses = matchVCardPrefixedField("ADR", rawText, true, true);
List<String> org = matchSingleVCardPrefixedField("ORG", rawText, true, true);
List<String> birthday = matchSingleVCardPrefixedField("BDAY", rawText, true, false);
if (birthday != null && !isLikeVCardDate(birthday[0]))
{
birthday = null;
}
List<String> title = matchSingleVCardPrefixedField("TITLE", rawText, true, false);
List<List<String>> urls = matchVCardPrefixedField("URL", rawText, true, false);
List<String> instantMessenger = matchSingleVCardPrefixedField("IMPP", rawText, true, false);
List<String> geoString = matchSingleVCardPrefixedField("GEO", rawText, true, false);
String[] geo = geoString == null ? null : SEMICOLON_OR_COMMA.Split(geoString[0]);
if (geo != null && geo.Length != 2)
{
geo = null;
}
return new AddressBookParsedResult(toPrimaryValues(names),
nicknames,
null,
toPrimaryValues(phoneNumbers),
toTypes(phoneNumbers),
toPrimaryValues(emails),
toTypes(emails),
toPrimaryValue(instantMessenger),
toPrimaryValue(note),
toPrimaryValues(addresses),
toTypes(addresses),
toPrimaryValue(org),
toPrimaryValue(birthday),
toPrimaryValue(title),
toPrimaryValues(urls),
geo);
}
public static List<List<String>> matchVCardPrefixedField(String prefix,
String rawText,
bool trim,
bool parseFieldDivider)
{
List<List<String>> matches = null;
int i = 0;
int max = rawText.Length;
while (i < max)
{
// At start or after newline, match prefix, followed by optional metadata
// (led by ;) ultimately ending in colon
var matcher = new Regex("(?:^|\n)" + prefix + "(?:;([^:]*))?:", RegexOptions.IgnoreCase);
if (i > 0)
{
i--; // Find from i-1 not i since looking at the preceding character
}
var match = matcher.Match(rawText, i);
if (!match.Success)
{
break;
}
i = match.Index + match.Length;
String metadataString = match.Groups[1].Value; // group 1 = metadata substring
List<String> metadata = null;
bool quotedPrintable = false;
String quotedPrintableCharset = null;
String valueType = null;
if (metadataString != null)
{
foreach (String metadatum in SEMICOLON.Split(metadataString))
{
if (metadata == null)
{
metadata = new List<String>(1);
}
metadata.Add(metadatum);
String[] metadatumTokens = EQUALS.Split(metadatum, 2);
if (metadatumTokens.Length > 1)
{
String key = metadatumTokens[0];
String value = metadatumTokens[1];
if (String.Compare("ENCODING", key, StringComparison.OrdinalIgnoreCase) == 0 &&
String.Compare("QUOTED-PRINTABLE", value, StringComparison.OrdinalIgnoreCase) == 0)
{
quotedPrintable = true;
}
else if (String.Compare("CHARSET", key, StringComparison.OrdinalIgnoreCase) == 0)
{
quotedPrintableCharset = value;
}
else if (String.Compare("VALUE", key, StringComparison.OrdinalIgnoreCase) == 0)
{
valueType = value;
}
}
}
}
int matchStart = i; // Found the start of a match here
while ((i = rawText.IndexOf('\n', i)) >= 0)
{
// Really, end in \r\n
if (i < rawText.Length - 1 && // But if followed by tab or space,
(rawText[i + 1] == ' ' || // this is only a continuation
rawText[i + 1] == '\t'))
{
i += 2; // Skip \n and continutation whitespace
}
else if (quotedPrintable && // If preceded by = in quoted printable
((i >= 1 && rawText[i - 1] == '=') || // this is a continuation
(i >= 2 && rawText[i - 2] == '=')))
{
i++; // Skip \n
}
else
{
break;
}
}
if (i < 0)
{
// No terminating end character? uh, done. Set i such that loop terminates and break
i = max;
}
else if (i > matchStart)
{
// found a match
if (matches == null)
{
matches = new List<List<String>>(1); // lazy init
}
if (i >= 1 && rawText[i - 1] == '\r')
{
i--; // Back up over \r, which really should be there
}
String element = rawText.Substring(matchStart, i - matchStart);
if (trim)
{
element = element.Trim();
}
if (quotedPrintable)
{
element = decodeQuotedPrintable(element, quotedPrintableCharset);
if (parseFieldDivider)
{
element = UNESCAPED_SEMICOLONS.Replace(element, "\n").Trim();
}
}
else
{
if (parseFieldDivider)
{
element = UNESCAPED_SEMICOLONS.Replace(element, "\n").Trim();
}
element = CR_LF_SPACE_TAB.Replace(element, "");
element = NEWLINE_ESCAPE.Replace(element, "\n");
element = VCARD_ESCAPES.Replace(element, "$1");
}
// Only handle VALUE=uri specially
if ("uri".Equals(valueType))
{
// Don't actually support dereferencing URIs, but use scheme-specific part not URI
// as value, to support tel: and mailto:
try
{
Uri uri;
if (Uri.TryCreate(element, UriKind.RelativeOrAbsolute, out uri))
{
element = uri.AbsoluteUri.Replace(uri.Scheme + ':', "");
}
}
catch (Exception)
{
// ignore
}
}
if (metadata == null)
{
var matched = new List<String>(1);
matched.Add(element);
matches.Add(matched);
}
else
{
metadata.Insert(0, element);
matches.Add(metadata);
}
i++;
}
else
{
i++;
}
}
return matches;
}
private static String decodeQuotedPrintable(String value, String charset)
{
int length = value.Length;
var result = new StringBuilder(length);
var fragmentBuffer = new MemoryStream();
for (int i = 0; i < length; i++)
{
char c = value[i];
switch (c)
{
case '\r':
case '\n':
break;
case '=':
if (i < length - 2)
{
char nextChar = value[i + 1];
if (nextChar == '\r' || nextChar == '\n')
{
// Ignore, it's just a continuation symbol
}
else
{
char nextNextChar = value[i + 2];
int firstDigit = parseHexDigit(nextChar);
int secondDigit = parseHexDigit(nextNextChar);
if (firstDigit >= 0 && secondDigit >= 0)
{
fragmentBuffer.WriteByte((byte)((firstDigit << 4) | secondDigit));
} // else ignore it, assume it was incorrectly encoded
i += 2;
}
}
break;
default:
maybeAppendFragment(fragmentBuffer, charset, result);
result.Append(c);
break;
}
}
maybeAppendFragment(fragmentBuffer, charset, result);
return result.ToString();
}
private static void maybeAppendFragment(MemoryStream fragmentBuffer,
String charset,
StringBuilder result)
{
if (fragmentBuffer.Length > 0)
{
byte[] fragmentBytes = fragmentBuffer.ToArray();
String fragment;
if (charset == null)
{
#if WindowsCE
fragment = Encoding.Default.GetString(fragmentBytes, 0, fragmentBytes.Length);
#else
fragment = Encoding.UTF8.GetString(fragmentBytes, 0, fragmentBytes.Length);
#endif
}
else
{
try
{
fragment = Encoding.GetEncoding(charset).GetString(fragmentBytes, 0, fragmentBytes.Length);
}
catch (Exception)
{
#if WindowsCE
// WindowsCE doesn't support all encodings. But it is device depended.
// So we try here the some different ones
if (charset == "ISO-8859-1")
{
fragment = Encoding.GetEncoding(1252).GetString(fragmentBytes, 0, fragmentBytes.Length);
}
else
{
fragment = Encoding.Default.GetString(fragmentBytes, 0, fragmentBytes.Length);
}
fragment = Encoding.Default.GetString(fragmentBytes, 0, fragmentBytes.Length);
#else
fragment = Encoding.UTF8.GetString(fragmentBytes, 0, fragmentBytes.Length);
#endif
}
}
fragmentBuffer.Seek(0, SeekOrigin.Begin);
fragmentBuffer.SetLength(0);
result.Append(fragment);
}
}
internal static List<String> matchSingleVCardPrefixedField(String prefix,
String rawText,
bool trim,
bool parseFieldDivider)
{
List<List<String>> values = matchVCardPrefixedField(prefix, rawText, trim, parseFieldDivider);
return values == null || values.Count == 0 ? null : values[0];
}
private static String toPrimaryValue(List<String> list)
{
return list == null || list.Count == 0 ? null : list[0];
}
private static String[] toPrimaryValues(ICollection<List<String>> lists)
{
if (lists == null || lists.Count == 0)
{
return null;
}
var result = new List<String>(lists.Count);
foreach (var list in lists)
{
String value = list[0];
if (!String.IsNullOrEmpty(value))
{
result.Add(value);
}
}
return SupportClass.toStringArray(result);
}
private static String[] toTypes(ICollection<List<String>> lists)
{
if (lists == null || lists.Count == 0)
{
return null;
}
List<String> result = new List<String>(lists.Count);
foreach (var list in lists)
{
String value = list[0];
if (!String.IsNullOrEmpty(value))
{
String type = null;
for (int i = 1; i < list.Count; i++)
{
String metadatum = list[i];
int equals = metadatum.IndexOf('=');
if (equals < 0)
{
// take the whole thing as a usable label
type = metadatum;
break;
}
if (String.Compare("TYPE", metadatum.Substring(0, equals), StringComparison.OrdinalIgnoreCase) == 0)
{
type = metadatum.Substring(equals + 1);
break;
}
}
result.Add(type);
}
}
return SupportClass.toStringArray(result);
}
private static bool isLikeVCardDate(String value)
{
return value == null || VCARD_LIKE_DATE.Match(value).Success;
}
/**
* Formats name fields of the form "Public;John;Q.;Reverend;III" into a form like
* "Reverend John Q. Public III".
*
* @param names name values to format, in place
*/
private static void formatNames(IEnumerable<List<String>> names)
{
if (names != null)
{
foreach (var list in names)
{
String name = list[0];
String[] components = new String[5];
int start = 0;
int end;
int componentIndex = 0;
while (componentIndex < components.Length - 1 && (end = name.IndexOf(';', start)) >= 0)
{
components[componentIndex] = name.Substring(start, end - start);
componentIndex++;
start = end + 1;
}
components[componentIndex] = name.Substring(start);
StringBuilder newName = new StringBuilder(100);
maybeAppendComponent(components, 3, newName);
maybeAppendComponent(components, 1, newName);
maybeAppendComponent(components, 2, newName);
maybeAppendComponent(components, 0, newName);
maybeAppendComponent(components, 4, newName);
list.Insert(0, newName.ToString().Trim());
}
}
}
private static void maybeAppendComponent(String[] components, int i, StringBuilder newName)
{
if (!String.IsNullOrEmpty(components[i]))
{
if (newName.Length > 0)
{
newName.Append(' ');
}
newName.Append(components[i]);
}
}
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
namespace ZXing.Client.Result
{
/// <summary>
/// Partially implements the iCalendar format's "VEVENT" format for specifying a
/// calendar event. See RFC 2445. This supports SUMMARY, DTSTART and DTEND fields.
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
sealed class VEventResultParser : ResultParser
{
override public ParsedResult parse(ZXing.Result result)
{
String rawText = result.Text;
if (rawText == null)
{
return null;
}
int vEventStart = rawText.IndexOf("BEGIN:VEVENT");
if (vEventStart < 0)
{
return null;
}
String summary = matchSingleVCardPrefixedField("SUMMARY", rawText);
String start = matchSingleVCardPrefixedField("DTSTART", rawText);
if (start == null)
{
return null;
}
String end = matchSingleVCardPrefixedField("DTEND", rawText);
String duration = matchSingleVCardPrefixedField("DURATION", rawText);
String location = matchSingleVCardPrefixedField("LOCATION", rawText);
String organizer = stripMailto(matchSingleVCardPrefixedField("ORGANIZER", rawText));
String[] attendees = matchVCardPrefixedField("ATTENDEE", rawText);
if (attendees != null)
{
for (int i = 0; i < attendees.Length; i++)
{
attendees[i] = stripMailto(attendees[i]);
}
}
String description = matchSingleVCardPrefixedField("DESCRIPTION", rawText);
String geoString = matchSingleVCardPrefixedField("GEO", rawText);
double latitude;
double longitude;
if (geoString == null)
{
latitude = Double.NaN;
longitude = Double.NaN;
}
else
{
int semicolon = geoString.IndexOf(';');
if (semicolon < 0)
{
return null;
}
#if WindowsCE
try { latitude = Double.Parse(geoString.Substring(0, semicolon), NumberStyles.Float, CultureInfo.InvariantCulture); }
catch { return null; }
try { longitude = Double.Parse(geoString.Substring(semicolon + 1), NumberStyles.Float, CultureInfo.InvariantCulture); }
catch { return null; }
#else
if (!Double.TryParse(geoString.Substring(0, semicolon), NumberStyles.Float, CultureInfo.InvariantCulture, out latitude))
return null;
if (!Double.TryParse(geoString.Substring(semicolon + 1), NumberStyles.Float, CultureInfo.InvariantCulture, out longitude))
return null;
#endif
}
try
{
return new CalendarParsedResult(summary,
start,
end,
duration,
location,
organizer,
attendees,
description,
latitude,
longitude);
}
catch (ArgumentException)
{
return null;
}
}
private static String matchSingleVCardPrefixedField(String prefix,
String rawText)
{
var values = VCardResultParser.matchSingleVCardPrefixedField(prefix, rawText, true, false);
return values == null || values.Count == 0 ? null : values[0];
}
private static String[] matchVCardPrefixedField(String prefix, String rawText)
{
List<List<String>> values = VCardResultParser.matchVCardPrefixedField(prefix, rawText, true, false);
if (values == null || values.Count == 0)
{
return null;
}
int size = values.Count;
String[] result = new String[size];
for (int i = 0; i < size; i++)
{
result[i] = values[i][0];
}
return result;
}
private static String stripMailto(String s)
{
if (s != null && (s.StartsWith("mailto:") || s.StartsWith("MAILTO:")))
{
s = s.Substring(7);
}
return s;
}
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2014 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes a Vehicle Identification Number (VIN).
/// </summary>
public class VINParsedResult : ParsedResult
{
/// <summary>
/// VIN
/// </summary>
public String VIN { get; private set; }
/// <summary>
/// manufacturer id
/// </summary>
public String WorldManufacturerID { get; private set; }
/// <summary>
/// vehicle descriptor section
/// </summary>
public String VehicleDescriptorSection { get; private set; }
/// <summary>
/// vehicle identifier section
/// </summary>
public String VehicleIdentifierSection { get; private set; }
/// <summary>
/// country code
/// </summary>
public String CountryCode { get; private set; }
/// <summary>
/// vehicle attributes
/// </summary>
public String VehicleAttributes { get; private set; }
/// <summary>
/// model year
/// </summary>
public int ModelYear { get; private set; }
/// <summary>
/// plant code
/// </summary>
public char PlantCode { get; private set; }
/// <summary>
/// sequential number
/// </summary>
public String SequentialNumber { get; private set; }
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="vin"></param>
/// <param name="worldManufacturerID"></param>
/// <param name="vehicleDescriptorSection"></param>
/// <param name="vehicleIdentifierSection"></param>
/// <param name="countryCode"></param>
/// <param name="vehicleAttributes"></param>
/// <param name="modelYear"></param>
/// <param name="plantCode"></param>
/// <param name="sequentialNumber"></param>
public VINParsedResult(String vin,
String worldManufacturerID,
String vehicleDescriptorSection,
String vehicleIdentifierSection,
String countryCode,
String vehicleAttributes,
int modelYear,
char plantCode,
String sequentialNumber)
: base(ParsedResultType.VIN)
{
VIN = vin;
WorldManufacturerID = worldManufacturerID;
VehicleDescriptorSection = vehicleDescriptorSection;
VehicleIdentifierSection = vehicleIdentifierSection;
CountryCode = countryCode;
VehicleAttributes = vehicleAttributes;
ModelYear = modelYear;
PlantCode = plantCode;
SequentialNumber = sequentialNumber;
}
/// <summary>
/// a user friendly representation
/// </summary>
public override string DisplayResult
{
get
{
var result = new StringBuilder(50);
result.Append(WorldManufacturerID).Append(' ');
result.Append(VehicleDescriptorSection).Append(' ');
result.Append(VehicleIdentifierSection).Append('\n');
if (CountryCode != null)
{
result.Append(CountryCode).Append(' ');
}
result.Append(ModelYear).Append(' ');
result.Append(PlantCode).Append(' ');
result.Append(SequentialNumber).Append('\n');
return result.ToString();
}
}
}
}

View File

@@ -0,0 +1,260 @@
/*
* Copyright 2014 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text.RegularExpressions;
namespace ZXing.Client.Result
{
/// <summary>
/// Detects a result that is likely a vehicle identification number.
/// @author Sean Owen
/// </summary>
public class VINResultParser : ResultParser
{
#if SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2
private static readonly Regex IOQ = new Regex("[IOQ]");
private static readonly Regex AZ09 = new Regex(@"\A(?:" + "[A-Z0-9]{17}" + @")\z");
#else
private static readonly Regex IOQ = new Regex("[IOQ]", RegexOptions.Compiled);
private static readonly Regex AZ09 = new Regex(@"\A(?:" + "[A-Z0-9]{17}" + @")\z", RegexOptions.Compiled);
#endif
/// <summary>
/// attempt to parse the raw result to the specific type
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public override ParsedResult parse(ZXing.Result result)
{
try
{
if (result.BarcodeFormat != BarcodeFormat.CODE_39)
{
return null;
}
var rawText = result.Text;
rawText = IOQ.Replace(rawText, "").Trim();
var az09Match = AZ09.Match(rawText);
if (!az09Match.Success)
{
return null;
}
if (!checkChecksum(rawText))
{
return null;
}
var wmi = rawText.Substring(0, 3);
return new VINParsedResult(rawText,
wmi,
rawText.Substring(3, 6),
rawText.Substring(9, 8),
countryCode(wmi),
rawText.Substring(3, 5),
modelYear(rawText[9]),
rawText[10],
rawText.Substring(11));
}
catch
{
return null;
}
}
private static bool checkChecksum(String vin)
{
var sum = 0;
for (var i = 0; i < vin.Length; i++)
{
sum += vinPositionWeight(i + 1) * vinCharValue(vin[i]);
}
var currentCheckChar = vin[8];
var expectedCheckChar = checkChar(sum % 11);
return currentCheckChar == expectedCheckChar;
}
private static int vinCharValue(char c)
{
if (c >= 'A' && c <= 'I')
{
return (c - 'A') + 1;
}
if (c >= 'J' && c <= 'R')
{
return (c - 'J') + 1;
}
if (c >= 'S' && c <= 'Z')
{
return (c - 'S') + 2;
}
if (c >= '0' && c <= '9')
{
return c - '0';
}
throw new ArgumentException(c.ToString());
}
private static int vinPositionWeight(int position)
{
if (position >= 1 && position <= 7)
{
return 9 - position;
}
if (position == 8)
{
return 10;
}
if (position == 9)
{
return 0;
}
if (position >= 10 && position <= 17)
{
return 19 - position;
}
throw new ArgumentException();
}
private static char checkChar(int remainder)
{
if (remainder < 10)
{
return (char)('0' + remainder);
}
if (remainder == 10)
{
return 'X';
}
throw new ArgumentException();
}
private static int modelYear(char c)
{
if (c >= 'E' && c <= 'H')
{
return (c - 'E') + 1984;
}
if (c >= 'J' && c <= 'N')
{
return (c - 'J') + 1988;
}
if (c == 'P')
{
return 1993;
}
if (c >= 'R' && c <= 'T')
{
return (c - 'R') + 1994;
}
if (c >= 'V' && c <= 'Y')
{
return (c - 'V') + 1997;
}
if (c >= '1' && c <= '9')
{
return (c - '1') + 2001;
}
if (c >= 'A' && c <= 'D')
{
return (c - 'A') + 2010;
}
throw new ArgumentException(c.ToString());
}
private static String countryCode(String wmi)
{
char c1 = wmi[0];
char c2 = wmi[1];
switch (c1)
{
case '1':
case '4':
case '5':
return "US";
case '2':
return "CA";
case '3':
if (c2 >= 'A' && c2 <= 'W')
{
return "MX";
}
break;
case '9':
if ((c2 >= 'A' && c2 <= 'E') || (c2 >= '3' && c2 <= '9'))
{
return "BR";
}
break;
case 'J':
if (c2 >= 'A' && c2 <= 'T')
{
return "JP";
}
break;
case 'K':
if (c2 >= 'L' && c2 <= 'R')
{
return "KO";
}
break;
case 'L':
return "CN";
case 'M':
if (c2 >= 'A' && c2 <= 'E')
{
return "IN";
}
break;
case 'S':
if (c2 >= 'A' && c2 <= 'M')
{
return "UK";
}
if (c2 >= 'N' && c2 <= 'T')
{
return "DE";
}
break;
case 'V':
if (c2 >= 'F' && c2 <= 'R')
{
return "FR";
}
if (c2 >= 'S' && c2 <= 'W')
{
return "ES";
}
break;
case 'W':
return "DE";
case 'X':
if (c2 == '0' || (c2 >= '3' && c2 <= '9'))
{
return "RU";
}
break;
case 'Z':
if (c2 >= 'A' && c2 <= 'R')
{
return "IT";
}
break;
}
return null;
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Client.Result
{
/// <summary>
/// Represents a parsed result that encodes wifi network information, like SSID and password.
/// </summary>
/// <author>Vikram Aggarwal</author>
public class WifiParsedResult : ParsedResult
{
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="networkEncryption"></param>
/// <param name="ssid"></param>
/// <param name="password"></param>
public WifiParsedResult(String networkEncryption, String ssid, String password)
: this(networkEncryption, ssid, password, false)
{
}
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="networkEncryption"></param>
/// <param name="ssid"></param>
/// <param name="password"></param>
/// <param name="hidden"></param>
public WifiParsedResult(String networkEncryption, String ssid, String password, bool hidden)
: this(networkEncryption, ssid, password, hidden, null, null, null, null)
{
}
/// <summary>
/// initializing constructor
/// </summary>
/// <param name="networkEncryption"></param>
/// <param name="ssid"></param>
/// <param name="password"></param>
/// <param name="hidden"></param>
/// <param name="identity"></param>
/// <param name="anonymousIdentity"></param>
/// <param name="eapMethod"></param>
/// <param name="phase2Method"></param>
public WifiParsedResult(String networkEncryption, String ssid, String password, bool hidden, String identity, String anonymousIdentity, String eapMethod, String phase2Method)
: base(ParsedResultType.WIFI)
{
Ssid = ssid;
NetworkEncryption = networkEncryption;
Password = password;
Hidden = hidden;
Identity = identity;
AnonymousIdentity = anonymousIdentity;
EapMethod = eapMethod;
Phase2Method = phase2Method;
var result = new StringBuilder(80);
maybeAppend(Ssid, result);
maybeAppend(NetworkEncryption, result);
maybeAppend(Password, result);
maybeAppend(Hidden.ToString(), result);
maybeAppend(Identity, result);
maybeAppend(AnonymousIdentity, result);
maybeAppend(EapMethod, result);
maybeAppend(Phase2Method, result);
displayResultValue = result.ToString();
}
/// <summary>
/// SSID
/// </summary>
public String Ssid { get; private set; }
/// <summary>
/// network encryption
/// </summary>
public String NetworkEncryption { get; private set; }
/// <summary>
/// password
/// </summary>
public String Password { get; private set; }
/// <summary>
/// hidden flag
/// </summary>
public bool Hidden { get; private set; }
/// <summary>
/// identity
/// </summary>
public String Identity { get; private set; }
/// <summary>
/// anonymous
/// </summary>
public String AnonymousIdentity { get; private set; }
/// <summary>
/// eap
/// </summary>
public String EapMethod { get; private set; }
/// <summary>
/// phase 2 method
/// </summary>
public String Phase2Method { get; private set; }
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Client.Result
{
/// <summary>
/// <p>Parses a WIFI configuration string. Strings will be of the form:</p>
/// <p>{@code WIFI:T:[network type];S:[network SSID];P:[network password];H:[hidden?];;}</p>
/// <p>The fields can appear in any order. Only "S:" is required.</p>
/// <p>For WPA2 enterprise(EAP), strings will be of the form:</p>
/// <p>{@code WIFI:T:WPA2-EAP;S:[network SSID];H:[hidden?];E:[EAP method];PH2:[Phase 2 method];A:[anonymous identity];I:[username];P:[password];;}</p>
/// <p>"EAP method" can e.g.be "TTLS" or "PWD" or one of the other fields in <a href = "https://developer.android.com/reference/android/net/wifi/WifiEnterpriseConfig.Eap.html"> WifiEnterpriseConfig.Eap </a> and "Phase 2 method" can e.g.be "MSCHAPV2" or any of the other fields in <a href = "https://developer.android.com/reference/android/net/wifi/WifiEnterpriseConfig.Phase2.html"> WifiEnterpriseConfig.Phase2 </a></p>
/// </summary>
/// <author>Vikram Aggarwal</author>
/// <author>Sean Owen</author>
/// <author>Steffen Kieß</author>
public class WifiResultParser : ResultParser
{
/// <summary>
/// attempt to parse the raw result to the specific type
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public override ParsedResult parse(ZXing.Result result)
{
var rawText = result.Text;
if (!rawText.StartsWith("WIFI:"))
{
return null;
}
rawText = rawText.Substring("WIFI:".Length);
var ssid = matchSinglePrefixedField("S:", rawText, ';', false);
if (string.IsNullOrEmpty(ssid))
{
return null;
}
var pass = matchSinglePrefixedField("P:", rawText, ';', false);
var type = matchSinglePrefixedField("T:", rawText, ';', false) ?? "nopass";
// Unfortunately, in the past, H: was not just used for boolean 'hidden', but 'phase 2 method'.
// To try to retain backwards compatibility, we set one or the other based on whether the string
// is 'true' or 'false':
bool hidden = false;
String phase2Method = matchSinglePrefixedField("PH2:", rawText, ';', false);
String hValue = matchSinglePrefixedField("H:", rawText, ';', false);
if (hValue != null)
{
// If PH2 was specified separately, or if the value is clearly boolean, interpret it as 'hidden'
if (phase2Method != null || String.Compare("true", hValue, StringComparison.OrdinalIgnoreCase) == 0 || String.Compare("false", hValue, StringComparison.OrdinalIgnoreCase) == 0)
{
#if WindowsCE
try { hidden = Boolean.Parse(hValue); } catch { }
#else
Boolean.TryParse(hValue, out hidden);
#endif
}
else
{
phase2Method = hValue;
}
}
var identity = matchSinglePrefixedField("I:", rawText, ';', false);
var anonymousIdentity = matchSinglePrefixedField("A:", rawText, ';', false);
var eapMethod = matchSinglePrefixedField("E:", rawText, ';', false);
return new WifiParsedResult(type, ssid, pass, hidden, identity, anonymousIdentity, eapMethod, phase2Method);
}
}
}