#ifndef ACCEPTLANGUAGE_H #define ACCEPTLANGUAGE_H /* * @(#)AcceptLanguage.h * * This file is part of webCDwriter - Network CD Writing. * * Copyright (C) 2002-2004 Jörg P. M. Haeger * * webCDwriter is free software. See CDWserver.cpp for details. */ #include "Config.h" #include "File.h" #include "FileInputStream.h" #include "Log.h" #include "String.h" #include "StringBuffer.h" const int localesMax = 20; /** * Support for "Accept-Language" of HTTP. * * @version 20041013 * @author Jörg P. M. Haeger */ class AcceptLanguage { struct { char l1, l2, c1, c2; int q; } locales[localesMax]; int count; String webCDcreatorLanguage, webCDcreatorCountry; int fileLastModified; public: AcceptLanguage() { log.debug("AcceptLanguage", "()"); count = 0; webCDcreatorLanguage = ""; webCDcreatorCountry = ""; fileLastModified = 0; } ~AcceptLanguage() { log.debug("AcceptLanguage", "~() count = %d", count); } void operator=(AcceptLanguage &orig) { log.debug("AcceptLanguage", "operator="); for (int i = 0; i < orig.count; i++) locales[i] = orig.locales[i]; count = orig.count; webCDcreatorLanguage = orig.webCDcreatorLanguage; webCDcreatorCountry = orig.webCDcreatorCountry; } void add(String &language) { if (count == localesMax) return; if (language.length() < 2) return; char l1 = language.charAt(0); if (l1 < 'a') l1 += ('a' - 'A'); char l2 = language.charAt(1); if (l2 < 'a') l2 += ('a' - 'A'); if (l1 < 'a' || l1 > 'z' || l2 < 'a' || l2 > 'z') return; char c1 = ' ', c2 = ' '; int i = 2; if (i + 2 < language.length() && (language.charAt(i) == '-' || language.charAt(i) == '_')) { c1 = language.charAt(i + 1); if (c1 > 'Z') c1 -= ('z' - 'Z'); c2 = language.charAt(i + 2); if (c2 > 'Z') c2 -= ('z' - 'Z'); if (c1 < 'A' || c1 > 'Z' || c2 < 'A' || c2 > 'Z') return; i += 3; } int q = 100; if (i + 2 < language.length() && language.charAt(i) == ';' && language.charAt(i + 1) == 'q' && language.charAt(i + 2) == '=') { i += 3; while (i < language.length() && language.charAt(i) == '0') i++; if (i + 1 < language.length() && language.charAt(i) == '.' && language.charAt(i + 1) >= '0' && language.charAt(i + 1) <= '9') q = 10 * (language.charAt(i + 1) - '0'); if (i + 2 < language.length() && language.charAt(i + 2) >= '0' && language.charAt(i + 2) <= '9') q += language.charAt(i + 2) - '0'; } for (i = 0; i < count && locales[i].q >= q; i++) ; for (int j = count; j > i; j--) locales[j] = locales[j - 1]; locales[i].l1 = l1; locales[i].l2 = l2; locales[i].c1 = c1; locales[i].c2 = c2; locales[i].q = q; log.debug("AcceptLanguage", "%c%c%c%c %d", locales[i].l1, locales[i].l2, locales[i].c1, locales[i].c2, locales[i].q); count++; } int getFileLastModified() { return fileLastModified; } String *getLocales() { StringBuffer str; for (int i = 0; i < count; i++) { // str.append(i + 1); // str.append(": "); append(str, i); if (i < count - 1) str.append(", "); } return new String(str); } String &getWebCDcreatorCountry() { getWebCDcreatorLanguage(); return webCDcreatorCountry; } String &getWebCDcreatorLanguage() { if (webCDcreatorLanguage.length() == 0) for (int i = 0; i < count; i++) { StringBuffer strBuf; strBuf.append("webCDcreator/i18n/Messages_"); append(strBuf, i); strBuf.append(".properties"); String name = new String(strBuf); // log.debug("AcceptLanguage", "%s", name.getBytes()); File msgsFile = new File(config.getHttpDir(), name); if (msgsFile.exists()) { webCDcreatorLanguage = webCDcreatorLanguage + locales[i].l1 + locales[i].l2; if (locales[i].c1 >= 'A') webCDcreatorCountry = webCDcreatorCountry + locales[i].c1 + locales[i].c2; break; } } return webCDcreatorLanguage; } static int i18n(StringBuffer &buf, int p0, int p1, StringBuffer &msgs) { int i = 0, n = msgs.length(); for (; i < n; i++) { int j = 0; for (; p0 + j < p1; i++, j++) if (buf.charAt(p0 + j) != msgs.charAt(i)) break; if (p0 + j == p1) { while (i < n && msgs.charAt(i) == ' ') i++; if (i < n && msgs.charAt(i) == '=') break; } // go to the end of the line while (i < n && msgs.charAt(i) != '\n') i++; } // printf("n = %d, i = %d, p0 = %d, p1 = %d\n", n, i, p0, p1); if (i < n) { buf.delete_(p0, p1); i++; while (i < n && msgs.charAt(i) == ' ') i++; for (; i < n && msgs.charAt(i) != '\n'; i++, p0++) { if (msgs.charAt(i) == '\\' && i + 1 < n && msgs.charAt(i + 1) == '\n') { // skip \ + LF i += 2; if (i == n || msgs.charAt(i) == '\n') break; } buf.insert(p0, (char)msgs.charAt(i)); } } return i; } StringBuffer &i18n(StringBuffer &buf) { StringBuffer msgsBufs[count + 1]; int n = 0; for (int i = 0; i < count; i++) { String name = "messages"; name = name + '_' + locales[i].l1 + locales[i].l2; if (locales[i].c1 >= 'A') name = name + '_' + locales[i].c1 + locales[i].c2; File msgsFile = new File(config.getHttpDir(), name); if (msgsFile.exists()) msgsBufs[n++] = read(msgsFile); if (name.equals("messages_en")) break; } // add the default messages File msgsFile = new File(config.getHttpDir(), "messages"); if (msgsFile.exists()) msgsBufs[n++] = read(msgsFile); for (int i = 0; i < 1000; i++) { int p0 = buf.indexOf(""); if (p0 < 0) break; buf.delete_(p0, p0 + 6); int p1 = buf.indexOf("", p0); if (p1 < 0) break; buf.delete_(p1, p1 + 7); // look for a translation for (int j = 0; j < n; j++) if (i18n(buf, p0, p1, msgsBufs[j]) < msgsBufs[j].length()) break; } return buf; } StringBuffer *load(File &file) { String str = file.getPath(); int dot = str.length(); for (int i = str.length() - 1; i >= 0; i--) if (str.charAt(i) == '.') { dot = i; break; } if (dot > 2 && str.charAt(dot - 3) == '_') { if (!file.exists()) { String path = file.getPath(); int p0 = path.indexOf("_en."); if (p0 > 0) { String path2 = ""; path2 = path2 + path.substring(0, p0) + path.substring(p0 + 3); file = new File(path2); } } fileLastModified = file.lastModified(); return read(file); } for (int i = 0; i < count; i++) { StringBuffer buf; for (int j = 0; j < dot; j++) buf.append((char)str.charAt(j)); buf.append('_'); append(buf, i); for (int j = dot; j < str.length(); j++) buf.append((char)str.charAt(j)); // log.debug("AcceptLanguage", "%s", String(buf).getBytes()); File f = new File(new String(buf)); if (f.exists()) { fileLastModified = f.lastModified(); return read(f); } if (locales[i].l1 == 'e' && locales[i].l2 == 'n' && locales[i].c1 < 'A' && file.exists()) { fileLastModified = file.lastModified(); return read(file); } } fileLastModified = file.lastModified(); return read(file); } private: StringBuffer &append(StringBuffer &strBuf, int i) { strBuf.append(locales[i].l1); strBuf.append(locales[i].l2); if (locales[i].c1 >= 'A') { strBuf.append('_'); strBuf.append(locales[i].c1); strBuf.append(locales[i].c2); } return strBuf; } static StringBuffer *read(File &file) { StringBuffer *str = new StringBuffer(file.getSize()); FileInputStream in = new FileInputStream(file); while (1) { char buf[4094]; int n = in.read(buf, 0, sizeof buf); if (n <= 0) break; str->append(buf, 0, n); } return str; } }; #endif