mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
Calendar events ported not passing
This commit is contained in:
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.result;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a calendar event at a certain time, optionally
|
||||
* with attendees and a location.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class CalendarParsedRXingResult extends ParsedRXingResult {
|
||||
|
||||
private static final Pattern RFC2445_DURATION =
|
||||
Pattern.compile("P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?");
|
||||
private static final 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 final Pattern DATE_TIME = Pattern.compile("[0-9]{8}(T[0-9]{6}Z?)?");
|
||||
|
||||
private final String summary;
|
||||
private final long start;
|
||||
private final boolean startAllDay;
|
||||
private final long end;
|
||||
private final boolean endAllDay;
|
||||
private final String location;
|
||||
private final String organizer;
|
||||
private final String[] attendees;
|
||||
private final String description;
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
|
||||
public CalendarParsedRXingResult(String summary,
|
||||
String startString,
|
||||
String endString,
|
||||
String durationString,
|
||||
String location,
|
||||
String organizer,
|
||||
String[] attendees,
|
||||
String description,
|
||||
double latitude,
|
||||
double longitude) {
|
||||
super(ParsedRXingResultType.CALENDAR);
|
||||
this.summary = summary;
|
||||
|
||||
try {
|
||||
this.start = parseDate(startString);
|
||||
} catch (ParseException pe) {
|
||||
throw new IllegalArgumentException(pe.toString());
|
||||
}
|
||||
|
||||
if (endString == null) {
|
||||
long durationMS = parseDurationMS(durationString);
|
||||
end = durationMS < 0L ? -1L : start + durationMS;
|
||||
} else {
|
||||
try {
|
||||
this.end = parseDate(endString);
|
||||
} catch (ParseException pe) {
|
||||
throw new IllegalArgumentException(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;
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return start time
|
||||
* @deprecated use {@link #getStartTimestamp()}
|
||||
*/
|
||||
@Deprecated
|
||||
public Date getStart() {
|
||||
return new Date(start);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return start time
|
||||
* @see #getEndTimestamp()
|
||||
*/
|
||||
public long getStartTimestamp() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if start time was specified as a whole day
|
||||
*/
|
||||
public boolean isStartAllDay() {
|
||||
return startAllDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event end {@link Date}, or {@code null} if event has no duration
|
||||
* @deprecated use {@link #getEndTimestamp()}
|
||||
*/
|
||||
@Deprecated
|
||||
public Date getEnd() {
|
||||
return end < 0L ? null : new Date(end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event end {@link Date}, or -1 if event has no duration
|
||||
* @see #getStartTimestamp()
|
||||
*/
|
||||
public long getEndTimestamp() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if end time was specified as a whole day
|
||||
*/
|
||||
public boolean isEndAllDay() {
|
||||
return endAllDay;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public String getOrganizer() {
|
||||
return organizer;
|
||||
}
|
||||
|
||||
public String[] getAttendees() {
|
||||
return attendees;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayRXingResult() {
|
||||
StringBuilder 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);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @param when The string to parse
|
||||
* @throws ParseException if not able to parse as a date
|
||||
*/
|
||||
private static long parseDate(String when) throws ParseException {
|
||||
if (!DATE_TIME.matcher(when).matches()) {
|
||||
throw new ParseException(when, 0);
|
||||
}
|
||||
if (when.length() == 8) {
|
||||
// Show only year/month/day
|
||||
DateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
|
||||
// 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 format.parse(when).getTime();
|
||||
}
|
||||
// The when string can be local time, or UTC if it ends with a Z
|
||||
if (when.length() == 16 && when.charAt(15) == 'Z') {
|
||||
long 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);
|
||||
}
|
||||
return parseDateTimeString(when);
|
||||
}
|
||||
|
||||
private static String format(boolean allDay, long date) {
|
||||
if (date < 0L) {
|
||||
return null;
|
||||
}
|
||||
DateFormat format = allDay
|
||||
? DateFormat.getDateInstance(DateFormat.MEDIUM)
|
||||
: DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
|
||||
return format.format(date);
|
||||
}
|
||||
|
||||
private static long parseDurationMS(CharSequence durationString) {
|
||||
if (durationString == null) {
|
||||
return -1L;
|
||||
}
|
||||
Matcher m = RFC2445_DURATION.matcher(durationString);
|
||||
if (!m.matches()) {
|
||||
return -1L;
|
||||
}
|
||||
long durationMS = 0L;
|
||||
for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.length; i++) {
|
||||
String fieldValue = m.group(i + 1);
|
||||
if (fieldValue != null) {
|
||||
durationMS += RFC2445_DURATION_FIELD_UNITS[i] * Integer.parseInt(fieldValue);
|
||||
}
|
||||
}
|
||||
return durationMS;
|
||||
}
|
||||
|
||||
private static long parseDateTimeString(String dateTimeString) throws ParseException {
|
||||
DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH);
|
||||
return format.parse(dateTimeString).getTime();
|
||||
}
|
||||
|
||||
}
|
||||
313
src/client/result/CalendarParsedResult.rs
Normal file
313
src/client/result/CalendarParsedResult.rs
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// package com.google.zxing.client.result;
|
||||
|
||||
// import java.text.DateFormat;
|
||||
// import java.text.ParseException;
|
||||
// import java.text.SimpleDateFormat;
|
||||
// import java.util.Calendar;
|
||||
// import java.util.Date;
|
||||
// import java.util.GregorianCalendar;
|
||||
// import java.util.Locale;
|
||||
// import java.util.TimeZone;
|
||||
// import java.util.regex.Matcher;
|
||||
// import java.util.regex.Pattern;
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::exceptions::Exceptions;
|
||||
|
||||
use super::{
|
||||
maybe_append_multiple, maybe_append_string, ParsedRXingResult, ParsedRXingResultType,
|
||||
ResultParser,
|
||||
};
|
||||
|
||||
const RFC2445_DURATION: &'static str =
|
||||
"P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?";
|
||||
const RFC2445_DURATION_FIELD_UNITS: [i64; 5] = [
|
||||
7 * 24 * 60 * 60 * 1000i64, // 1 week
|
||||
24 * 60 * 60 * 1000i64, // 1 day
|
||||
60 * 60 * 1000i64, // 1 hour
|
||||
60 * 1000i64, // 1 minute
|
||||
1000i64, // 1 second
|
||||
];
|
||||
|
||||
const DATE_TIME: &'static str = "[0-9]{8}(T[0-9]{6}Z?)?";
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a calendar event at a certain time, optionally
|
||||
* with attendees and a location.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct CalendarParsedRXingResult {
|
||||
summary: String,
|
||||
start: i64,
|
||||
startAllDay: bool,
|
||||
end: i64,
|
||||
endAllDay: bool,
|
||||
location: String,
|
||||
organizer: String,
|
||||
attendees: Vec<String>,
|
||||
description: String,
|
||||
latitude: f64,
|
||||
longitude: f64,
|
||||
}
|
||||
|
||||
impl ParsedRXingResult for CalendarParsedRXingResult {
|
||||
fn getType(&self) -> super::ParsedRXingResultType {
|
||||
ParsedRXingResultType::CALENDAR
|
||||
}
|
||||
|
||||
fn getDisplayRXingResult(&self) -> String {
|
||||
let mut result = String::with_capacity(100);
|
||||
maybe_append_string(&self.summary, &mut result);
|
||||
maybe_append_string(
|
||||
&Self::format_event(self.startAllDay, self.start),
|
||||
&mut result,
|
||||
);
|
||||
maybe_append_string(&Self::format_event(self.endAllDay, self.end), &mut result);
|
||||
maybe_append_string(&self.location, &mut result);
|
||||
maybe_append_string(&self.organizer, &mut result);
|
||||
maybe_append_multiple(&self.attendees, &mut result);
|
||||
maybe_append_string(&self.description, &mut result);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl CalendarParsedRXingResult {
|
||||
pub fn new(
|
||||
summary: String,
|
||||
startString: String,
|
||||
endString: String,
|
||||
durationString: String,
|
||||
location: String,
|
||||
organizer: String,
|
||||
attendees: Vec<String>,
|
||||
description: String,
|
||||
latitude: f64,
|
||||
longitude: f64,
|
||||
) -> Result<Self, Exceptions> {
|
||||
let start = Self::parseDate(startString.clone())?;
|
||||
let end = if endString.is_empty() {
|
||||
let durationMS = Self::parseDurationMS(&durationString);
|
||||
if durationMS < 0i64 {
|
||||
-1i64
|
||||
} else {
|
||||
start + durationMS
|
||||
}
|
||||
} else {
|
||||
Self::parseDate(endString.clone())?
|
||||
};
|
||||
let startAllDay;
|
||||
let endAllDay;
|
||||
|
||||
// try {
|
||||
// this.start = parseDate(startString);
|
||||
// } catch (ParseException pe) {
|
||||
// throw new IllegalArgumentException(pe.toString());
|
||||
// }
|
||||
|
||||
// if (endString == null) {
|
||||
// long durationMS = parseDurationMS(durationString);
|
||||
// end = durationMS < 0L ? -1L : start + durationMS;
|
||||
// } else {
|
||||
// try {
|
||||
// this.end = parseDate(endString);
|
||||
// } catch (ParseException pe) {
|
||||
// throw new IllegalArgumentException(pe.toString());
|
||||
// }
|
||||
// }
|
||||
|
||||
startAllDay = startString.len() == 8;
|
||||
endAllDay = !endString.is_empty() && endString.len() == 8;
|
||||
|
||||
Ok(Self {
|
||||
summary,
|
||||
start,
|
||||
startAllDay,
|
||||
end,
|
||||
endAllDay,
|
||||
location,
|
||||
organizer,
|
||||
attendees,
|
||||
description,
|
||||
latitude,
|
||||
longitude,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @param when The string to parse
|
||||
* @throws ParseException if not able to parse as a date
|
||||
*/
|
||||
fn parseDate(when: String) -> Result<i64, Exceptions> {
|
||||
let date_time_regex = Regex::new(DATE_TIME).unwrap();
|
||||
if !date_time_regex.is_match(&when) {
|
||||
return Err(Exceptions::ParseException(when));
|
||||
}
|
||||
if when.len() == 8 {
|
||||
// Show only year/month/day
|
||||
let date_format_string = "%Y%m%d";
|
||||
// DateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
|
||||
// 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
|
||||
let dtm = DateTime::parse_from_str(&when, date_format_string).unwrap();
|
||||
let dtm = dtm.with_timezone(&Utc);
|
||||
|
||||
// format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
// return format.parse(when).getTime();
|
||||
return Ok(dtm.timestamp());
|
||||
}
|
||||
// The when string can be local time, or UTC if it ends with a Z
|
||||
if when.len() == 16 && when.chars().nth(15).unwrap() == 'Z' {
|
||||
let milliseconds = Self::parseDateTimeString(&when[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);
|
||||
return milliseconds;
|
||||
}
|
||||
Self::parseDateTimeString(&when)
|
||||
}
|
||||
|
||||
fn format_event(allDay: bool, date: i64) -> String {
|
||||
if date < 0 {
|
||||
return "".to_owned();
|
||||
}
|
||||
let format_string = if allDay { "%F" } else { "%c" };
|
||||
// DateFormat format = allDay
|
||||
// ? DateFormat.getDateInstance(DateFormat.MEDIUM)
|
||||
// : DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
|
||||
// return format.format(date);
|
||||
NaiveDateTime::from_timestamp(date, 0)
|
||||
.format(format_string)
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn parseDurationMS(durationString: &str) -> i64 {
|
||||
if durationString.is_empty() {
|
||||
return -1;
|
||||
}
|
||||
let regex = Regex::new(RFC2445_DURATION).unwrap();
|
||||
if let Some(m) = regex.captures(durationString) {
|
||||
let mut durationMS = 0i64;
|
||||
for i in 0..RFC2445_DURATION_FIELD_UNITS.len() {
|
||||
// for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.length; i++) {
|
||||
let fieldValue = m.get(i + 1);
|
||||
if fieldValue.is_some() {
|
||||
let z = fieldValue.unwrap().as_str().parse::<i64>().unwrap();
|
||||
durationMS += RFC2445_DURATION_FIELD_UNITS[i] * z;
|
||||
}
|
||||
}
|
||||
durationMS
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
// if (!m.matches()) {
|
||||
// return -1L;
|
||||
// }
|
||||
// long durationMS = 0L;
|
||||
// for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.length; i++) {
|
||||
// String fieldValue = m.group(i + 1);
|
||||
// if (fieldValue != null) {
|
||||
// durationMS += RFC2445_DURATION_FIELD_UNITS[i] * Integer.parseInt(fieldValue);
|
||||
// }
|
||||
// }
|
||||
// return durationMS;
|
||||
}
|
||||
|
||||
fn parseDateTimeString(dateTimeString: &str) -> Result<i64, Exceptions> {
|
||||
if let Ok(dtm) = DateTime::parse_from_str(dateTimeString, "%Y%m%dT%H%M%S") {
|
||||
Ok(dtm.timestamp())
|
||||
} else {
|
||||
Err(Exceptions::ParseException(format!(
|
||||
"Couldn't parse {}",
|
||||
dateTimeString
|
||||
)))
|
||||
}
|
||||
// DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH);
|
||||
// return format.parse(dateTimeString).getTime();
|
||||
}
|
||||
|
||||
pub fn getSummary(&self) -> &String {
|
||||
&self.summary
|
||||
}
|
||||
|
||||
/**
|
||||
* @return start time
|
||||
* @see #getEndTimestamp()
|
||||
*/
|
||||
pub fn getStartTimestamp(&self) -> i64 {
|
||||
self.start
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if start time was specified as a whole day
|
||||
*/
|
||||
pub fn isStartAllDay(&self) -> bool {
|
||||
self.startAllDay
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event end {@link Date}, or -1 if event has no duration
|
||||
* @see #getStartTimestamp()
|
||||
*/
|
||||
pub fn getEndTimestamp(&self) -> i64 {
|
||||
self.end
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if end time was specified as a whole day
|
||||
*/
|
||||
pub fn isEndAllDay(&self) -> bool {
|
||||
self.endAllDay
|
||||
}
|
||||
|
||||
pub fn getLocation(&self) -> &str {
|
||||
&self.location
|
||||
}
|
||||
|
||||
pub fn getOrganizer(&self) -> &str {
|
||||
&self.organizer
|
||||
}
|
||||
|
||||
pub fn getAttendees(&self) -> &Vec<String> {
|
||||
&self.attendees
|
||||
}
|
||||
|
||||
pub fn getDescription(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
|
||||
pub fn getLatitude(&self) -> f64 {
|
||||
self.latitude
|
||||
}
|
||||
|
||||
pub fn getLongitude(&self) -> f64 {
|
||||
self.longitude
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.result;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.RXingResult;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Tests {@link CalendarParsedRXingResult}.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class CalendarParsedRXingResultTestCase extends Assert {
|
||||
|
||||
private static final double EPSILON = 1.0E-10;
|
||||
|
||||
private static DateFormat makeGMTFormat() {
|
||||
DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.ENGLISH);
|
||||
format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
return format;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartEnd() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"DTEND:20080505T234555Z\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", "20080505T234555Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoVCalendar() {
|
||||
doTest(
|
||||
"BEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"DTEND:20080505T234555Z\r\n" +
|
||||
"END:VEVENT",
|
||||
null, null, null, "20080504T123456Z", "20080505T234555Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStart() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuration() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"DURATION:P1D\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", "20080505T123456Z");
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"DURATION:P1DT2H3M4S\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", "20080505T143800Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSummary() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"SUMMARY:foo\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, "foo", null, "20080504T123456Z", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocation() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"LOCATION:Miami\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, "Miami", "20080504T123456Z", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDescription() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"DESCRIPTION:This is a test\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
"This is a test", null, null, "20080504T123456Z", null);
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"DESCRIPTION:This is a test\r\n\t with a continuation\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
"This is a test with a continuation", null, null, "20080504T123456Z", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeo() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"GEO:-12.345;-45.678\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", null, null, null, -12.345, -45.678);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadGeo() {
|
||||
// Not parsed as VEVENT
|
||||
RXingResult fakeRXingResult = new RXingResult("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"GEO:-12.345\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR", null, null, BarcodeFormat.QR_CODE);
|
||||
ParsedRXingResult result = RXingResultParser.parseRXingResult(fakeRXingResult);
|
||||
assertSame(ParsedRXingResultType.TEXT, result.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrganizer() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"ORGANIZER:mailto:bob@example.org\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", null, "bob@example.org", null, Double.NaN, Double.NaN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttendees() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" +
|
||||
"DTSTART:20080504T123456Z\r\n" +
|
||||
"ATTENDEE:mailto:bob@example.org\r\n" +
|
||||
"ATTENDEE:mailto:alice@example.org\r\n" +
|
||||
"END:VEVENT\r\nEND:VCALENDAR",
|
||||
null, null, null, "20080504T123456Z", null, null,
|
||||
new String[] {"bob@example.org", "alice@example.org"}, Double.NaN, Double.NaN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVEventEscapes() {
|
||||
doTest("BEGIN:VEVENT\n" +
|
||||
"CREATED:20111109T110351Z\n" +
|
||||
"LAST-MODIFIED:20111109T170034Z\n" +
|
||||
"DTSTAMP:20111109T170034Z\n" +
|
||||
"UID:0f6d14ef-6cb7-4484-9080-61447ccdf9c2\n" +
|
||||
"SUMMARY:Summary line\n" +
|
||||
"CATEGORIES:Private\n" +
|
||||
"DTSTART;TZID=Europe/Vienna:20111110T110000\n" +
|
||||
"DTEND;TZID=Europe/Vienna:20111110T120000\n" +
|
||||
"LOCATION:Location\\, with\\, escaped\\, commas\n" +
|
||||
"DESCRIPTION:Meeting with a friend\\nlook at homepage first\\n\\n\n" +
|
||||
" \\n\n" +
|
||||
"SEQUENCE:1\n" +
|
||||
"X-MOZ-GENERATION:1\n" +
|
||||
"END:VEVENT",
|
||||
"Meeting with a friend\nlook at homepage first\n\n\n \n",
|
||||
"Summary line",
|
||||
"Location, with, escaped, commas",
|
||||
"20111110T110000Z",
|
||||
"20111110T120000Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllDayValueDate() {
|
||||
doTest("BEGIN:VEVENT\n" +
|
||||
"DTSTART;VALUE=DATE:20111110\n" +
|
||||
"DTEND;VALUE=DATE:20111110\n" +
|
||||
"END:VEVENT",
|
||||
null, null, null, "20111110T000000Z", "20111110T000000Z");
|
||||
}
|
||||
|
||||
private static void doTest(String contents,
|
||||
String description,
|
||||
String summary,
|
||||
String location,
|
||||
String startString,
|
||||
String endString) {
|
||||
doTest(contents, description, summary, location, startString, endString, null, null, Double.NaN, Double.NaN);
|
||||
}
|
||||
|
||||
private static void doTest(String contents,
|
||||
String description,
|
||||
String summary,
|
||||
String location,
|
||||
String startString,
|
||||
String endString,
|
||||
String organizer,
|
||||
String[] attendees,
|
||||
double latitude,
|
||||
double longitude) {
|
||||
RXingResult fakeRXingResult = new RXingResult(contents, null, null, BarcodeFormat.QR_CODE);
|
||||
ParsedRXingResult result = RXingResultParser.parseRXingResult(fakeRXingResult);
|
||||
assertSame(ParsedRXingResultType.CALENDAR, result.getType());
|
||||
CalendarParsedRXingResult calRXingResult = (CalendarParsedRXingResult) result;
|
||||
assertEquals(description, calRXingResult.getDescription());
|
||||
assertEquals(summary, calRXingResult.getSummary());
|
||||
assertEquals(location, calRXingResult.getLocation());
|
||||
DateFormat dateFormat = makeGMTFormat();
|
||||
assertEquals(startString, dateFormat.format(calRXingResult.getStartTimestamp()));
|
||||
assertEquals(endString, calRXingResult.getEndTimestamp() < 0L ? null : dateFormat.format(calRXingResult.getEndTimestamp()));
|
||||
assertEquals(organizer, calRXingResult.getOrganizer());
|
||||
assertArrayEquals(attendees, calRXingResult.getAttendees());
|
||||
assertEqualOrNaN(latitude, calRXingResult.getLatitude());
|
||||
assertEqualOrNaN(longitude, calRXingResult.getLongitude());
|
||||
}
|
||||
|
||||
private static void assertEqualOrNaN(double expected, double actual) {
|
||||
if (Double.isNaN(expected)) {
|
||||
assertTrue(Double.isNaN(actual));
|
||||
} else {
|
||||
assertEquals(expected, actual, EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
257
src/client/result/CalendarParsedResultTestCase.rs
Normal file
257
src/client/result/CalendarParsedResultTestCase.rs
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// package com.google.zxing.client.result;
|
||||
|
||||
// import com.google.zxing.BarcodeFormat;
|
||||
// import com.google.zxing.RXingResult;
|
||||
// import org.junit.Assert;
|
||||
// import org.junit.Before;
|
||||
// import org.junit.Test;
|
||||
|
||||
// import java.text.DateFormat;
|
||||
// import java.text.SimpleDateFormat;
|
||||
// import java.util.Locale;
|
||||
// import java.util.TimeZone;
|
||||
|
||||
// /**
|
||||
// * Tests {@link CalendarParsedRXingResult}.
|
||||
// *
|
||||
// * @author Sean Owen
|
||||
// */
|
||||
// public final class CalendarParsedRXingResultTestCase extends Assert {
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
|
||||
use crate::{
|
||||
client::result::{ParsedClientResult, ParsedRXingResultType},
|
||||
BarcodeFormat, RXingResult,
|
||||
};
|
||||
|
||||
use super::{ParsedRXingResult, ResultParser};
|
||||
|
||||
const EPSILON: f64 = 1.0E-10;
|
||||
const DATE_FORMAT_STRING: &'static str = "yyyyMMdd'T'HHmmss'Z'";
|
||||
|
||||
// private static DateFormat makeGMTFormat() {
|
||||
// DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.ENGLISH);
|
||||
// format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
// return format;
|
||||
// }
|
||||
|
||||
// @Before
|
||||
// public void setUp() {
|
||||
// Locale.setDefault(Locale.ENGLISH);
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn testStartEnd() {
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nDTEND:20080505T234555Z\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "20080505T234555Z");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testNoVCalendar() {
|
||||
doTestShort(
|
||||
"BEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nDTEND:20080505T234555Z\r\nEND:VEVENT",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"20080504T123456Z",
|
||||
"20080505T234555Z",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testStart() {
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testDuration() {
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nDURATION:P1D\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "20080505T123456Z");
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nDURATION:P1DT2H3M4S\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "20080505T143800Z");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testSummary() {
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nSUMMARY:foo\r\nDTSTART:20080504T123456Z\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "foo", "", "20080504T123456Z", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testLocation() {
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nLOCATION:Miami\r\nDTSTART:20080504T123456Z\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "Miami", "20080504T123456Z", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testDescription() {
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nDESCRIPTION:This is a test\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"This is a test", "", "", "20080504T123456Z", "");
|
||||
doTestShort(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nDESCRIPTION:This is a test\r\n\t with a continuation\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"This is a test with a continuation", "", "", "20080504T123456Z", "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testGeo() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nGEO:-12.345;-45.678\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "", "", &Vec::new(), -12.345, -45.678);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testBadGeo() {
|
||||
// Not parsed as VEVENT
|
||||
let fakeRXingResult = RXingResult::new(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nGEO:-12.345\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
BarcodeFormat::QR_CODE,
|
||||
);
|
||||
let result = ResultParser::parseRXingResult(&fakeRXingResult);
|
||||
assert_eq!(ParsedRXingResultType::TEXT, result.getType());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testOrganizer() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nORGANIZER:mailto:bob@example.org\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "", "bob@example.org", &Vec::new(), f64::NAN, f64::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testAttendees() {
|
||||
doTest(
|
||||
"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20080504T123456Z\r\nATTENDEE:mailto:bob@example.org\r\nATTENDEE:mailto:alice@example.org\r\nEND:VEVENT\r\nEND:VCALENDAR",
|
||||
"", "", "", "20080504T123456Z", "", "",
|
||||
&vec!["bob@example.org", "alice@example.org"], f64::NAN, f64::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testVEventEscapes() {
|
||||
doTestShort("BEGIN:VEVENT\nCREATED:20111109T110351Z\nLAST-MODIFIED:20111109T170034Z\nDTSTAMP:20111109T170034Z\nUID:0f6d14ef-6cb7-4484-9080-61447ccdf9c2\nSUMMARY:Summary line\nCATEGORIES:Private\nDTSTART;TZID=Europe/Vienna:20111110T110000\nDTEND;TZID=Europe/Vienna:20111110T120000\nLOCATION:Location\\, with\\, escaped\\, commas\nDESCRIPTION:Meeting with a friend\\nlook at homepage first\\n\\n\n \\n\nSEQUENCE:1\nX-MOZ-GENERATION:1\nEND:VEVENT",
|
||||
"Meeting with a friend\nlook at homepage first\n\n\n \n",
|
||||
"Summary line",
|
||||
"Location, with, escaped, commas",
|
||||
"20111110T110000Z",
|
||||
"20111110T120000Z");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testAllDayValueDate() {
|
||||
doTestShort(
|
||||
"BEGIN:VEVENT\nDTSTART;VALUE=DATE:20111110\nDTEND;VALUE=DATE:20111110\nEND:VEVENT",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"20111110T000000Z",
|
||||
"20111110T000000Z",
|
||||
);
|
||||
}
|
||||
|
||||
fn doTestShort(
|
||||
contents: &str,
|
||||
description: &str,
|
||||
summary: &str,
|
||||
location: &str,
|
||||
startString: &str,
|
||||
endString: &str,
|
||||
) {
|
||||
doTest(
|
||||
contents,
|
||||
description,
|
||||
summary,
|
||||
location,
|
||||
startString,
|
||||
endString,
|
||||
"",
|
||||
&Vec::new(),
|
||||
f64::NAN,
|
||||
f64::NAN,
|
||||
);
|
||||
}
|
||||
|
||||
fn doTest(
|
||||
contents: &str,
|
||||
description: &str,
|
||||
summary: &str,
|
||||
location: &str,
|
||||
startString: &str,
|
||||
endString: &str,
|
||||
organizer: &str,
|
||||
attendees: &[&str],
|
||||
latitude: f64,
|
||||
longitude: f64,
|
||||
) {
|
||||
let fakeRXingResult =
|
||||
RXingResult::new(contents, Vec::new(), Vec::new(), BarcodeFormat::QR_CODE);
|
||||
let result = ResultParser::parseRXingResult(&fakeRXingResult);
|
||||
assert_eq!(ParsedRXingResultType::CALENDAR, result.getType());
|
||||
if let ParsedClientResult::CalendarEventResult(calRXingResult) = result {
|
||||
assert_eq!(description, calRXingResult.getDescription());
|
||||
assert_eq!(summary, calRXingResult.getSummary());
|
||||
assert_eq!(location, calRXingResult.getLocation());
|
||||
let dateFormat = "%c"; //makeGMTFormat();
|
||||
assert_eq!(
|
||||
startString,
|
||||
format_date_string(calRXingResult.getStartTimestamp(), dateFormat) // dateFormat.format(calRXingResult.getStartTimestamp())
|
||||
);
|
||||
assert_eq!(
|
||||
endString,
|
||||
if calRXingResult.getEndTimestamp() < 0i64 {
|
||||
"".to_owned()
|
||||
} else {
|
||||
format_date_string(calRXingResult.getEndTimestamp(), dateFormat)
|
||||
// dateFormat.format(calRXingResult.getEndTimestamp())
|
||||
}
|
||||
);
|
||||
assert_eq!(organizer, calRXingResult.getOrganizer());
|
||||
assert_eq!(attendees, calRXingResult.getAttendees());
|
||||
assertEqualOrNaN(latitude, calRXingResult.getLatitude());
|
||||
assertEqualOrNaN(longitude, calRXingResult.getLongitude());
|
||||
} else {
|
||||
panic!("Expected Calendar");
|
||||
}
|
||||
}
|
||||
|
||||
fn assertEqualOrNaN(expected: f64, actual: f64) {
|
||||
if expected.is_nan() {
|
||||
assert!(actual.is_nan());
|
||||
} else {
|
||||
assert!(expected - actual < EPSILON && actual - expected < EPSILON);
|
||||
// assert_eq!(expected, actual, EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
fn format_date_string(timestamp: i64, format_string: &str) -> String {
|
||||
NaiveDateTime::from_timestamp(timestamp, 0)
|
||||
.format(format_string)
|
||||
.to_string()
|
||||
// DateTime::from(timestamp,0).with_timezone(Utc).format(format_string).to_string()
|
||||
}
|
||||
@@ -153,7 +153,7 @@ pub fn parse(result: &RXingResult) -> Option<ParsedClientResult> {
|
||||
}
|
||||
}
|
||||
|
||||
fn matchVCardPrefixedField(
|
||||
pub fn matchVCardPrefixedField(
|
||||
prefix: &str,
|
||||
rawText: &str,
|
||||
trim: bool,
|
||||
@@ -427,7 +427,7 @@ fn maybeAppendFragment(fragmentBuffer: &mut Vec<u8>, charset: &str, result: &mut
|
||||
}
|
||||
}
|
||||
|
||||
fn matchSingleVCardPrefixedField(
|
||||
pub fn matchSingleVCardPrefixedField(
|
||||
prefix: &str,
|
||||
rawText: &str,
|
||||
trim: bool,
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.zxing.client.result;
|
||||
|
||||
import com.google.zxing.RXingResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Partially implements the iCalendar format's "VEVENT" format for specifying a
|
||||
* calendar event. See RFC 2445. This supports SUMMARY, LOCATION, GEO, DTSTART and DTEND fields.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class VEventRXingResultParser extends RXingResultParser {
|
||||
|
||||
@Override
|
||||
public CalendarParsedRXingResult parse(RXingResult result) {
|
||||
String rawText = getMassagedText(result);
|
||||
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;
|
||||
}
|
||||
try {
|
||||
latitude = Double.parseDouble(geoString.substring(0, semicolon));
|
||||
longitude = Double.parseDouble(geoString.substring(semicolon + 1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return new CalendarParsedRXingResult(summary,
|
||||
start,
|
||||
end,
|
||||
duration,
|
||||
location,
|
||||
organizer,
|
||||
attendees,
|
||||
description,
|
||||
latitude,
|
||||
longitude);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String matchSingleVCardPrefixedField(CharSequence prefix,
|
||||
String rawText) {
|
||||
List<String> values = VCardRXingResultParser.matchSingleVCardPrefixedField(prefix, rawText, true, false);
|
||||
return values == null || values.isEmpty() ? null : values.get(0);
|
||||
}
|
||||
|
||||
private static String[] matchVCardPrefixedField(CharSequence prefix, String rawText) {
|
||||
List<List<String>> values = VCardRXingResultParser.matchVCardPrefixedField(prefix, rawText, true, false);
|
||||
if (values == null || values.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
int size = values.size();
|
||||
String[] result = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = values.get(i).get(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String stripMailto(String s) {
|
||||
if (s != null && (s.startsWith("mailto:") || s.startsWith("MAILTO:"))) {
|
||||
s = s.substring(7);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
174
src/client/result/VEventResultParser.rs
Normal file
174
src/client/result/VEventResultParser.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// package com.google.zxing.client.result;
|
||||
|
||||
// import com.google.zxing.RXingResult;
|
||||
|
||||
// import java.util.List;
|
||||
|
||||
use crate::RXingResult;
|
||||
|
||||
use super::{CalendarParsedRXingResult, ParsedClientResult, ResultParser, VCardResultParser};
|
||||
|
||||
/**
|
||||
* Partially implements the iCalendar format's "VEVENT" format for specifying a
|
||||
* calendar event. See RFC 2445. This supports SUMMARY, LOCATION, GEO, DTSTART and DTEND fields.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub fn parse(result: &RXingResult) -> Option<ParsedClientResult> {
|
||||
let rawText = ResultParser::getMassagedText(result);
|
||||
if let None = rawText.find("BEGIN:VEVENT") {
|
||||
return None;
|
||||
}
|
||||
// if (vEventStart < 0) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
let summary = matchSingleVCardPrefixedField("SUMMARY", &rawText);
|
||||
let start = matchSingleVCardPrefixedField("DTSTART", &rawText);
|
||||
if start.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let end = matchSingleVCardPrefixedField("DTEND", &rawText);
|
||||
let duration = matchSingleVCardPrefixedField("DURATION", &rawText);
|
||||
let location = matchSingleVCardPrefixedField("LOCATION", &rawText);
|
||||
let organizer = stripMailto(&matchSingleVCardPrefixedField("ORGANIZER", &rawText));
|
||||
|
||||
let mut attendees = matchVCardPrefixedField("ATTENDEE", &rawText);
|
||||
if !attendees.is_empty() {
|
||||
for i in 0..attendees.len() {
|
||||
// for (int i = 0; i < attendees.length; i++) {
|
||||
attendees[i] = stripMailto(&attendees[i]);
|
||||
}
|
||||
}
|
||||
let description = matchSingleVCardPrefixedField("DESCRIPTION", &rawText);
|
||||
|
||||
let geoString = matchSingleVCardPrefixedField("GEO", &rawText);
|
||||
let latitude;
|
||||
let longitude;
|
||||
if geoString.is_empty() {
|
||||
latitude = f64::NAN;
|
||||
longitude = f64::NAN;
|
||||
} else {
|
||||
if let Some(semicolon) = geoString.find(';') {
|
||||
latitude = if let Ok(l) = geoString[..semicolon].parse() {
|
||||
l
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
longitude = if let Ok(l) = geoString[semicolon + 1..].parse() {
|
||||
l
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
// if (semicolon < 0) {
|
||||
// return null;
|
||||
// }
|
||||
// try {
|
||||
// latitude = Double.parseDouble(geoString.substring(0, semicolon));
|
||||
// longitude = Double.parseDouble(geoString.substring(semicolon + 1));
|
||||
// } catch (NumberFormatException ignored) {
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
||||
if let Ok(cpr) = CalendarParsedRXingResult::new(
|
||||
summary,
|
||||
start,
|
||||
end,
|
||||
duration,
|
||||
location,
|
||||
organizer,
|
||||
attendees,
|
||||
description,
|
||||
latitude,
|
||||
longitude,
|
||||
) {
|
||||
Some(ParsedClientResult::CalendarEventResult(cpr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
// try {
|
||||
// return new CalendarParsedRXingResult(summary,
|
||||
// start,
|
||||
// end,
|
||||
// duration,
|
||||
// location,
|
||||
// organizer,
|
||||
// attendees,
|
||||
// description,
|
||||
// latitude,
|
||||
// longitude);
|
||||
// } catch (IllegalArgumentException ignored) {
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
||||
fn matchSingleVCardPrefixedField(prefix: &str, rawText: &str) -> String {
|
||||
if let Some(values) =
|
||||
VCardResultParser::matchSingleVCardPrefixedField(prefix, rawText, true, false)
|
||||
{
|
||||
if values.is_empty() {
|
||||
"".to_owned()
|
||||
} else {
|
||||
values.get(0).unwrap().clone()
|
||||
}
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
// return values == null || values.isEmpty() ? null : values.get(0);
|
||||
}
|
||||
|
||||
fn matchVCardPrefixedField(prefix: &str, rawText: &str) -> Vec<String> {
|
||||
if let Some(values) = VCardResultParser::matchVCardPrefixedField(prefix, rawText, true, false) {
|
||||
if values.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
let size = values.len();
|
||||
let mut result = vec!["".to_owned(); size]; //new String[size];
|
||||
for i in 0..size {
|
||||
// for (int i = 0; i < size; i++) {
|
||||
result[i] = values.get(i).unwrap().get(0).unwrap().clone();
|
||||
}
|
||||
result
|
||||
}
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
// if values == null || values.isEmpty() {
|
||||
// return null;
|
||||
// }
|
||||
// int size = values.size();
|
||||
// String[] result = new String[size];
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// result[i] = values.get(i).get(0);
|
||||
// }
|
||||
// return result;
|
||||
}
|
||||
|
||||
fn stripMailto(s: &str) -> String {
|
||||
let mut s = s;
|
||||
if !s.is_empty() && (s.starts_with("mailto:") || s.starts_with("MAILTO:")) {
|
||||
s = &s[7..];
|
||||
}
|
||||
s.to_owned()
|
||||
}
|
||||
@@ -31,6 +31,8 @@ mod AddressBookDoCoMoResultParser;
|
||||
mod AddressBookAUResultParser;
|
||||
mod VCardResultParser;
|
||||
mod BizcardResultParser;
|
||||
mod CalendarParsedResult;
|
||||
mod VEventResultParser;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
@@ -52,6 +54,8 @@ pub use URIParsedResult::*;
|
||||
pub use EmailAddressParsedResult::*;
|
||||
pub use VINParsedResult::*;
|
||||
pub use AddressBookParsedResult::*;
|
||||
pub use CalendarParsedResult::*;
|
||||
pub use CalendarParsedResult::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod TelParsedResultTestCase;
|
||||
@@ -73,6 +77,8 @@ mod EmailAddressParsedResultTestCase;
|
||||
mod VINParsedResultTestCase;
|
||||
#[cfg(test)]
|
||||
mod AddressBookParsedResultTestCase;
|
||||
#[cfg(test)]
|
||||
mod CalendarParsedResultTestCase;
|
||||
|
||||
pub enum ParsedClientResult {
|
||||
TextResult(TextParsedRXingResult),
|
||||
@@ -86,6 +92,7 @@ pub enum ParsedClientResult {
|
||||
EmailResult(EmailAddressParsedRXingResult),
|
||||
VINResult(VINParsedRXingResult),
|
||||
AddressBookResult(AddressBookParsedRXingResult),
|
||||
CalendarEventResult(CalendarParsedRXingResult),
|
||||
}
|
||||
|
||||
impl ParsedRXingResult for ParsedClientResult {
|
||||
@@ -102,6 +109,7 @@ impl ParsedRXingResult for ParsedClientResult {
|
||||
ParsedClientResult::EmailResult(a) => a.getType(),
|
||||
ParsedClientResult::VINResult(a) => a.getType(),
|
||||
ParsedClientResult::AddressBookResult(a) => a.getType(),
|
||||
ParsedClientResult::CalendarEventResult(a) => a.getType(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +126,7 @@ impl ParsedRXingResult for ParsedClientResult {
|
||||
ParsedClientResult::EmailResult(a) => a.getDisplayRXingResult(),
|
||||
ParsedClientResult::VINResult(a) => a.getDisplayRXingResult(),
|
||||
ParsedClientResult::AddressBookResult(a) => a.getDisplayRXingResult(),
|
||||
ParsedClientResult::CalendarEventResult(a) => a.getDisplayRXingResult(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user