blob: 789cf1dcf45f2b5667687515bda35adb97b162d3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.asterix.external.classad;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.asterix.om.base.AMutableInt32;
public class Util {
// convert escapes in-place
// the string can only shrink while converting escapes so we can safely convert in-place.
private static final Pattern OCTAL = Pattern.compile("\\\\([0-3][0-7]{0,2})");
public static boolean convertEscapes(AMutableCharArrayString text) {
boolean validStr = true;
if (text.getLength() == 0) {
return true;
}
int dest = 0;
boolean hasOctal = false;
for (int source = 0; source < text.getLength(); ++source) {
char ch = text.charAt(source);
// scan for escapes, a terminating slash cannot be an escape
if (ch == '\\' && source < text.getLength() - 1) {
++source; // skip the \ character
ch = text.charAt(source);
// The escape part should be re-validated
switch (ch) {
case 'b':
ch = '\b';
break;
case 'f':
ch = '\f';
break;
case 'n':
ch = '\n';
break;
case 'r':
ch = '\r';
break;
case 't':
ch = '\t';
break;
case '\\':
ch = '\\';
break;
default:
if (Lexer.isodigit(ch)) {
hasOctal = true;
++dest;
}
break;
}
}
if (dest == source) {
// no need to assign ch to text when we haven't seen any escapes yet.
// text[dest] = ch;
++dest;
} else {
try {
text.erase(dest);
text.setChar(dest, ch);
++dest;
--source;
} catch (Throwable th) {
th.printStackTrace();
}
}
}
if (dest < text.getLength()) {
text.erase(dest);
text.setLength(dest);
}
// silly, but to fulfull the original contract for this function
// we need to remove the last character in the string if it is a '\0'
// (earlier logic guaranteed that a '\0' can ONLY be the last character)
if (text.getLength() > 0 && (text.charAt(text.getLength() - 1) == '\0')) {
text.erase(text.getLength() - 1);
}
if (hasOctal) {
Matcher m = OCTAL.matcher(text.toString());
StringBuffer out = new StringBuffer();
while (m.find()) {
int octet = Integer.parseInt(m.group(1), 8);
if (octet == 0 || octet > 255) {
return false;
}
m.appendReplacement(out, String.valueOf((char) octet));
}
m.appendTail(out);
text.setValue(new String(out.toString().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
}
return validStr;
}
public static Random initialized = new Random((new Date()).getTime());
public static int getRandomInteger() {
return initialized.nextInt();
}
public static double getRandomReal() {
return initialized.nextDouble();
}
public static int timezoneOffset(ClassAdTime clock) {
return clock.getOffset();
}
public static void getLocalTime(ClassAdTime now, ClassAdTime localtm) {
localtm.setValue(Calendar.getInstance(), now);
localtm.isAbsolute(true);
}
public static void absTimeToString(ClassAdTime atime, AMutableCharArrayString buffer) {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
//"yyyy-MM-dd'T'HH:mm:ss"
//2004-01-01T00:00:00+11:00
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
buffer.appendString(formatter.format(atime.getCalendar().getTime()));
buffer.appendString(
(atime.getOffset() >= 0 ? "+" : "-") + String.format("%02d", (Math.abs(atime.getOffset()) / 3600000))
+ ":" + String.format("%02d", ((Math.abs(atime.getOffset() / 60) % 60))));
}
public static void relTimeToString(long rsecs, AMutableCharArrayString buffer) {
double fractional_seconds;
int days, hrs, mins;
double secs;
if (rsecs < 0) {
buffer.appendChar('-');
rsecs = -rsecs;
}
fractional_seconds = rsecs % 1000;
days = (int) (rsecs / 1000);
hrs = days % 86400;
mins = hrs % 3600;
secs = (mins % 60) + (fractional_seconds / 1000.0);
days = days / 86400;
hrs = hrs / 3600;
mins = mins / 60;
if (days != 0) {
if (fractional_seconds == 0) {
buffer.appendString(String.format("%d+%02d:%02d:%02d", days, hrs, mins, (int) secs));
} else {
buffer.appendString(String.format("%d+%02d:%02d:%g", days, hrs, mins, secs));
}
} else if (hrs != 0) {
if (fractional_seconds == 0) {
buffer.appendString(String.format("%02d:%02d:%02d", hrs, mins, (int) secs));
} else {
buffer.appendString(String.format("%02d:%02d:%02g", hrs, mins, secs));
}
} else if (mins != 0) {
if (fractional_seconds == 0) {
buffer.appendString(String.format("%02d:%02d", mins, (int) secs));
} else {
buffer.appendString(String.format("%02d:%02g", mins, secs));
}
return;
} else {
if (fractional_seconds == 0) {
buffer.appendString(String.format("%02d", (int) secs));
} else {
buffer.appendString(String.format("%02g", secs));
}
}
}
public static void dayNumbers(int year, int month, int day, AMutableInt32 weekday, AMutableInt32 yearday) {
int fixed = fixedFromGregorian(year, month, day);
int jan1_fixed = fixedFromGregorian(year, 1, 1);
weekday.setValue(fixed % 7);
yearday.setValue(fixed - jan1_fixed);
return;
}
public static int fixedFromGregorian(int year, int month, int day) {
int fixed;
int month_adjustment;
if (month <= 2) {
month_adjustment = 0;
} else if (isLeapYear(year)) {
month_adjustment = -1;
} else {
month_adjustment = -2;
}
fixed = 365 * (year - 1) + ((year - 1) / 4) - ((year - 1) / 100) + ((year - 1) / 400)
+ ((367 * month - 362) / 12) + month_adjustment + day;
return fixed;
}
public static boolean isLeapYear(int year) {
int mod4;
int mod400;
boolean leap_year;
mod4 = year % 4;
mod400 = year % 400;
if (mod4 == 0 && mod400 != 100 && mod400 != 200 && mod400 != 300) {
leap_year = true;
} else {
leap_year = false;
}
return leap_year;
}
public static int isInf(double x) {
if (Double.isInfinite(x)) {
return (x < 0.0) ? (-1) : 1;
}
return 0;
}
public static boolean isNan(double x) {
return Double.isNaN(x);
}
}