diff options
Diffstat (limited to 'chromium/third_party')
150 files changed, 14819 insertions, 55 deletions
diff --git a/chromium/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp b/chromium/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp index c499b7c9ab9..f09ab370ab8 100644 --- a/chromium/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp +++ b/chromium/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp @@ -20,12 +20,17 @@ v8::Local<v8::Value> toV8(DOMWindow* window, v8::Local<v8::Object> creationConte if (UNLIKELY(!window)) return v8::Null(isolate); - // Initializes environment of a frame, and return the global object - // of the frame. - Frame * frame = window->frame(); - if (!frame) + + // TODO(yukishiino): There must be no case to return undefined. + // 'window', 'frames' and 'self' attributes in Window interface return + // the WindowProxy object of the browsing context, which never be undefined. + // 'top' and 'parent' attributes return the same when detached. Therefore, + // there must be no case to return undefined. + // See http://crbug.com/621730 and http://crbug.com/621577 . + if (!window->isCurrentlyDisplayedInFrame()) return v8Undefined(); + Frame* frame = window->frame(); return frame->windowProxy(DOMWrapperWorld::current(isolate))->globalIfNotDetached(); } diff --git a/chromium/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp b/chromium/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp index ae45713e008..4c7b46ab97f 100644 --- a/chromium/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp +++ b/chromium/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp @@ -540,12 +540,9 @@ static void getter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo< v8SetReturnValue(info, result); return; } - v8::Local<v8::Value> prototype = info.Holder()->GetPrototype(); - if (prototype->IsObject()) { - v8::Local<v8::Value> value; - if (prototype.As<v8::Object>()->Get(info.GetIsolate()->GetCurrentContext(), property).ToLocal(&value)) - v8SetReturnValue(info, value); - } + v8::Local<v8::Value> value; + if (info.Holder()->GetRealNamedPropertyInPrototypeChain(info.GetIsolate()->GetCurrentContext(), property.As<v8::String>()).ToLocal(&value)) + v8SetReturnValue(info, value); } void WindowProxy::namedItemAdded(HTMLDocument* document, const AtomicString& name) diff --git a/chromium/third_party/WebKit/Source/core/dom/Document.cpp b/chromium/third_party/WebKit/Source/core/dom/Document.cpp index 140eb8db74c..a57c9b323df 100644 --- a/chromium/third_party/WebKit/Source/core/dom/Document.cpp +++ b/chromium/third_party/WebKit/Source/core/dom/Document.cpp @@ -6006,7 +6006,6 @@ DEFINE_TRACE(Document) visitor->trace(m_mediaQueryMatcher); visitor->trace(m_scriptedAnimationController); visitor->trace(m_scriptedIdleTaskController); - visitor->trace(m_taskRunner); visitor->trace(m_textAutosizer); visitor->trace(m_registrationContext); visitor->trace(m_customElementMicrotaskRunQueue); diff --git a/chromium/third_party/WebKit/Source/core/dom/Document.h b/chromium/third_party/WebKit/Source/core/dom/Document.h index 3d7c505aa0d..6d1d73b7a4d 100644 --- a/chromium/third_party/WebKit/Source/core/dom/Document.h +++ b/chromium/third_party/WebKit/Source/core/dom/Document.h @@ -1350,7 +1350,7 @@ private: Member<ScriptedAnimationController> m_scriptedAnimationController; Member<ScriptedIdleTaskController> m_scriptedIdleTaskController; - Member<MainThreadTaskRunner> m_taskRunner; + OwnPtr<MainThreadTaskRunner> m_taskRunner; Member<TextAutosizer> m_textAutosizer; Member<CustomElementRegistrationContext> m_registrationContext; diff --git a/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp b/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp index 2c0df118fc4..7f10ea0302f 100644 --- a/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp +++ b/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp @@ -42,6 +42,7 @@ MainThreadTaskRunner::MainThreadTaskRunner(ExecutionContext* context) #endif , m_pendingTasksTimer(this, &MainThreadTaskRunner::pendingTasksTimerFired) , m_suspended(false) + , m_weakFactory(this) { } @@ -49,20 +50,11 @@ MainThreadTaskRunner::~MainThreadTaskRunner() { } -DEFINE_TRACE(MainThreadTaskRunner) -{ - visitor->trace(m_context); -} - void MainThreadTaskRunner::postTaskInternal(const WebTraceLocation& location, PassOwnPtr<ExecutionContextTask> task, bool isInspectorTask) { Platform::current()->mainThread()->getWebTaskRunner()->postTask(location, threadSafeBind( &MainThreadTaskRunner::perform, -#if ENABLE(OILPAN) - CrossThreadWeakPersistentThisPointer<MainThreadTaskRunner>(this), -#else AllowCrossThreadAccess(m_weakFactory.createWeakPtr()), -#endif task, isInspectorTask)); } @@ -81,6 +73,11 @@ void MainThreadTaskRunner::postInspectorTask(const WebTraceLocation& location, P void MainThreadTaskRunner::perform(PassOwnPtr<ExecutionContextTask> task, bool isInspectorTask) { + // If the owner m_context is about to be swept then it + // is no longer safe to access. + if (Heap::willObjectBeLazilySwept(m_context.get())) + return; + if (!isInspectorTask && (m_context->tasksNeedSuspension() || !m_pendingTasks.isEmpty())) { m_pendingTasks.append(task); return; @@ -108,6 +105,11 @@ void MainThreadTaskRunner::resume() void MainThreadTaskRunner::pendingTasksTimerFired(Timer<MainThreadTaskRunner>*) { + // If the owner m_context is about to be swept then it + // is no longer safe to access. + if (Heap::willObjectBeLazilySwept(m_context.get())) + return; + while (!m_pendingTasks.isEmpty()) { OwnPtr<ExecutionContextTask> task = m_pendingTasks[0].release(); m_pendingTasks.remove(0); diff --git a/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h b/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h index 385ae5ec7a0..0bdd69f0088 100644 --- a/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h +++ b/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h @@ -42,10 +42,11 @@ namespace blink { class ExecutionContext; class ExecutionContextTask; -class CORE_EXPORT MainThreadTaskRunner final : public GarbageCollectedFinalized<MainThreadTaskRunner> { +class CORE_EXPORT MainThreadTaskRunner final { + USING_FAST_MALLOC(MainThreadTaskRunner); WTF_MAKE_NONCOPYABLE(MainThreadTaskRunner); public: - static RawPtr<MainThreadTaskRunner> create(ExecutionContext*); + static PassOwnPtr<MainThreadTaskRunner> create(ExecutionContext*); ~MainThreadTaskRunner(); @@ -65,18 +66,18 @@ private: void postTaskInternal(const WebTraceLocation&, PassOwnPtr<ExecutionContextTask>, bool isInspectorTask); - Member<ExecutionContext> m_context; -#if !ENABLE(OILPAN) - WeakPtrFactory<MainThreadTaskRunner> m_weakFactory; -#endif + // Untraced back reference to the owner Document; + // this object has identical lifetime to it. + UntracedMember<ExecutionContext> m_context; Timer<MainThreadTaskRunner> m_pendingTasksTimer; Vector<OwnPtr<ExecutionContextTask>> m_pendingTasks; bool m_suspended; + WeakPtrFactory<MainThreadTaskRunner> m_weakFactory; }; -inline RawPtr<MainThreadTaskRunner> MainThreadTaskRunner::create(ExecutionContext* context) +inline PassOwnPtr<MainThreadTaskRunner> MainThreadTaskRunner::create(ExecutionContext* context) { - return new MainThreadTaskRunner(context); + return adoptPtr(new MainThreadTaskRunner(context)); } } // namespace blink diff --git a/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunnerTest.cpp b/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunnerTest.cpp index 1c97da29e13..4e2f08408a3 100644 --- a/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunnerTest.cpp +++ b/chromium/third_party/WebKit/Source/core/dom/MainThreadTaskRunnerTest.cpp @@ -45,8 +45,8 @@ static void markBoolean(bool* toBeMarked) TEST(MainThreadTaskRunnerTest, PostTask) { - RawPtr<NullExecutionContext> context = new NullExecutionContext(); - RawPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context.get()); + NullExecutionContext* context = new NullExecutionContext(); + OwnPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context); bool isMarked = false; runner->postTask(BLINK_FROM_HERE, createSameThreadTask(&markBoolean, &isMarked)); @@ -57,8 +57,8 @@ TEST(MainThreadTaskRunnerTest, PostTask) TEST(MainThreadTaskRunnerTest, SuspendTask) { - RawPtr<NullExecutionContext> context = new NullExecutionContext(); - RawPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context.get()); + NullExecutionContext* context = new NullExecutionContext(); + OwnPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context); bool isMarked = false; context->setTasksNeedSuspension(true); @@ -75,8 +75,8 @@ TEST(MainThreadTaskRunnerTest, SuspendTask) TEST(MainThreadTaskRunnerTest, RemoveRunner) { - RawPtr<NullExecutionContext> context = new NullExecutionContext(); - RawPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context.get()); + NullExecutionContext* context = new NullExecutionContext(); + OwnPtr<MainThreadTaskRunner> runner = MainThreadTaskRunner::create(context); bool isMarked = false; context->setTasksNeedSuspension(true); diff --git a/chromium/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/chromium/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp index 768821caa09..072d3091445 100644 --- a/chromium/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp +++ b/chromium/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp @@ -179,9 +179,15 @@ static bool updateMarkerRenderedRect(Node* node, RenderedDocumentMarker& marker) range->setStart(node, marker.startOffset(), exceptionState); if (!exceptionState.hadException()) range->setEnd(node, marker.endOffset(), IGNORE_EXCEPTION); - if (exceptionState.hadException()) + if (exceptionState.hadException()) { + range->dispose(); return marker.invalidateRenderedRect(); - return marker.setRenderedRect(LayoutRect(range->boundingBox())); + } + // TODO(yosin): Once we have a |EphemeralRange| version of |boundingBox()|, + // we should use it instead of |Range| version. + const bool isUpdated = marker.setRenderedRect(LayoutRect(range->boundingBox())); + range->dispose(); + return isUpdated; } // Markers are stored in order sorted by their start offset. diff --git a/chromium/third_party/WebKit/Source/core/frame/DOMWindow.cpp b/chromium/third_party/WebKit/Source/core/frame/DOMWindow.cpp index a02e3cc70b2..a64e9e20cf4 100644 --- a/chromium/third_party/WebKit/Source/core/frame/DOMWindow.cpp +++ b/chromium/third_party/WebKit/Source/core/frame/DOMWindow.cpp @@ -97,7 +97,10 @@ DOMWindow* DOMWindow::opener() const DOMWindow* DOMWindow::parent() const { - if (!frame()) + // TODO(yukishiino): The 'parent' attribute must return |this| + // (the WindowProxy object of the browsing context itself) when it's + // top-level or detached. + if (!isCurrentlyDisplayedInFrame()) return nullptr; Frame* parent = frame()->tree().parent(); @@ -106,7 +109,10 @@ DOMWindow* DOMWindow::parent() const DOMWindow* DOMWindow::top() const { - if (!frame()) + // TODO(yukishiino): The 'top' attribute must return |this| + // (the WindowProxy object of the browsing context itself) when it's + // top-level or detached. + if (!isCurrentlyDisplayedInFrame()) return nullptr; return frame()->tree().top()->domWindow(); diff --git a/chromium/third_party/WebKit/Source/core/frame/FrameView.cpp b/chromium/third_party/WebKit/Source/core/frame/FrameView.cpp index a0027120041..004912befb3 100644 --- a/chromium/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/chromium/third_party/WebKit/Source/core/frame/FrameView.cpp @@ -162,6 +162,7 @@ FrameView::FrameView(LocalFrame* frame) , m_isUpdatingAllLifecyclePhases(false) , m_scrollAnchor(this) , m_needsScrollbarsUpdate(false) + , m_suppressAdjustViewSize(false) { ASSERT(m_frame); init(); @@ -531,6 +532,9 @@ void FrameView::setContentsSize(const IntSize& size) void FrameView::adjustViewSize() { + if (m_suppressAdjustViewSize) + return; + LayoutViewItem layoutViewItem = LayoutViewItem(this->layoutView()); if (layoutViewItem.isNull()) return; @@ -553,6 +557,15 @@ void FrameView::adjustViewSize() setContentsSize(size); } +void FrameView::adjustViewSizeAndLayout() +{ + adjustViewSize(); + if (needsLayout()) { + TemporaryChange<bool> suppressAdjustViewSize(m_suppressAdjustViewSize, true); + layout(); + } +} + void FrameView::calculateScrollbarModesFromOverflowStyle(const ComputedStyle* style, ScrollbarMode& hMode, ScrollbarMode& vMode) { hMode = vMode = ScrollbarAuto; @@ -1035,7 +1048,7 @@ void FrameView::layout() } // Reset m_layoutSchedulingEnabled to its previous value. if (!inSubtreeLayout && !document->printing()) - adjustViewSize(); + adjustViewSizeAndLayout(); m_frameTimingRequestsDirty = true; @@ -2762,7 +2775,7 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatS } } - adjustViewSize(); + adjustViewSizeAndLayout(); } IntRect FrameView::convertFromLayoutObject(const LayoutObject& layoutObject, const IntRect& layoutObjectRect) const @@ -4081,7 +4094,7 @@ void FrameView::notifyRenderThrottlingObservers() { TRACE_EVENT0("blink", "FrameView::notifyRenderThrottlingObservers"); DCHECK(!isInPerformLayout()); - DCHECK(!m_frame->document()->inStyleRecalc()); + DCHECK(!m_frame->document() || !m_frame->document()->inStyleRecalc()); bool wasThrottled = canThrottleRendering(); updateThrottlingStatus(); @@ -4112,7 +4125,7 @@ void FrameView::notifyRenderThrottlingObservers() layoutView->invalidatePaintForViewAndCompositedLayers(); } - bool hasHandlers = m_frame->document()->frameHost()->eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEventBlocking); + bool hasHandlers = m_frame->host() && m_frame->host()->eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEventBlocking); if (wasThrottled != canThrottleRendering() && scrollingCoordinator && hasHandlers) scrollingCoordinator->touchEventTargetRectsDidChange(); diff --git a/chromium/third_party/WebKit/Source/core/frame/FrameView.h b/chromium/third_party/WebKit/Source/core/frame/FrameView.h index 0269d400dab..da4ddb8ab33 100644 --- a/chromium/third_party/WebKit/Source/core/frame/FrameView.h +++ b/chromium/third_party/WebKit/Source/core/frame/FrameView.h @@ -173,6 +173,7 @@ public: void updateBackgroundRecursively(const Color&, bool); void adjustViewSize(); + void adjustViewSizeAndLayout(); // Scale used to convert incoming input events. float inputEventsScaleFactor() const; @@ -909,6 +910,7 @@ private: ScrollAnchor m_scrollAnchor; bool m_needsScrollbarsUpdate; + bool m_suppressAdjustViewSize; }; inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count) diff --git a/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp b/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp index 64110d549da..13210514494 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp @@ -760,7 +760,9 @@ Vector<CharacterRange> Font::individualCharacterRanges(const TextRun& run) const // will be improved shaping in SVG when compared to HTML. FontCachePurgePreventer purgePreventer; CachingWordShaper shaper(m_fontFallbackList->shapeCache(m_fontDescription)); - return shaper.individualCharacterRanges(this, run); + auto ranges = shaper.individualCharacterRanges(this, run); + DCHECK_EQ(ranges.size(), static_cast<unsigned>(run.length())); + return ranges; } float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* glyphBounds) const diff --git a/chromium/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp b/chromium/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp index 92f9592aded..4135bf23386 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp @@ -123,7 +123,13 @@ Vector<CharacterRange> CachingWordShaper::individualCharacterRanges( float totalWidth = shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); - return buffer.individualCharacterRanges(run.direction(), totalWidth); + auto ranges = buffer.individualCharacterRanges(run.direction(), totalWidth); + // The shaper can fail to return glyph metrics for all characters (see + // crbug.com/613915 and crbug.com/615661) so add empty ranges to ensure all + // characters have an associated range. + while (ranges.size() < static_cast<unsigned>(run.length())) + ranges.append(CharacterRange(0, 0)); + return ranges; } }; // namespace blink diff --git a/chromium/third_party/WebKit/Source/platform/heap/Heap.cpp b/chromium/third_party/WebKit/Source/platform/heap/Heap.cpp index cb41196d388..9efd299f876 100644 --- a/chromium/third_party/WebKit/Source/platform/heap/Heap.cpp +++ b/chromium/third_party/WebKit/Source/platform/heap/Heap.cpp @@ -463,18 +463,27 @@ void Heap::collectGarbage(BlinkGC::StackState stackState, BlinkGC::GCType gcType if (gcType != BlinkGC::TakeSnapshot) Heap::resetHeapCounters(); - // 1. Trace persistent roots. - ThreadState::visitPersistentRoots(visitor.get()); + { + // Access to the CrossThreadPersistentRegion has to be prevented while + // marking and global weak processing is in progress. If not, threads + // not attached to Oilpan and participating in this GC are able + // to allocate & free PersistentNodes, something the marking phase isn't + // capable of handling. + CrossThreadPersistentRegion::LockScope persistentLock(ProcessHeap::crossThreadPersistentRegion()); + + // 1. Trace persistent roots. + ThreadState::visitPersistentRoots(visitor.get()); - // 2. Trace objects reachable from the stack. We do this independent of the - // given stackState since other threads might have a different stack state. - ThreadState::visitStackRoots(visitor.get()); + // 2. Trace objects reachable from the stack. We do this independent of the + // given stackState since other threads might have a different stack state. + ThreadState::visitStackRoots(visitor.get()); - // 3. Transitive closure to trace objects including ephemerons. - processMarkingStack(visitor.get()); + // 3. Transitive closure to trace objects including ephemerons. + processMarkingStack(visitor.get()); - postMarkingProcessing(visitor.get()); - globalWeakProcessing(visitor.get()); + postMarkingProcessing(visitor.get()); + globalWeakProcessing(visitor.get()); + } // Now we can delete all orphaned pages because there are no dangling // pointers to the orphaned pages. (If we have such dangling pointers, diff --git a/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h b/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h index ebaf0604edc..41d9c1941fb 100644 --- a/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h +++ b/chromium/third_party/WebKit/Source/platform/heap/PersistentNode.h @@ -180,15 +180,44 @@ public: m_persistentRegion->freePersistentNode(persistentNode); } + class LockScope final { + STACK_ALLOCATED(); + public: + LockScope(CrossThreadPersistentRegion& persistentRegion) + : m_persistentRegion(persistentRegion) + { + m_persistentRegion.lock(); + } + ~LockScope() + { + m_persistentRegion.unlock(); + } + private: + CrossThreadPersistentRegion& m_persistentRegion; + }; + void tracePersistentNodes(Visitor* visitor) { - MutexLocker lock(m_mutex); + // If this assert triggers, you're tracing without being in a LockScope. + ASSERT(m_mutex.locked()); m_persistentRegion->tracePersistentNodes(visitor); } void prepareForThreadStateTermination(ThreadState*); private: + friend class LockScope; + + void lock() + { + m_mutex.lock(); + } + + void unlock() + { + m_mutex.unlock(); + } + // We don't make CrossThreadPersistentRegion inherit from PersistentRegion // because we don't want to virtualize performance-sensitive methods // such as PersistentRegion::allocate/freePersistentNode. diff --git a/chromium/third_party/libaddressinput/BUILD.gn b/chromium/third_party/libaddressinput/BUILD.gn new file mode 100644 index 00000000000..864e79003ca --- /dev/null +++ b/chromium/third_party/libaddressinput/BUILD.gn @@ -0,0 +1,227 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//testing/test.gni") +import("//tools/grit/grit_rule.gni") + +libaddressinput_util_files = [ + "src/cpp/src/address_data.cc", + "src/cpp/src/address_field.cc", + "src/cpp/src/address_field_util.cc", + "src/cpp/src/address_formatter.cc", + "src/cpp/src/address_metadata.cc", + "src/cpp/src/address_ui.cc", + "src/cpp/src/format_element.cc", + "src/cpp/src/language.cc", + "src/cpp/src/localization.cc", + "src/cpp/src/lookup_key.cc", + "src/cpp/src/region_data_constants.cc", + "src/cpp/src/rule.cc", + "src/cpp/src/util/cctype_tolower_equal.cc", + "src/cpp/src/util/json.cc", + "src/cpp/src/util/string_split.cc", + "src/cpp/src/util/string_util.cc", +] + +config("no-newline-eof-warning") { + if (is_clang) { + cflags = [ "-Wno-newline-eof" ] + } +} + +# GYP version: third_party/libaddressinput/libaddressinput.gyp:libaddressinput_strings +grit("strings") { + source = "//chrome/app/address_input_strings.grd" + outputs = [ + "messages.h", + "en_messages.cc", + "address_input_strings_am.pak", + "address_input_strings_ar.pak", + "address_input_strings_bg.pak", + "address_input_strings_bn.pak", + "address_input_strings_ca.pak", + "address_input_strings_cs.pak", + "address_input_strings_da.pak", + "address_input_strings_de.pak", + "address_input_strings_el.pak", + "address_input_strings_en-GB.pak", + "address_input_strings_en-US.pak", + "address_input_strings_es.pak", + "address_input_strings_es-419.pak", + "address_input_strings_et.pak", + "address_input_strings_fa.pak", + "address_input_strings_fake-bidi.pak", + "address_input_strings_fi.pak", + "address_input_strings_fil.pak", + "address_input_strings_fr.pak", + "address_input_strings_gu.pak", + "address_input_strings_he.pak", + "address_input_strings_hi.pak", + "address_input_strings_hr.pak", + "address_input_strings_hu.pak", + "address_input_strings_id.pak", + "address_input_strings_it.pak", + "address_input_strings_ja.pak", + "address_input_strings_kn.pak", + "address_input_strings_ko.pak", + "address_input_strings_lt.pak", + "address_input_strings_lv.pak", + "address_input_strings_ml.pak", + "address_input_strings_mr.pak", + "address_input_strings_ms.pak", + "address_input_strings_nl.pak", + "address_input_strings_nb.pak", + "address_input_strings_pl.pak", + "address_input_strings_pt-BR.pak", + "address_input_strings_pt-PT.pak", + "address_input_strings_ro.pak", + "address_input_strings_ru.pak", + "address_input_strings_sk.pak", + "address_input_strings_sl.pak", + "address_input_strings_sr.pak", + "address_input_strings_sv.pak", + "address_input_strings_sw.pak", + "address_input_strings_ta.pak", + "address_input_strings_te.pak", + "address_input_strings_th.pak", + "address_input_strings_tr.pak", + "address_input_strings_uk.pak", + "address_input_strings_vi.pak", + "address_input_strings_zh-CN.pak", + "address_input_strings_zh-TW.pak", + ] + + if (is_ios) { + # iOS uses "pt" for pt-BR" and "es-MX" for "es-419". + outputs -= [ + "address_input_strings_pt-BR.pak", + "address_input_strings_es-419.pak", + ] + outputs += [ + "address_input_strings_pt.pak", + "address_input_strings_es-MX.pak", + ] + } + + configs = [ ":no-newline-eof-warning" ] +} + +config("libaddressinput_config") { + defines = [ + "I18N_ADDRESSINPUT_USE_BASICTYPES_OVERRIDE=1", + "I18N_ADDRESS_VALIDATION_DATA_URL=\"https://i18napis.appspot.com/ssl-aggregate-address/\"", + ] + include_dirs = [ + "src/cpp/include", + "chromium/override", + ] +} + +# This target provides basic functionality which is cooked into the build. +# GYP version: third_party/libaddressinput/libaddressinput.gyp:libaddressinput_util +static_library("util") { + sources = libaddressinput_util_files + sources += [ + "chromium/addressinput_util.cc", + "chromium/json.cc", + ] + sources -= [ "src/cpp/src/util/json.cc" ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + ":no-newline-eof-warning", + "//build/config/compiler:no_chromium_code", + ] + + public_configs = [ ":libaddressinput_config" ] + + include_dirs = [ "$root_gen_dir/third_party/libaddressinput" ] + + deps = [ + ":strings", + "//base", + "//base:i18n", + "//third_party/icu", + "//third_party/re2", + ] +} + +if (!is_android || use_aura) { + # The list of files in libaddressinput.gypi. + gypi_values = exec_script("//build/gypi_to_gn.py", + [ rebase_path("src/cpp/libaddressinput.gypi") ], + "scope", + [ "src/cpp/libaddressinput.gypi" ]) + + # This target provides more complicated functionality like pinging servers + # for validation rules. + # GYP version: third_party/libaddressinput/libaddressinput.gyp:libaddressinput + static_library("libaddressinput") { + sources = rebase_path(gypi_values.libaddressinput_files, ".", "src/cpp") + sources += [ + "chromium/chrome_address_validator.cc", + "chromium/chrome_metadata_source.cc", + "chromium/chrome_storage_impl.cc", + "chromium/fallback_data_store.cc", + "chromium/input_suggester.cc", + "chromium/string_compare.cc", + "chromium/trie.cc", + ] + sources -= libaddressinput_util_files + sources -= [ "src/cpp/src/util/string_compare.cc" ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + + public_configs = [ ":libaddressinput_config" ] + + deps = [ + ":strings", + ":util", + "//base", + "//base:i18n", + "//components/prefs", + "//net", + "//third_party/icu", + "//third_party/re2", + ] + } + + test("libaddressinput_unittests") { + sources = + rebase_path(gypi_values.libaddressinput_test_files, ".", "src/cpp") + sources += [ + "chromium/addressinput_util_unittest.cc", + "chromium/chrome_address_validator_unittest.cc", + "chromium/chrome_metadata_source_unittest.cc", + "chromium/chrome_storage_impl_unittest.cc", + "chromium/fallback_data_store_unittest.cc", + "chromium/storage_test_runner.cc", + "chromium/string_compare_unittest.cc", + "chromium/trie_unittest.cc", + ] + + if (is_ios) { + # TODO(rouslan): This tests uses ASSERT_DEATH which is not supported on + # iOS. Re-enable once http://crbug.com/595645 is fixed. + sources -= [ "src/cpp/test/address_data_test.cc" ] + } + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + + defines = [ "TEST_DATA_DIR=\"third_party/libaddressinput/src/testdata\"" ] + + include_dirs = [ "src/cpp/src" ] + + deps = [ + ":libaddressinput", + ":strings", + "//base/test:run_all_unittests", + "//components/prefs", + "//net:test_support", + "//testing/gtest", + ] + } +} diff --git a/chromium/third_party/libaddressinput/LICENSE b/chromium/third_party/libaddressinput/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/chromium/third_party/libaddressinput/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/chromium/third_party/libaddressinput/OWNERS b/chromium/third_party/libaddressinput/OWNERS new file mode 100644 index 00000000000..d379e0309a9 --- /dev/null +++ b/chromium/third_party/libaddressinput/OWNERS @@ -0,0 +1,2 @@ +rouslan@chromium.org +estade@chromium.org diff --git a/chromium/third_party/libaddressinput/README.chromium b/chromium/third_party/libaddressinput/README.chromium new file mode 100644 index 00000000000..9e7ff6edb91 --- /dev/null +++ b/chromium/third_party/libaddressinput/README.chromium @@ -0,0 +1,21 @@ +Name: The library to input, validate, and display addresses. +Short Name: libaddressinput +URL: https://github.com/googlei18n/libaddressinput +Version: 0 +Date: 10 November 2014 +Revision: 678a7f55a2ae7ccf417b4809e602b808b56a8ddb +License: Apache 2.0 +License File: LICENSE +Security Critical: no + +Description: + +This library lets you enter, validate, and display an address with correct +semantics for many countries around the world. The library uses the serialized +validation rules from a Google-managed server (without SLA) at +https://i18napis.appspot.com/ssl-aggregate-address. The library is used in +requestAutocomplete dialog and autofill. + +Local Modifications: +- Use Chrome's version of JSON reader in chromium/json.cc. +- Use Chrome's version of loose string comparison in chromium/string_compare.cc. diff --git a/chromium/third_party/libaddressinput/chromium/DEPS b/chromium/third_party/libaddressinput/chromium/DEPS new file mode 100644 index 00000000000..b55c0fa48ac --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/DEPS @@ -0,0 +1,8 @@ +include_rules = [ + '+base', + "+components/prefs", + '+net', + '+testing', + '+third_party/icu', + '+url', +] diff --git a/chromium/third_party/libaddressinput/chromium/addressinput_util.cc b/chromium/third_party/libaddressinput/chromium/addressinput_util.cc new file mode 100644 index 00000000000..ca10d41ddef --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/addressinput_util.cc @@ -0,0 +1,77 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/addressinput_util.h" + +#include <stddef.h> + +#include <algorithm> + +#include "base/logging.h" +#include "base/macros.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h" + +namespace autofill { +namespace addressinput { + +namespace { + +using ::i18n::addressinput::AddressData; +using ::i18n::addressinput::AddressField; +using ::i18n::addressinput::AddressProblem; +using ::i18n::addressinput::IsFieldRequired; + +using ::i18n::addressinput::MISSING_REQUIRED_FIELD; + +// Returns true if the |problem| should not be reported for the |field| because +// the |filter| excludes it. +bool FilterExcludes(const std::multimap<AddressField, AddressProblem>* filter, + AddressField field, + AddressProblem problem) { + return filter != NULL && !filter->empty() && + std::find(filter->begin(), + filter->end(), + std::multimap<AddressField, AddressProblem>::value_type( + field, problem)) == filter->end(); +} + +} // namespace + +bool HasAllRequiredFields(const AddressData& address_to_check) { + std::multimap<AddressField, AddressProblem> problems; + ValidateRequiredFields(address_to_check, NULL, &problems); + return problems.empty(); +} + +void ValidateRequiredFields( + const AddressData& address_to_check, + const std::multimap<AddressField, AddressProblem>* filter, + std::multimap<AddressField, AddressProblem>* problems) { + DCHECK(problems); + + static const AddressField kFields[] = { + ::i18n::addressinput::COUNTRY, + ::i18n::addressinput::ADMIN_AREA, + ::i18n::addressinput::LOCALITY, + ::i18n::addressinput::DEPENDENT_LOCALITY, + ::i18n::addressinput::SORTING_CODE, + ::i18n::addressinput::POSTAL_CODE, + ::i18n::addressinput::STREET_ADDRESS, + // ORGANIZATION is never required. + ::i18n::addressinput::RECIPIENT + }; + + for (size_t i = 0; i < arraysize(kFields); ++i) { + AddressField field = kFields[i]; + if (address_to_check.IsFieldEmpty(field) && + IsFieldRequired(field, address_to_check.region_code) && + !FilterExcludes(filter, field, MISSING_REQUIRED_FIELD)) { + problems->insert(std::make_pair(field, MISSING_REQUIRED_FIELD)); + } + } +} + +} // namespace addressinput +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/addressinput_util.h b/chromium/third_party/libaddressinput/chromium/addressinput_util.h new file mode 100644 index 00000000000..7c888a7b1f2 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/addressinput_util.h @@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_ADDRESSINPUT_UTIL_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_ADDRESSINPUT_UTIL_H_ + +#include <map> + +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h" + +namespace i18n { +namespace addressinput { +struct AddressData; +} +} + +namespace autofill { +namespace addressinput { + +// Returns true if |address_to_check| has all of its required fields. +bool HasAllRequiredFields( + const ::i18n::addressinput::AddressData& address_to_check); + +// Validates required fields in |address_to_check| without loading rules from +// the server. The |problems| parameter cannot be NULL. Does not take ownership +// of its parameters. +// +// See documentation of ::i18n::addressinput::AddressValidator::Validate() for +// description of |filter| and |problems|. +void ValidateRequiredFields( + const ::i18n::addressinput::AddressData& address_to_check, + const std::multimap< ::i18n::addressinput::AddressField, + ::i18n::addressinput::AddressProblem>* filter, + std::multimap< ::i18n::addressinput::AddressField, + ::i18n::addressinput::AddressProblem>* problems); + +} // namespace addressinput +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_ADDRESSINPUT_UTIL_H_ diff --git a/chromium/third_party/libaddressinput/chromium/addressinput_util_unittest.cc b/chromium/third_party/libaddressinput/chromium/addressinput_util_unittest.cc new file mode 100644 index 00000000000..b68ea81760d --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/addressinput_util_unittest.cc @@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/addressinput_util.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" + +namespace autofill { +namespace addressinput { + +using ::i18n::addressinput::AddressData; + +TEST(AddressinputUtilTest, AddressRequiresRegionCode) { + AddressData address; + EXPECT_FALSE(HasAllRequiredFields(address)); +} + +TEST(AddressinputUtilTest, UsRequiresState) { + AddressData address; + address.region_code = "US"; + address.postal_code = "90291"; + // Leave state empty. + address.locality = "Los Angeles"; + address.address_line.push_back("340 Main St."); + EXPECT_FALSE(HasAllRequiredFields(address)); +} + +TEST(AddressinputUtilTest, CompleteAddressReturnsTrue) { + AddressData address; + address.region_code = "US"; + address.postal_code = "90291"; + address.administrative_area = "CA"; + address.locality = "Los Angeles"; + address.address_line.push_back("340 Main St."); + EXPECT_TRUE(HasAllRequiredFields(address)); +} + +} // namespace addressinput +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/canonicalize_string.cc b/chromium/third_party/libaddressinput/chromium/canonicalize_string.cc new file mode 100644 index 00000000000..d1fc1ce10aa --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/canonicalize_string.cc @@ -0,0 +1,72 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/src/cpp/src/util/canonicalize_string.h" + +#include <stdint.h> + +#include "base/logging.h" +#include "base/macros.h" +#include "third_party/icu/source/common/unicode/errorcode.h" +#include "third_party/icu/source/common/unicode/locid.h" +#include "third_party/icu/source/common/unicode/unistr.h" +#include "third_party/icu/source/common/unicode/utypes.h" +#include "third_party/icu/source/i18n/unicode/coll.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/util/scoped_ptr.h" + +namespace i18n { +namespace addressinput { + +namespace { + +class ChromeStringCanonicalizer : public StringCanonicalizer { + public: + ChromeStringCanonicalizer() + : error_code_(U_ZERO_ERROR), + collator_( + icu::Collator::createInstance( + icu::Locale::getRoot(), error_code_)) { + collator_->setStrength(icu::Collator::PRIMARY); + DCHECK(U_SUCCESS(error_code_)); + } + + virtual ~ChromeStringCanonicalizer() {} + + // StringCanonicalizer implementation. + virtual std::string CanonicalizeString(const std::string& original) { + // Returns a canonical version of the string that can be used for comparing + // strings regardless of diacritics and capitalization. + // CanonicalizeString("Texas") == CanonicalizeString("T\u00E9xas"); + // CanonicalizeString("Texas") == CanonicalizeString("teXas"); + // CanonicalizeString("Texas") != CanonicalizeString("California"); + // + // The output is not human-readable. + // CanonicalizeString("Texas") != "Texas"; + icu::UnicodeString icu_str( + original.c_str(), static_cast<int32_t>(original.length())); + int32_t buffer_size = collator_->getSortKey(icu_str, NULL, 0); + scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); + DCHECK(buffer.get()); + int32_t filled_size = + collator_->getSortKey(icu_str, buffer.get(), buffer_size); + DCHECK_EQ(buffer_size, filled_size); + return std::string(reinterpret_cast<const char*>(buffer.get())); + } + + private: + UErrorCode error_code_; + scoped_ptr<icu::Collator> collator_; + + DISALLOW_COPY_AND_ASSIGN(ChromeStringCanonicalizer); +}; + +} // namespace + +// static +scoped_ptr<StringCanonicalizer> StringCanonicalizer::Build() { + return scoped_ptr<StringCanonicalizer>(new ChromeStringCanonicalizer); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/chromium/chrome_address_validator.cc b/chromium/third_party/libaddressinput/chromium/chrome_address_validator.cc new file mode 100644 index 00000000000..c55ab49ca47 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_address_validator.cc @@ -0,0 +1,164 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/chrome_address_validator.h" + +#include <cmath> + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "third_party/libaddressinput/chromium/addressinput_util.h" +#include "third_party/libaddressinput/chromium/input_suggester.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_normalizer.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" + +namespace autofill { +namespace { + +using ::i18n::addressinput::AddressData; +using ::i18n::addressinput::AddressField; +using ::i18n::addressinput::AddressNormalizer; +using ::i18n::addressinput::BuildCallback; +using ::i18n::addressinput::FieldProblemMap; +using ::i18n::addressinput::PreloadSupplier; +using ::i18n::addressinput::Source; +using ::i18n::addressinput::Storage; + +using ::i18n::addressinput::ADMIN_AREA; +using ::i18n::addressinput::DEPENDENT_LOCALITY; +using ::i18n::addressinput::POSTAL_CODE; + +// The maximum number attempts to load rules. +static const int kMaxAttemptsNumber = 8; + +} // namespace + +AddressValidator::AddressValidator(scoped_ptr<Source> source, + scoped_ptr<Storage> storage, + LoadRulesListener* load_rules_listener) + : supplier_(new PreloadSupplier(source.release(), + storage.release())), + input_suggester_(new InputSuggester(supplier_.get())), + normalizer_(new AddressNormalizer(supplier_.get())), + validator_(new ::i18n::addressinput::AddressValidator(supplier_.get())), + validated_(BuildCallback(this, &AddressValidator::Validated)), + rules_loaded_(BuildCallback(this, &AddressValidator::RulesLoaded)), + load_rules_listener_(load_rules_listener), + weak_factory_(this) {} + +AddressValidator::~AddressValidator() {} + +void AddressValidator::LoadRules(const std::string& region_code) { + attempts_number_[region_code] = 0; + supplier_->LoadRules(region_code, *rules_loaded_); +} + +AddressValidator::Status AddressValidator::ValidateAddress( + const AddressData& address, + const FieldProblemMap* filter, + FieldProblemMap* problems) const { + if (supplier_->IsPending(address.region_code)) { + if (problems) + addressinput::ValidateRequiredFields(address, filter, problems); + return RULES_NOT_READY; + } + + if (!supplier_->IsLoaded(address.region_code)) { + if (problems) + addressinput::ValidateRequiredFields(address, filter, problems); + return RULES_UNAVAILABLE; + } + + if (!problems) + return SUCCESS; + + validator_->Validate(address, + true, // Allow postal office boxes. + true, // Require recipient name. + filter, + problems, + *validated_); + + return SUCCESS; +} + +AddressValidator::Status AddressValidator::GetSuggestions( + const AddressData& user_input, + AddressField focused_field, + size_t suggestion_limit, + std::vector<AddressData>* suggestions) const { + if (supplier_->IsPending(user_input.region_code)) + return RULES_NOT_READY; + + if (!supplier_->IsLoaded(user_input.region_code)) + return RULES_UNAVAILABLE; + + if (!suggestions) + return SUCCESS; + + suggestions->clear(); + + if (focused_field == POSTAL_CODE || + (focused_field >= ADMIN_AREA && focused_field <= DEPENDENT_LOCALITY)) { + input_suggester_->GetSuggestions( + user_input, focused_field, suggestion_limit, suggestions); + } + + return SUCCESS; +} + +bool AddressValidator::CanonicalizeAdministrativeArea( + AddressData* address) const { + if (!supplier_->IsLoaded(address->region_code)) + return false; + + // TODO: It would probably be beneficial to use the full canonicalization. + AddressData tmp(*address); + normalizer_->Normalize(&tmp); + address->administrative_area = tmp.administrative_area; + + return true; +} + +AddressValidator::AddressValidator() + : load_rules_listener_(NULL), weak_factory_(this) {} + +base::TimeDelta AddressValidator::GetBaseRetryPeriod() const { + return base::TimeDelta::FromSeconds(8); +} + +void AddressValidator::Validated(bool success, + const AddressData&, + const FieldProblemMap&) { + DCHECK(success); +} + +void AddressValidator::RulesLoaded(bool success, + const std::string& region_code, + int) { + if (load_rules_listener_) + load_rules_listener_->OnAddressValidationRulesLoaded(region_code, success); + + // Count the first failed attempt to load rules as well. + if (success || attempts_number_[region_code] + 1 >= kMaxAttemptsNumber) + return; + + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&AddressValidator::RetryLoadRules, + weak_factory_.GetWeakPtr(), + region_code), + GetBaseRetryPeriod() * pow(2, attempts_number_[region_code]++)); +} + +void AddressValidator::RetryLoadRules(const std::string& region_code) { + // Do not reset retry count. + supplier_->LoadRules(region_code, *rules_loaded_); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/chrome_address_validator.h b/chromium/third_party/libaddressinput/chromium/chrome_address_validator.h new file mode 100644 index 00000000000..94ae50434e9 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_address_validator.h @@ -0,0 +1,203 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_ADDRESS_VALIDATOR_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_ADDRESS_VALIDATOR_H_ + +#include <stddef.h> + +#include <map> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h" + +namespace i18n { +namespace addressinput { +class AddressNormalizer; +class Source; +class Storage; +struct AddressData; +} +} + +namespace autofill { + +class InputSuggester; + +// The object to be notified when loading of address validation rules is +// finished. +class LoadRulesListener { + public: + virtual ~LoadRulesListener() {} + + // Called when the validation rules for the |region_code| have been loaded. + // The validation rules include the generic rules for the |region_code| and + // specific rules for the country's administrative areas, localities, and + // dependent localities. If a country has language-specific validation rules, + // then these are also loaded. + // + // The |success| parameter is true when the rules were loaded successfully. + virtual void OnAddressValidationRulesLoaded(const std::string& region_code, + bool success) = 0; +}; + +// Interface to the libaddressinput AddressValidator for Chromium Autofill. The +// class is named AddressValidator to simplify switching between libaddressinput +// and this version. +// +// It's not possible to name this file address_validator.h because some +// compilers do not handle multiple files with the same name (although in +// different directories) gracefully. This class is a shim between upstream +// libaddressinput API and the API that Chrome expects, hence the file name +// chrome_address_validator.h. +class AddressValidator { + public: + // The status of address validation. + enum Status { + // Address validation completed successfully. Check |problems| to see if any + // problems were found. + SUCCESS, + + // The validation rules are not available, because LoadRules() was not + // called or failed. Reload the rules. + RULES_UNAVAILABLE, + + // The validation rules are being loaded. Try again later. + RULES_NOT_READY + }; + + // Takes ownership of |source| and |storage|. + AddressValidator(scoped_ptr< ::i18n::addressinput::Source> source, + scoped_ptr< ::i18n::addressinput::Storage> storage, + LoadRulesListener* load_rules_listener); + + virtual ~AddressValidator(); + + // Loads the generic validation rules for |region_code| and specific rules + // for the region's administrative areas, localities, and dependent + // localities. A typical data size is 10KB. The largest is 250KB. If a region + // has language-specific validation rules, then these are also loaded. + // + // Example rule: + // https://i18napis.appspot.com/ssl-aggregate-address/data/US + // + // If the rules are already in progress of being loaded, it does nothing. + // Invokes |load_rules_listener| when the loading has finished. + virtual void LoadRules(const std::string& region_code); + + // Validates the |address| and populates |problems| with the validation + // problems, filtered according to the |filter| parameter. + // + // If the |filter| is empty, then all discovered validation problems are + // returned. If the |filter| contains problem elements, then only the problems + // in the |filter| may be returned. + virtual Status ValidateAddress( + const ::i18n::addressinput::AddressData& address, + const ::i18n::addressinput::FieldProblemMap* filter, + ::i18n::addressinput::FieldProblemMap* problems) const; + + // Fills in |suggestions| for the partially typed in |user_input|, assuming + // the user is typing in the |focused_field|. If the number of |suggestions| + // is over the |suggestion_limit|, then returns no |suggestions| at all. + // + // If the |solutions| parameter is NULL, the checks whether the validation + // rules are available, but does not fill in suggestions. + // + // Sample user input 1: + // country code = "US" + // postal code = "90066" + // focused field = POSTAL_CODE + // suggestions limit = 1 + // Suggestion: + // [{administrative_area: "CA"}] + // + // Sample user input 2: + // country code = "CN" + // dependent locality = "Zongyang" + // focused field = DEPENDENT_LOCALITY + // suggestions limit = 10 + // Suggestion: + // [{dependent_locality: "Zongyang Xian", + // locality: "Anqing Shi", + // administrative_area: "Anhui Sheng"}] + virtual Status GetSuggestions( + const ::i18n::addressinput::AddressData& user_input, + ::i18n::addressinput::AddressField focused_field, + size_t suggestion_limit, + std::vector< ::i18n::addressinput::AddressData>* suggestions) const; + + // Canonicalizes the administrative area in |address_data|. For example, + // "texas" changes to "TX". Returns true on success, otherwise leaves + // |address_data| alone and returns false. + virtual bool CanonicalizeAdministrativeArea( + ::i18n::addressinput::AddressData* address) const; + + protected: + // Constructor used only for MockAddressValidator. + AddressValidator(); + + // Returns the period of time to wait between the first attempt's failure and + // the second attempt's initiation to load rules. Exposed for testing. + virtual base::TimeDelta GetBaseRetryPeriod() const; + + private: + // Verifies that |validator_| succeeded. Invoked by |validated_| callback. + void Validated(bool success, + const ::i18n::addressinput::AddressData&, + const ::i18n::addressinput::FieldProblemMap&); + + // Invokes the |load_rules_listener_|, if it's not NULL. Called by + // |rules_loaded_| callback. + void RulesLoaded(bool success, const std::string& region_code, int); + + // Retries loading rules without resetting the retry counter. + void RetryLoadRules(const std::string& region_code); + + // Loads and stores aggregate rules at COUNTRY level. + const scoped_ptr< ::i18n::addressinput::PreloadSupplier> supplier_; + + // Suggests addresses based on user input. + const scoped_ptr<InputSuggester> input_suggester_; + + // Normalizes addresses into a canonical form. + const scoped_ptr< ::i18n::addressinput::AddressNormalizer> normalizer_; + + // Validates addresses. + const scoped_ptr<const ::i18n::addressinput::AddressValidator> validator_; + + // The callback that |validator_| invokes when it finished validating an + // address. + const scoped_ptr<const ::i18n::addressinput::AddressValidator::Callback> + validated_; + + // The callback that |supplier_| invokes when it finished loading rules. + const scoped_ptr<const ::i18n::addressinput::PreloadSupplier::Callback> + rules_loaded_; + + // Not owned delegate to invoke when |suppler_| finished loading rules. Can be + // NULL. + LoadRulesListener* const load_rules_listener_; + + // A mapping of region codes to the number of attempts to retry loading rules. + std::map<std::string, int> attempts_number_; + + // Member variables should appear before the WeakPtrFactory, to ensure that + // any WeakPtrs to AddressValidator are invalidated before its members + // variable's destructors are executed, rendering them invalid. + base::WeakPtrFactory<AddressValidator> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AddressValidator); +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_ADDRESS_VALIDATOR_H_ diff --git a/chromium/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc b/chromium/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc new file mode 100644 index 00000000000..a7f9861247f --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc @@ -0,0 +1,892 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/chrome_address_validator.h" + +#include <stddef.h> +#include <string> +#include <utility> +#include <vector> + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" +#include "third_party/libaddressinput/src/cpp/test/testdata_source.h" + +namespace autofill { + +using ::i18n::addressinput::AddressData; +using ::i18n::addressinput::AddressField; +using ::i18n::addressinput::AddressProblem; +using ::i18n::addressinput::BuildCallback; +using ::i18n::addressinput::FieldProblemMap; +using ::i18n::addressinput::GetRegionCodes; +using ::i18n::addressinput::NullStorage; +using ::i18n::addressinput::Source; +using ::i18n::addressinput::Storage; +using ::i18n::addressinput::TestdataSource; + +using ::i18n::addressinput::COUNTRY; +using ::i18n::addressinput::ADMIN_AREA; +using ::i18n::addressinput::LOCALITY; +using ::i18n::addressinput::DEPENDENT_LOCALITY; +using ::i18n::addressinput::SORTING_CODE; +using ::i18n::addressinput::POSTAL_CODE; +using ::i18n::addressinput::STREET_ADDRESS; +using ::i18n::addressinput::RECIPIENT; + +using ::i18n::addressinput::INVALID_FORMAT; +using ::i18n::addressinput::MISMATCHING_VALUE; +using ::i18n::addressinput::MISSING_REQUIRED_FIELD; +using ::i18n::addressinput::UNEXPECTED_FIELD; +using ::i18n::addressinput::UNKNOWN_VALUE; +using ::i18n::addressinput::USES_P_O_BOX; + +class AddressValidatorTest : public testing::Test, LoadRulesListener { + protected: + AddressValidatorTest() + : validator_( + new AddressValidator(scoped_ptr<Source>(new TestdataSource(true)), + scoped_ptr<Storage>(new NullStorage), + this)) { + validator_->LoadRules("US"); + } + + virtual ~AddressValidatorTest() {} + + const scoped_ptr<AddressValidator> validator_; + + private: + // LoadRulesListener implementation. + virtual void OnAddressValidationRulesLoaded(const std::string& country_code, + bool success) override { + AddressData address_data; + address_data.region_code = country_code; + FieldProblemMap dummy; + AddressValidator::Status status = + validator_->ValidateAddress(address_data, NULL, &dummy); + ASSERT_EQ(success, status == AddressValidator::SUCCESS); + } + + DISALLOW_COPY_AND_ASSIGN(AddressValidatorTest); +}; + +// Use this test fixture if you're going to use a region with a large set of +// validation rules. All rules should be loaded in SetUpTestCase(). +class LargeAddressValidatorTest : public testing::Test { + protected: + LargeAddressValidatorTest() {} + virtual ~LargeAddressValidatorTest() {} + + static void SetUpTestCase() { + validator_ = + new AddressValidator(scoped_ptr<Source>(new TestdataSource(true)), + scoped_ptr<Storage>(new NullStorage), + NULL); + validator_->LoadRules("CN"); + validator_->LoadRules("KR"); + validator_->LoadRules("TW"); + } + + static void TearDownTestcase() { + delete validator_; + validator_ = NULL; + } + + // Owned shared instance of validator with large sets validation rules. + static AddressValidator* validator_; + + private: + DISALLOW_COPY_AND_ASSIGN(LargeAddressValidatorTest); +}; + +AddressValidator* LargeAddressValidatorTest::validator_ = NULL; + +TEST_F(AddressValidatorTest, RegionHasRules) { + const std::vector<std::string>& region_codes = GetRegionCodes(); + AddressData address; + for (size_t i = 0; i < region_codes.size(); ++i) { + SCOPED_TRACE("For region: " + region_codes[i]); + validator_->LoadRules(region_codes[i]); + address.region_code = region_codes[i]; + FieldProblemMap dummy; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &dummy)); + } +} + +TEST_F(AddressValidatorTest, EmptyAddressNoFatalFailure) { + AddressData address; + address.region_code = "US"; + + FieldProblemMap dummy; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &dummy)); +} + +TEST_F(AddressValidatorTest, UsStateNamesAreValidEntries) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "California"; + + FieldProblemMap filter; + filter.insert(std::make_pair(ADMIN_AREA, UNKNOWN_VALUE)); + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, &filter, &problems)); + EXPECT_TRUE(problems.empty()); +} + +TEST_F(AddressValidatorTest, USZipCode) { + AddressData address; + address.recipient = "Mr. Smith"; + address.address_line.push_back("340 Main St."); + address.locality = "Venice"; + address.administrative_area = "CA"; + address.region_code = "US"; + + // Valid Californian zip code. + address.postal_code = "90291"; + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); + + problems.clear(); + + // An extended, valid Californian zip code. + address.postal_code = "90210-1234"; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); + + problems.clear(); + + // New York zip code (which is invalid for California). + address.postal_code = "12345"; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_EQ(1U, problems.size()); + EXPECT_EQ(problems.begin()->first, POSTAL_CODE); + EXPECT_EQ(problems.begin()->second, MISMATCHING_VALUE); + + problems.clear(); + + // A zip code with a "90" in the middle. + address.postal_code = "12903"; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_EQ(1U, problems.size()); + EXPECT_EQ(problems.begin()->first, POSTAL_CODE); + EXPECT_EQ(problems.begin()->second, MISMATCHING_VALUE); + + problems.clear(); + + // Invalid zip code (too many digits). + address.postal_code = "902911"; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_EQ(1U, problems.size()); + EXPECT_EQ(problems.begin()->first, POSTAL_CODE); + EXPECT_EQ(problems.begin()->second, INVALID_FORMAT); + + problems.clear(); + + // Invalid zip code (too few digits). + address.postal_code = "9029"; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_EQ(1U, problems.size()); + EXPECT_EQ(problems.begin()->first, POSTAL_CODE); + EXPECT_EQ(problems.begin()->second, INVALID_FORMAT); +} + +TEST_F(AddressValidatorTest, BasicValidation) { + // US rules should always be available, even though this load call fails. + validator_->LoadRules("US"); + AddressData address; + address.region_code = "US"; + address.language_code = "en"; + address.administrative_area = "TX"; + address.locality = "Paris"; + address.postal_code = "75461"; + address.address_line.push_back("123 Main St"); + address.recipient = "Mr. Smith"; + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); + + // The display name works as well as the key. + address.administrative_area = "Texas"; + problems.clear(); + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); + + // Ignore capitalization. + address.administrative_area = "tx"; + problems.clear(); + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); + + // Ignore capitalization. + address.administrative_area = "teXas"; + problems.clear(); + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); + + // Ignore diacriticals. + address.administrative_area = base::WideToUTF8(L"T\u00E9xas"); + problems.clear(); + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_TRUE(problems.empty()); +} + +TEST_F(AddressValidatorTest, BasicValidationFailure) { + // US rules should always be available, even though this load call fails. + validator_->LoadRules("US"); + AddressData address; + address.region_code = "US"; + address.language_code = "en"; + address.administrative_area = "XT"; + address.locality = "Paris"; + address.postal_code = "75461"; + address.address_line.push_back("123 Main St"); + address.recipient = "Mr. Smith"; + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(address, NULL, &problems)); + + ASSERT_EQ(1U, problems.size()); + EXPECT_EQ(UNKNOWN_VALUE, problems.begin()->second); + EXPECT_EQ(ADMIN_AREA, problems.begin()->first); +} + +TEST_F(AddressValidatorTest, NoNullSuggestionsCrash) { + AddressData address; + address.region_code = "US"; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, COUNTRY, 1, NULL)); +} + +TEST_F(AddressValidatorTest, SuggestAdminAreaForPostalCode) { + AddressData address; + address.region_code = "US"; + address.postal_code = "90291"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("CA", suggestions[0].administrative_area); + EXPECT_EQ("90291", suggestions[0].postal_code); +} + +TEST_F(LargeAddressValidatorTest, SuggestLocalityForPostalCodeWithAdminArea) { + AddressData address; + address.region_code = "TW"; + address.postal_code = "515"; + address.administrative_area = "Changhua"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("Dacun Township", suggestions[0].locality); + EXPECT_EQ("Changhua County", suggestions[0].administrative_area); + EXPECT_EQ("515", suggestions[0].postal_code); +} + +TEST_F(LargeAddressValidatorTest, SuggestAdminAreaForPostalCodeWithLocality) { + AddressData address; + address.region_code = "TW"; + address.postal_code = "515"; + address.locality = "Dacun"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("Dacun Township", suggestions[0].locality); + EXPECT_EQ("Changhua County", suggestions[0].administrative_area); + EXPECT_EQ("515", suggestions[0].postal_code); +} + +TEST_F(AddressValidatorTest, NoSuggestForPostalCodeWithWrongAdminArea) { + AddressData address; + address.region_code = "US"; + address.postal_code = "90066"; + address.postal_code = "TX"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(LargeAddressValidatorTest, SuggestForLocality) { + AddressData address; + address.region_code = "CN"; + address.locality = "Anqin"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, LOCALITY, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("Anqing Shi", suggestions[0].locality); + EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area); +} + +TEST_F(LargeAddressValidatorTest, SuggestForLocalityAndAdminArea) { + AddressData address; + address.region_code = "CN"; + address.locality = "Anqing"; + address.administrative_area = "Anhui"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, LOCALITY, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_TRUE(suggestions[0].dependent_locality.empty()); + EXPECT_EQ("Anqing Shi", suggestions[0].locality); + EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area); +} + +TEST_F(LargeAddressValidatorTest, SuggestForAdminAreaAndLocality) { + AddressData address; + address.region_code = "CN"; + address.locality = "Anqing"; + address.administrative_area = "Anhui"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_TRUE(suggestions[0].dependent_locality.empty()); + EXPECT_TRUE(suggestions[0].locality.empty()); + EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area); +} + +TEST_F(LargeAddressValidatorTest, SuggestForDependentLocality) { + AddressData address; + address.region_code = "CN"; + address.dependent_locality = "Zongyang"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions( + address, DEPENDENT_LOCALITY, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("Zongyang Xian", suggestions[0].dependent_locality); + EXPECT_EQ("Anqing Shi", suggestions[0].locality); + EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area); +} + +TEST_F(LargeAddressValidatorTest, + NoSuggestForDependentLocalityWithWrongAdminArea) { + AddressData address; + address.region_code = "CN"; + address.dependent_locality = "Zongyang"; + address.administrative_area = "Sichuan Sheng"; + address.language_code = "zh-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions( + address, DEPENDENT_LOCALITY, 10, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(AddressValidatorTest, EmptySuggestionsOverLimit) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "A"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(AddressValidatorTest, PreferShortSuggestions) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "CA"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("CA", suggestions[0].administrative_area); +} + +TEST_F(AddressValidatorTest, SuggestTheSingleMatchForFullMatchName) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "Texas"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("Texas", suggestions[0].administrative_area); +} + +TEST_F(AddressValidatorTest, SuggestAdminArea) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "Cali"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("California", suggestions[0].administrative_area); +} + +TEST_F(AddressValidatorTest, MultipleSuggestions) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "MA"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions)); + EXPECT_LT(1U, suggestions.size()); + + // Massachusetts should not be a suggestion, because it's already covered + // under MA. + std::set<std::string> expected_suggestions; + expected_suggestions.insert("MA"); + expected_suggestions.insert("Maine"); + expected_suggestions.insert("Marshall Islands"); + expected_suggestions.insert("Maryland"); + for (std::vector<AddressData>::const_iterator it = suggestions.begin(); + it != suggestions.end(); + ++it) { + expected_suggestions.erase(it->administrative_area); + } + EXPECT_TRUE(expected_suggestions.empty()); +} + +TEST_F(LargeAddressValidatorTest, SuggestNonLatinKeyWhenLanguageMatches) { + AddressData address; + address.language_code = "ko"; + address.region_code = "KR"; + address.postal_code = "210-210"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("강원도", suggestions[0].administrative_area); + EXPECT_EQ("210-210", suggestions[0].postal_code); +} + +TEST_F(LargeAddressValidatorTest, SuggestNonLatinKeyWhenUserInputIsNotLatin) { + AddressData address; + address.language_code = "en"; + address.region_code = "KR"; + address.administrative_area = "강원"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("강원도", suggestions[0].administrative_area); +} + +TEST_F(LargeAddressValidatorTest, + SuggestLatinNameWhenLanguageDiffersAndLatinNameAvailable) { + AddressData address; + address.language_code = "ko-Latn"; + address.region_code = "KR"; + address.postal_code = "210-210"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("Gangwon", suggestions[0].administrative_area); + EXPECT_EQ("210-210", suggestions[0].postal_code); +} + +TEST_F(AddressValidatorTest, NoSuggestionsForEmptyAddress) { + AddressData address; + address.region_code = "US"; + + std::vector<AddressData> suggestions; + EXPECT_EQ( + AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(AddressValidatorTest, SuggestionIncludesCountry) { + AddressData address; + address.region_code = "US"; + address.postal_code = "90291"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("US", suggestions[0].region_code); +} + +TEST_F(AddressValidatorTest, InvalidPostalCodeNoSuggestions) { + AddressData address; + address.region_code = "US"; + address.postal_code = "0"; + + std::vector<AddressData> suggestions; + EXPECT_EQ( + AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(AddressValidatorTest, MismatchedPostalCodeNoSuggestions) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "TX"; + address.postal_code = "90291"; + + std::vector<AddressData> suggestions; + EXPECT_EQ( + AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(AddressValidatorTest, SuggestOnlyForAdministrativeAreasAndPostalCode) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "CA"; + address.locality = "Los Angeles"; + address.dependent_locality = "Venice"; + address.postal_code = "90291"; + address.sorting_code = "123"; + address.address_line.push_back("123 Main St"); + address.recipient = "Jon Smith"; + + // Fields that should not have suggestions in US. + static const AddressField kNoSugestFields[] = { + COUNTRY, + LOCALITY, + DEPENDENT_LOCALITY, + SORTING_CODE, + STREET_ADDRESS, + RECIPIENT + }; + + static const size_t kNumNoSuggestFields = + sizeof kNoSugestFields / sizeof (AddressField); + + for (size_t i = 0; i < kNumNoSuggestFields; ++i) { + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions( + address, kNoSugestFields[i], 999, &suggestions)); + EXPECT_TRUE(suggestions.empty()); + } +} + +TEST_F(AddressValidatorTest, SuggestionsAreCleared) { + AddressData address; + address.region_code = "US"; + + std::vector<AddressData> suggestions(1, address); + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); + EXPECT_TRUE(suggestions.empty()); +} + +TEST_F(AddressValidatorTest, CanonicalizeUsAdminAreaName) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "cALIFORNIa"; + EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); + EXPECT_EQ("CA", address.administrative_area); +} + +TEST_F(AddressValidatorTest, CanonicalizeUsAdminAreaKey) { + AddressData address; + address.region_code = "US"; + address.administrative_area = "CA"; + EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); + EXPECT_EQ("CA", address.administrative_area); +} + +TEST_F(AddressValidatorTest, CanonicalizeJpAdminAreaKey) { + validator_->LoadRules("JP"); + AddressData address; + address.region_code = "JP"; + address.administrative_area = "東京都"; + EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); + EXPECT_EQ("東京都", address.administrative_area); +} + +TEST_F(AddressValidatorTest, CanonicalizeJpAdminAreaLatinName) { + validator_->LoadRules("JP"); + AddressData address; + address.region_code = "JP"; + address.administrative_area = "tOKYo"; + EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); + EXPECT_EQ("TOKYO", address.administrative_area); +} + +TEST_F(AddressValidatorTest, TokushimaSuggestionIsValid) { + validator_->LoadRules("JP"); + AddressData address; + address.region_code = "JP"; + address.administrative_area = "Toku"; + address.language_code = "ja-Latn"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("TOKUSHIMA", suggestions[0].administrative_area); + + FieldProblemMap filter; + for (int i = UNEXPECTED_FIELD; i <= USES_P_O_BOX; ++i) + filter.insert(std::make_pair(ADMIN_AREA, static_cast<AddressProblem>(i))); + + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->ValidateAddress(suggestions[0], &filter, &problems)); + EXPECT_TRUE(problems.empty()); +} + +TEST_F(AddressValidatorTest, ValidPostalCodeInSuggestion) { + validator_->LoadRules("US"); + AddressData address; + address.region_code = "US"; + address.administrative_area = "New"; + address.postal_code = "13699"; + + std::vector<AddressData> suggestions; + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 999, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("New York", suggestions[0].administrative_area); + + address.administrative_area = "New"; + address.postal_code = "03755"; + + EXPECT_EQ(AddressValidator::SUCCESS, + validator_->GetSuggestions(address, ADMIN_AREA, 999, &suggestions)); + ASSERT_EQ(1U, suggestions.size()); + EXPECT_EQ("New Hampshire", suggestions[0].administrative_area); +} + +TEST_F(AddressValidatorTest, ValidateRequiredFieldsWithoutRules) { + // Do not load the rules for JP. + AddressData address; + address.region_code = "JP"; + + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::RULES_UNAVAILABLE, + validator_->ValidateAddress(address, NULL, &problems)); + EXPECT_FALSE(problems.empty()); + + for (FieldProblemMap::const_iterator it = problems.begin(); + it != problems.end(); + ++it) { + EXPECT_EQ(MISSING_REQUIRED_FIELD, it->second); + } +} + +TEST_F(AddressValidatorTest, + DoNotValidateRequiredFieldsWithoutRulesWhenErorrIsFiltered) { + // Do not load the rules for JP. + AddressData address; + address.region_code = "JP"; + + FieldProblemMap filter; + filter.insert(std::make_pair(COUNTRY, UNKNOWN_VALUE)); + + FieldProblemMap problems; + EXPECT_EQ(AddressValidator::RULES_UNAVAILABLE, + validator_->ValidateAddress(address, &filter, &problems)); + EXPECT_TRUE(problems.empty()); +} + +// Use this test fixture for configuring the number of failed attempts to load +// rules. +class FailingAddressValidatorTest : public testing::Test, LoadRulesListener { + protected: + // A validator that retries loading rules without delay. + class TestAddressValidator : public AddressValidator { + public: + // Takes ownership of |source| and |storage|. + TestAddressValidator(scoped_ptr<::i18n::addressinput::Source> source, + scoped_ptr<::i18n::addressinput::Storage> storage, + LoadRulesListener* load_rules_listener) + : AddressValidator(std::move(source), + std::move(storage), + load_rules_listener) {} + + virtual ~TestAddressValidator() {} + + protected: + virtual base::TimeDelta GetBaseRetryPeriod() const override { + return base::TimeDelta::FromSeconds(0); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestAddressValidator); + }; + + // A source that always fails |failures_number| times before downloading + // data. + class FailingSource : public Source { + public: + explicit FailingSource() + : failures_number_(0), attempts_number_(0), actual_source_(true) {} + virtual ~FailingSource() {} + + // Sets the number of times to fail before downloading data. + void set_failures_number(int failures_number) { + failures_number_ = failures_number; + } + + // Source implementation. + // Always fails for the first |failures_number| times. + virtual void Get(const std::string& url, + const Callback& callback) const override { + ++attempts_number_; + // |callback| takes ownership of the |new std::string|. + if (failures_number_-- > 0) + callback(false, url, new std::string); + else + actual_source_.Get(url, callback); + } + + // Returns the number of download attempts. + int attempts_number() const { return attempts_number_; } + + private: + // The number of times to fail before downloading data. + mutable int failures_number_; + + // The number of times Get was called. + mutable int attempts_number_; + + // The source to use for successful downloads. + TestdataSource actual_source_; + + DISALLOW_COPY_AND_ASSIGN(FailingSource); + }; + + FailingAddressValidatorTest() + : source_(new FailingSource), + validator_( + new TestAddressValidator(scoped_ptr<Source>(source_), + scoped_ptr<Storage>(new NullStorage), + this)), + load_rules_success_(false) {} + + virtual ~FailingAddressValidatorTest() {} + + FailingSource* source_; // Owned by |validator_|. + scoped_ptr<AddressValidator> validator_; + bool load_rules_success_; + + private: + // LoadRulesListener implementation. + virtual void OnAddressValidationRulesLoaded(const std::string&, + bool success) override { + load_rules_success_ = success; + } + + base::MessageLoop ui_; + + DISALLOW_COPY_AND_ASSIGN(FailingAddressValidatorTest); +}; + +// The validator will attempt to load rules at most 8 times. +TEST_F(FailingAddressValidatorTest, RetryLoadingRulesHasLimit) { + source_->set_failures_number(99); + validator_->LoadRules("CH"); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(load_rules_success_); + EXPECT_EQ(8, source_->attempts_number()); +} + +// The validator will load rules successfully if the source returns data +// before the maximum number of retries. +TEST_F(FailingAddressValidatorTest, RuleRetryingWillSucceed) { + source_->set_failures_number(4); + validator_->LoadRules("CH"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(load_rules_success_); + EXPECT_EQ(5, source_->attempts_number()); +} + +// The delayed task to retry loading rules should stop (instead of crashing) if +// the validator is destroyed before it fires. +TEST_F(FailingAddressValidatorTest, DestroyedValidatorStopsRetries) { + source_->set_failures_number(4); + validator_->LoadRules("CH"); + + // Destroy the validator. + validator_.reset(); + + // Fire the delayed task to retry loading rules. + EXPECT_NO_FATAL_FAILURE(base::RunLoop().RunUntilIdle()); +} + +// Each call to LoadRules should reset the number of retry attempts. If the +// first call to LoadRules exceeded the maximum number of retries, the second +// call to LoadRules should start counting the retries from zero. +TEST_F(FailingAddressValidatorTest, LoadingRulesSecondTimeSucceeds) { + source_->set_failures_number(11); + validator_->LoadRules("CH"); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(load_rules_success_); + EXPECT_EQ(8, source_->attempts_number()); + + validator_->LoadRules("CH"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(load_rules_success_); + EXPECT_EQ(12, source_->attempts_number()); +} + +// Calling LoadRules("CH") and LoadRules("GB") simultaneously should attempt to +// load both rules up to the maximum number of attempts for each region. +TEST_F(FailingAddressValidatorTest, RegionsShouldRetryIndividually) { + source_->set_failures_number(99); + validator_->LoadRules("CH"); + validator_->LoadRules("GB"); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(load_rules_success_); + EXPECT_EQ(16, source_->attempts_number()); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/chrome_metadata_source.cc b/chromium/third_party/libaddressinput/chromium/chrome_metadata_source.cc new file mode 100644 index 00000000000..57c5acd4c25 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_metadata_source.cc @@ -0,0 +1,112 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/chrome_metadata_source.h" + +#include <utility> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/stl_util.h" +#include "net/base/io_buffer.h" +#include "net/base/load_flags.h" +#include "net/base/net_errors.h" +#include "net/http/http_status_code.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_fetcher_response_writer.h" +#include "url/gurl.h" + +namespace autofill { + +namespace { + +// A URLFetcherResponseWriter that writes into a provided buffer. +class UnownedStringWriter : public net::URLFetcherResponseWriter { + public: + UnownedStringWriter(std::string* data) : data_(data) {} + virtual ~UnownedStringWriter() {} + + virtual int Initialize(const net::CompletionCallback& callback) override { + data_->clear(); + return net::OK; + } + + virtual int Write(net::IOBuffer* buffer, + int num_bytes, + const net::CompletionCallback& callback) override { + data_->append(buffer->data(), num_bytes); + return num_bytes; + } + + virtual int Finish(const net::CompletionCallback& callback) override { + return net::OK; + } + + private: + std::string* data_; // weak reference. + + DISALLOW_COPY_AND_ASSIGN(UnownedStringWriter); +}; + +} // namespace + +ChromeMetadataSource::ChromeMetadataSource( + const std::string& validation_data_url, + net::URLRequestContextGetter* getter) + : validation_data_url_(validation_data_url), + getter_(getter) {} + +ChromeMetadataSource::~ChromeMetadataSource() { + STLDeleteValues(&requests_); +} + +void ChromeMetadataSource::Get(const std::string& key, + const Callback& downloaded) const { + const_cast<ChromeMetadataSource*>(this)->Download(key, downloaded); +} + +void ChromeMetadataSource::OnURLFetchComplete(const net::URLFetcher* source) { + std::map<const net::URLFetcher*, Request*>::iterator request = + requests_.find(source); + DCHECK(request != requests_.end()); + + bool ok = source->GetResponseCode() == net::HTTP_OK; + scoped_ptr<std::string> data(new std::string()); + if (ok) + data->swap(request->second->data); + request->second->callback(ok, request->second->key, data.release()); + + delete request->second; + requests_.erase(request); +} + +ChromeMetadataSource::Request::Request(const std::string& key, + scoped_ptr<net::URLFetcher> fetcher, + const Callback& callback) + : key(key), fetcher(std::move(fetcher)), callback(callback) {} + +void ChromeMetadataSource::Download(const std::string& key, + const Callback& downloaded) { + GURL resource(validation_data_url_ + key); + if (!resource.SchemeIsCryptographic()) { + downloaded(false, key, NULL); + return; + } + + scoped_ptr<net::URLFetcher> fetcher = + net::URLFetcher::Create(resource, net::URLFetcher::GET, this); + fetcher->SetLoadFlags( + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); + fetcher->SetRequestContext(getter_); + + Request* request = new Request(key, std::move(fetcher), downloaded); + request->fetcher->SaveResponseWithWriter( + scoped_ptr<net::URLFetcherResponseWriter>( + new UnownedStringWriter(&request->data))); + requests_[request->fetcher.get()] = request; + request->fetcher->Start(); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/chrome_metadata_source.h b/chromium/third_party/libaddressinput/chromium/chrome_metadata_source.h new file mode 100644 index 00000000000..624e6e4fe5f --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_metadata_source.h @@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_METADATA_SOURCE_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_METADATA_SOURCE_H_ + +#include <map> +#include <string> + +#include "base/macros.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h" + +namespace net { +class URLFetcher; +class URLRequestContextGetter; +} + +namespace autofill { + +// A class for downloading rules to let libaddressinput validate international +// addresses. +class ChromeMetadataSource : public ::i18n::addressinput::Source, + public net::URLFetcherDelegate { + public: + ChromeMetadataSource(const std::string& validation_data_url, + net::URLRequestContextGetter* getter); + virtual ~ChromeMetadataSource(); + + // ::i18n::addressinput::Source: + virtual void Get(const std::string& key, + const Callback& downloaded) const override; + + // net::URLFetcherDelegate: + virtual void OnURLFetchComplete(const net::URLFetcher* source) override; + + private: + struct Request { + Request(const std::string& key, + scoped_ptr<net::URLFetcher> fetcher, + const Callback& callback); + + std::string key; + // The data that's received. + std::string data; + // The object that manages retrieving the data. + scoped_ptr<net::URLFetcher> fetcher; + const Callback& callback; + }; + + // Non-const method actually implementing Get(). + void Download(const std::string& key, const Callback& downloaded); + + const std::string validation_data_url_; + net::URLRequestContextGetter* const getter_; // weak + + // Maps from active URL fetcher to request metadata. The value is owned. + std::map<const net::URLFetcher*, Request*> requests_; + + DISALLOW_COPY_AND_ASSIGN(ChromeMetadataSource); +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_METADATA_SOURCE_H_ diff --git a/chromium/third_party/libaddressinput/chromium/chrome_metadata_source_unittest.cc b/chromium/third_party/libaddressinput/chromium/chrome_metadata_source_unittest.cc new file mode 100644 index 00000000000..ae92a76654b --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_metadata_source_unittest.cc @@ -0,0 +1,100 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/chrome_metadata_source.h" + +#include "base/thread_task_runner_handle.h" +#include "net/url_request/test_url_fetcher_factory.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +static const char kFakeUrl[] = "https://example.com"; +static const char kFakeInsecureUrl[] = "http://example.com"; + +class ChromeMetadataSourceTest : public testing::Test { + public: + ChromeMetadataSourceTest() + : fake_factory_(&factory_), + success_(false) {} + virtual ~ChromeMetadataSourceTest() {} + + protected: + // Sets the response for the download. + void SetFakeResponse(const std::string& payload, net::HttpStatusCode code) { + fake_factory_.SetFakeResponse(url_, + payload, + code, + net::URLRequestStatus::SUCCESS); + } + + // Kicks off the download. + void Get() { + scoped_refptr<net::TestURLRequestContextGetter> getter( + new net::TestURLRequestContextGetter( + base::ThreadTaskRunnerHandle::Get())); + ChromeMetadataSource impl(std::string(), getter.get()); + scoped_ptr< ::i18n::addressinput::Source::Callback> callback( + ::i18n::addressinput::BuildCallback( + this, &ChromeMetadataSourceTest::OnDownloaded)); + impl.Get(url_.spec(), *callback); + base::MessageLoop::current()->RunUntilIdle(); + } + + void set_url(const GURL& url) { url_ = url; } + bool success() const { return success_; } + bool has_data() const { return !!data_; } + + const std::string& data() const { + DCHECK(data_); + return *data_; + } + + private: + // Callback for when download is finished. + void OnDownloaded(bool success, + const std::string& url, + std::string* data) { + ASSERT_FALSE(success && data == NULL); + success_ = success; + data_.reset(data); + } + + base::MessageLoop loop_; + net::URLFetcherImplFactory factory_; + net::FakeURLFetcherFactory fake_factory_; + GURL url_; + scoped_ptr<std::string> data_; + bool success_; +}; + +TEST_F(ChromeMetadataSourceTest, Success) { + const char kFakePayload[] = "ham hock"; + set_url(GURL(kFakeUrl)); + SetFakeResponse(kFakePayload, net::HTTP_OK); + Get(); + EXPECT_TRUE(success()); + EXPECT_EQ(kFakePayload, data()); +} + +TEST_F(ChromeMetadataSourceTest, Failure) { + const char kFakePayload[] = "ham hock"; + set_url(GURL(kFakeUrl)); + SetFakeResponse(kFakePayload, net::HTTP_INTERNAL_SERVER_ERROR); + Get(); + EXPECT_FALSE(success()); + EXPECT_TRUE(!has_data() || data().empty()); +} + +TEST_F(ChromeMetadataSourceTest, RejectsInsecureScheme) { + const char kFakePayload[] = "ham hock"; + set_url(GURL(kFakeInsecureUrl)); + SetFakeResponse(kFakePayload, net::HTTP_OK); + Get(); + EXPECT_FALSE(success()); + EXPECT_TRUE(!has_data() || data().empty()); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/chrome_rule_test.cc b/chromium/third_party/libaddressinput/chromium/chrome_rule_test.cc new file mode 100644 index 00000000000..e0d5c2f16bc --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_rule_test.cc @@ -0,0 +1,60 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/src/cpp/src/rule.h" + +#include <stddef.h> + +#include <string> + +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(RuleTest, CanonicalizeSubKeyTest) { + i18n::addressinput::Rule rule; + ASSERT_TRUE(rule.ParseSerializedRule(base::WideToUTF8( + L"{ \"sub_keys\": \"FOO~BAR~B\u00C4Z~\u0415\u0416\"," + L" \"sub_names\": \"Foolandia~Bartopolis~B\u00E4zmonia~" + L"\u0415\u0436ville\" }"))); + EXPECT_EQ(4U, rule.GetSubKeys().size()); + + static const struct { + const wchar_t* input; + // If empty, expect failure. + const wchar_t* output; + } expectations[] = { + { L"foo", L"FOO" }, + { L"Foo", L"FOO" }, + { L"FOO", L"FOO" }, + { L"F", L"" }, + { L"FOO2", L"" }, + { L"", L"" }, + { L"Bar", L"BAR" }, + { L"Bartopolis", L"BAR" }, + { L"BARTOPOLIS", L"BAR" }, + { L"BaRToPoLiS", L"BAR" }, + // Diacriticals. + { L"B\u00C4Z", L"B\u00C4Z" }, + { L"BAZ", L"B\u00C4Z" }, + { L"B\u00E4zmonia", L"B\u00C4Z" }, + { L"bazmonia", L"B\u00C4Z" }, + // Non-ascii (Cyrillic) case sensitivity. + { L"\u0415\u0416", L"\u0415\u0416" }, + { L"\u0415\u0416VILLE", L"\u0415\u0416" }, + { L"\u0435\u0436", L"\u0415\u0416" }, + { L"\u0435\u0436VILLE", L"\u0415\u0416" }, + { L"\u0435\u0436VILL", L"" }, + }; + + const size_t num_cases = sizeof(expectations) / sizeof(expectations[0]); + for (size_t i = 0; i < num_cases; ++i) { + const std::string input(base::WideToUTF8(expectations[i].input)); + const std::string expected_output(base::WideToUTF8(expectations[i].output)); + std::string output; + EXPECT_EQ(!expected_output.empty(), + rule.CanonicalizeSubKey(input, true, &output)) + << "Failed for input " << input; + EXPECT_EQ(expected_output, output); + } +} diff --git a/chromium/third_party/libaddressinput/chromium/chrome_storage_impl.cc b/chromium/third_party/libaddressinput/chromium/chrome_storage_impl.cc new file mode 100644 index 00000000000..918d3f2ee01 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_storage_impl.cc @@ -0,0 +1,74 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/chrome_storage_impl.h" + +#include <utility> + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "components/prefs/writeable_pref_store.h" +#include "third_party/libaddressinput/chromium/fallback_data_store.h" + +namespace autofill { + +ChromeStorageImpl::ChromeStorageImpl(WriteablePrefStore* store) + : backing_store_(store), + scoped_observer_(this) { + scoped_observer_.Add(backing_store_); +} + +ChromeStorageImpl::~ChromeStorageImpl() {} + +void ChromeStorageImpl::Put(const std::string& key, std::string* data) { + DCHECK(data); + scoped_ptr<std::string> owned_data(data); + scoped_ptr<base::StringValue> string_value( + new base::StringValue(std::string())); + string_value->GetString()->swap(*owned_data); + backing_store_->SetValue(key, std::move(string_value), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); +} + +void ChromeStorageImpl::Get(const std::string& key, + const Storage::Callback& data_ready) const { + // |Get()| should not be const, so this is just a thunk that fixes that. + const_cast<ChromeStorageImpl*>(this)->DoGet(key, data_ready); +} + +void ChromeStorageImpl::OnPrefValueChanged(const std::string& key) {} + +void ChromeStorageImpl::OnInitializationCompleted(bool succeeded) { + for (std::vector<Request*>::iterator iter = outstanding_requests_.begin(); + iter != outstanding_requests_.end(); ++iter) { + DoGet((*iter)->key, (*iter)->callback); + } + + outstanding_requests_.clear(); +} + +void ChromeStorageImpl::DoGet(const std::string& key, + const Storage::Callback& data_ready) { + if (!backing_store_->IsInitializationComplete()) { + outstanding_requests_.push_back(new Request(key, data_ready)); + return; + } + + const base::Value* value = NULL; + scoped_ptr<std::string> data(new std::string); + if (backing_store_->GetValue(key, &value) && value->GetAsString(data.get())) { + data_ready(true, key, data.release()); + } else if (FallbackDataStore::Get(key, data.get())) { + data_ready(true, key, data.release()); + } else { + data_ready(false, key, NULL); + } +} + +ChromeStorageImpl::Request::Request(const std::string& key, + const Callback& callback) + : key(key), + callback(callback) {} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/chrome_storage_impl.h b/chromium/third_party/libaddressinput/chromium/chrome_storage_impl.h new file mode 100644 index 00000000000..6a08adc59e2 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_storage_impl.h @@ -0,0 +1,62 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_STORAGE_IMPL_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_STORAGE_IMPL_H_ + +#include <list> +#include <string> + +#include "base/macros.h" +#include "base/memory/scoped_vector.h" +#include "base/scoped_observer.h" +#include "components/prefs/pref_store.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" + +class WriteablePrefStore; + +namespace autofill { + +// An implementation of the Storage interface which passes through to an +// underlying WriteablePrefStore. +class ChromeStorageImpl : public ::i18n::addressinput::Storage, + public PrefStore::Observer { + public: + // |store| must outlive |this|. + explicit ChromeStorageImpl(WriteablePrefStore* store); + virtual ~ChromeStorageImpl(); + + // ::i18n::addressinput::Storage implementation. + virtual void Put(const std::string& key, std::string* data) override; + virtual void Get(const std::string& key, const Callback& data_ready) + const override; + + // PrefStore::Observer implementation. + virtual void OnPrefValueChanged(const std::string& key) override; + virtual void OnInitializationCompleted(bool succeeded) override; + + private: + struct Request { + Request(const std::string& key, const Callback& callback); + + std::string key; + const Callback& callback; + }; + + // Non-const version of Get(). + void DoGet(const std::string& key, const Callback& data_ready); + + WriteablePrefStore* backing_store_; // weak + + // Get requests that haven't yet been serviced. + ScopedVector<Request> outstanding_requests_; + + ScopedObserver<PrefStore, ChromeStorageImpl> scoped_observer_; + + DISALLOW_COPY_AND_ASSIGN(ChromeStorageImpl); +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_CHROME_STORAGE_IMPL_H_ diff --git a/chromium/third_party/libaddressinput/chromium/chrome_storage_impl_unittest.cc b/chromium/third_party/libaddressinput/chromium/chrome_storage_impl_unittest.cc new file mode 100644 index 00000000000..629b8ffc345 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/chrome_storage_impl_unittest.cc @@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/chrome_storage_impl.h" + +#include <string> + +#include "components/prefs/value_map_pref_store.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libaddressinput/chromium/storage_test_runner.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h" + +namespace autofill { + +// Tests for ChromeStorageImpl object. +class ChromeStorageImplTest : public testing::Test { + protected: + ChromeStorageImplTest() + : store_(new ValueMapPrefStore()), + storage_(store_.get()), + runner_(&storage_) {} + + virtual ~ChromeStorageImplTest() {} + + scoped_refptr<ValueMapPrefStore> store_; + ChromeStorageImpl storage_; + StorageTestRunner runner_; +}; + +TEST_F(ChromeStorageImplTest, StandardStorageTests) { + EXPECT_NO_FATAL_FAILURE(runner_.RunAllTests()); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/fallback_data_store.cc b/chromium/third_party/libaddressinput/chromium/fallback_data_store.cc new file mode 100644 index 00000000000..4c20aa10d27 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/fallback_data_store.cc @@ -0,0 +1,203 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "fallback_data_store.h" + +#include <string> + +namespace autofill { + +bool FallbackDataStore::Get(const std::string& key, std::string* data) { + if (key != "data/US") + return false; + + // Available at https://i18napis.appspot.com/ssl-aggregate-address/data/US. + // The appended checksum is valid, but the timestamp is old. + data->assign( + "timestamp=0\n" + "checksum=38d4bcdadfe494ffe062a7ad668d66d6\n" + "{\"data/US/LA\": {\"lang\": \"en\", \"zipex\": \"70000,71599\", \"nam" + "e\": \"Louisiana\", \"zip\": \"70|71[0-5]\", \"key\": \"LA\", \"id\":" + " \"data/US/LA\"}, \"data/US/VT\": {\"lang\": \"en\", \"zipex\": \"0500" + "0,05999\", \"name\": \"Vermont\", \"zip\": \"05\", \"key\": \"VT\", \"" + "id\": \"data/US/VT\"}, \"data/US/NM\": {\"lang\": \"en\", \"zipex\": \"" + "87000,88499\", \"name\": \"New Mexico\", \"zip\": \"87|88[0-4]\", \"k" + "ey\": \"NM\", \"id\": \"data/US/NM\"}, \"data/US/NJ\": {\"lang\": \"e" + "n\", \"zipex\": \"07000,08999\", \"name\": \"New Jersey\", \"zip\": \"" + "0[78]\", \"key\": \"NJ\", \"id\": \"data/US/NJ\"}, \"data/US/NH\": {\"" + "lang\": \"en\", \"zipex\": \"03000,03899\", \"name\": \"New Hampshire\"" + ", \"zip\": \"03[0-8]\", \"key\": \"NH\", \"id\": \"data/US/NH\"}, \"d" + "ata/US/ND\": {\"lang\": \"en\", \"zipex\": \"58000,58999\", \"name\":" + " \"North Dakota\", \"zip\": \"58\", \"key\": \"ND\", \"id\": \"data/US" + "/ND\"}, \"data/US/NE\": {\"lang\": \"en\", \"zipex\": \"68000,69999\"," + " \"name\": \"Nebraska\", \"zip\": \"6[89]\", \"key\": \"NE\", \"id\":" + " \"data/US/NE\"}, \"data/US/NC\": {\"lang\": \"en\", \"zipex\": \"2700" + "0,28999\", \"name\": \"North Carolina\", \"zip\": \"2[78]\", \"key\":" + " \"NC\", \"id\": \"data/US/NC\"}, \"data/US/PR\": {\"lang\": \"en\", \"" + "zipex\": \"00600,00799:00900,00999\", \"name\": \"Puerto Rico\", \"zi" + "p\": \"00[679]\", \"key\": \"PR\", \"id\": \"data/US/PR\"}, \"data/US/" + "RI\": {\"lang\": \"en\", \"zipex\": \"02800,02999\", \"name\": \"Rhode" + " Island\", \"zip\": \"02[89]\", \"key\": \"RI\", \"id\": \"data/US/RI\"" + "}, \"data/US/NY\": {\"lang\": \"en\", \"zipex\": \"10000,14999:06390:" + "00501:00544\", \"name\": \"New York\", \"zip\": \"1[0-4]|06390|00501|0" + "0544\", \"key\": \"NY\", \"id\": \"data/US/NY\"}, \"data/US/NV\": {\"l" + "ang\": \"en\", \"zipex\": \"88900,89999\", \"name\": \"Nevada\", \"zi" + "p\": \"889|89\", \"key\": \"NV\", \"id\": \"data/US/NV\"}, \"data/US/K" + "Y\": {\"lang\": \"en\", \"zipex\": \"40000,42799\", \"name\": \"Kentuc" + "ky\", \"zip\": \"4[01]|42[0-7]\", \"key\": \"KY\", \"id\": \"data/US/K" + "Y\"}, \"data/US/PA\": {\"lang\": \"en\", \"zipex\": \"15000,19699\", \"" + "name\": \"Pennsylvania\", \"zip\": \"1[5-8]|19[0-6]\", \"key\": \"PA\"" + ", \"id\": \"data/US/PA\"}, \"data/US/OH\": {\"lang\": \"en\", \"zipe" + "x\": \"43000,45999\", \"name\": \"Ohio\", \"zip\": \"4[3-5]\", \"key\"" + ": \"OH\", \"id\": \"data/US/OH\"}, \"data/US/AS\": {\"lang\": \"en\"," + " \"zipex\": \"96799\", \"name\": \"American Samoa\", \"zip\": \"96799\"" + ", \"key\": \"AS\", \"id\": \"data/US/AS\"}, \"data/US/AA\": {\"lang\"" + ": \"en\", \"zipex\": \"34000,34099\", \"name\": \"Armed Forces (AA)\"," + " \"zip\": \"340\", \"key\": \"AA\", \"id\": \"data/US/AA\"}, \"data/US" + "/GA\": {\"lang\": \"en\", \"zipex\": \"30000,31999:39800,39899:39901\"" + ", \"name\": \"Georgia\", \"zip\": \"3[01]|398|39901\", \"key\": \"GA\"" + ", \"id\": \"data/US/GA\"}, \"data/US/OK\": {\"lang\": \"en\", \"zipex\"" + ": \"73000,74999\", \"name\": \"Oklahoma\", \"zip\": \"7[34]\", \"key\"" + ": \"OK\", \"id\": \"data/US/OK\"}, \"data/US/CO\": {\"lang\": \"en\"," + " \"zipex\": \"80000,81999\", \"name\": \"Colorado\", \"zip\": \"8[01]\"" + ", \"key\": \"CO\", \"id\": \"data/US/CO\"}, \"data/US/AK\": {\"lang\"" + ": \"en\", \"zipex\": \"99500,99999\", \"name\": \"Alaska\", \"zip\": \"" + "99[5-9]\", \"key\": \"AK\", \"id\": \"data/US/AK\"}, \"data/US/WV\": " + "{\"lang\": \"en\", \"zipex\": \"24700,26999\", \"name\": \"West Virgin" + "ia\", \"zip\": \"24[7-9]|2[56]\", \"key\": \"WV\", \"id\": \"data/US/W" + "V\"}, \"data/US/AL\": {\"lang\": \"en\", \"zipex\": \"35000,36999\", \"" + "name\": \"Alabama\", \"zip\": \"3[56]\", \"key\": \"AL\", \"id\": \"d" + "ata/US/AL\"}, \"data/US/GU\": {\"lang\": \"en\", \"zipex\": \"96910,96" + "932\", \"name\": \"Guam\", \"zip\": \"969([1-2]\\\\d|3[12])\", \"key\":" + " \"GU\", \"id\": \"data/US/GU\"}, \"data/US/AR\": {\"lang\": \"en\", \"" + "zipex\": \"71600,72999\", \"name\": \"Arkansas\", \"zip\": \"71[6-9]|" + "72\", \"key\": \"AR\", \"id\": \"data/US/AR\"}, \"data/US/AP\": {\"lan" + "g\": \"en\", \"zipex\": \"96200,96699\", \"name\": \"Armed Forces (AP" + ")\", \"zip\": \"96[2-6]\", \"key\": \"AP\", \"id\": \"data/US/AP\"}, \"" + "data/US/AZ\": {\"lang\": \"en\", \"zipex\": \"85000,86999\", \"name\"" + ": \"Arizona\", \"zip\": \"8[56]\", \"key\": \"AZ\", \"id\": \"data/US/" + "AZ\"}, \"data/US/VI\": {\"lang\": \"en\", \"zipex\": \"00800,00899\"," + " \"name\": \"Virgin Islands\", \"zip\": \"008\", \"key\": \"VI\", \"i" + "d\": \"data/US/VI\"}, \"data/US/CT\": {\"lang\": \"en\", \"zipex\": \"" + "06000,06999\", \"name\": \"Connecticut\", \"zip\": \"06\", \"key\": \"" + "CT\", \"id\": \"data/US/CT\"}, \"data/US/ME\": {\"lang\": \"en\", \"zi" + "pex\": \"03900,04999\", \"name\": \"Maine\", \"zip\": \"039|04\", \"ke" + "y\": \"ME\", \"id\": \"data/US/ME\"}, \"data/US/MD\": {\"lang\": \"en\"" + ", \"zipex\": \"20600,21999\", \"name\": \"Maryland\", \"zip\": \"20[6" + "-9]|21\", \"key\": \"MD\", \"id\": \"data/US/MD\"}, \"data/US/IN\": {\"" + "lang\": \"en\", \"zipex\": \"46000,47999\", \"name\": \"Indiana\", \"" + "zip\": \"4[67]\", \"key\": \"IN\", \"id\": \"data/US/IN\"}, \"data/US/" + "MA\": {\"lang\": \"en\", \"zipex\": \"01000,02799:05501:05544\", \"nam" + "e\": \"Massachusetts\", \"zip\": \"01|02[0-7]|05501|05544\", \"key\":" + " \"MA\", \"id\": \"data/US/MA\"}, \"data/US/IL\": {\"lang\": \"en\", \"" + "zipex\": \"60000,62999\", \"name\": \"Illinois\", \"zip\": \"6[0-2]\"" + ", \"key\": \"IL\", \"id\": \"data/US/IL\"}, \"data/US/MO\": {\"lang\":" + " \"en\", \"zipex\": \"63000,65999\", \"name\": \"Missouri\", \"zip\":" + " \"6[3-5]\", \"key\": \"MO\", \"id\": \"data/US/MO\"}, \"data/US/MN\":" + " {\"lang\": \"en\", \"zipex\": \"55000,56799\", \"name\": \"Minnesota\"" + ", \"zip\": \"55|56[0-7]\", \"key\": \"MN\", \"id\": \"data/US/MN\"}," + " \"data/US/IA\": {\"lang\": \"en\", \"zipex\": \"50000,52999\", \"nam" + "e\": \"Iowa\", \"zip\": \"5[0-2]\", \"key\": \"IA\", \"id\": \"data/US" + "/IA\"}, \"data/US/TN\": {\"lang\": \"en\", \"zipex\": \"37000,38599\"," + " \"name\": \"Tennessee\", \"zip\": \"37|38[0-5]\", \"key\": \"TN\", \"" + "id\": \"data/US/TN\"}, \"data/US/WY\": {\"lang\": \"en\", \"zipex\": \"" + "82000,83199:83414\", \"name\": \"Wyoming\", \"zip\": \"82|83[01]|8341" + "4\", \"key\": \"WY\", \"id\": \"data/US/WY\"}, \"data/US/KS\": {\"lan" + "g\": \"en\", \"zipex\": \"66000,67999\", \"name\": \"Kansas\", \"zip\"" + ": \"6[67]\", \"key\": \"KS\", \"id\": \"data/US/KS\"}, \"data/US/MI\":" + " {\"lang\": \"en\", \"zipex\": \"48000,49999\", \"name\": \"Michigan\"" + ", \"zip\": \"4[89]\", \"key\": \"MI\", \"id\": \"data/US/MI\"}, \"data" + "/US/ID\": {\"lang\": \"en\", \"zipex\": \"83200,83999\", \"name\": \"I" + "daho\", \"zip\": \"83[2-9]\", \"key\": \"ID\", \"id\": \"data/US/ID\"}" + ", \"data/US/MT\": {\"lang\": \"en\", \"zipex\": \"59000,59999\", \"nam" + "e\": \"Montana\", \"zip\": \"59\", \"key\": \"MT\", \"id\": \"data/US/" + "MT\"}, \"data/US/MS\": {\"lang\": \"en\", \"zipex\": \"38600,39799\"," + " \"name\": \"Mississippi\", \"zip\": \"38[6-9]|39[0-7]\", \"key\": \"M" + "S\", \"id\": \"data/US/MS\"}, \"data/US/MP\": {\"lang\": \"en\", \"zip" + "ex\": \"96950,96952\", \"name\": \"Northern Mariana Islands\", \"zip\"" + ": \"9695[0-2]\", \"key\": \"MP\", \"id\": \"data/US/MP\"}, \"data/US/P" + "W\": {\"lang\": \"en\", \"zipex\": \"96940\", \"name\": \"Palau\", \"z" + "ip\": \"969(39|40)\", \"key\": \"PW\", \"id\": \"data/US/PW\"}, \"data" + "/US/SC\": {\"lang\": \"en\", \"zipex\": \"29000,29999\", \"name\": \"S" + "outh Carolina\", \"zip\": \"29\", \"key\": \"SC\", \"id\": \"data/US/S" + "C\"}, \"data/US/MH\": {\"lang\": \"en\", \"zipex\": \"96960,96979\", \"" + "name\": \"Marshall Islands\", \"zip\": \"969[67]\", \"key\": \"MH\"," + " \"id\": \"data/US/MH\"}, \"data/US/WI\": {\"lang\": \"en\", \"zipex\"" + ": \"53000,54999\", \"name\": \"Wisconsin\", \"zip\": \"5[34]\", \"key\"" + ": \"WI\", \"id\": \"data/US/WI\"}, \"data/US/SD\": {\"lang\": \"en\"," + " \"zipex\": \"57000,57999\", \"name\": \"South Dakota\", \"zip\": \"5" + "7\", \"key\": \"SD\", \"id\": \"data/US/SD\"}, \"data/US/OR\": {\"lan" + "g\": \"en\", \"zipex\": \"97000,97999\", \"name\": \"Oregon\", \"zip\"" + ": \"97\", \"key\": \"OR\", \"id\": \"data/US/OR\"}, \"data/US/UT\": {\"" + "lang\": \"en\", \"zipex\": \"84000,84999\", \"name\": \"Utah\", \"zi" + "p\": \"84\", \"key\": \"UT\", \"id\": \"data/US/UT\"}, \"data/US/VA\":" + " {\"lang\": \"en\", \"zipex\": \"20100,20199:22000,24699\", \"name\":" + " \"Virginia\", \"zip\": \"201|2[23]|24[0-6]\", \"key\": \"VA\", \"id\"" + ": \"data/US/VA\"}, \"data/US/AE\": {\"lang\": \"en\", \"zipex\": \"090" + "00,09999\", \"name\": \"Armed Forces (AE)\", \"zip\": \"09\", \"key\":" + " \"AE\", \"id\": \"data/US/AE\"}, \"data/US/FL\": {\"lang\": \"en\", \"" + "zipex\": \"32000,33999:34100,34999\", \"name\": \"Florida\", \"zip\":" + " \"3[23]|34[1-9]\", \"key\": \"FL\", \"id\": \"data/US/FL\"}, \"data/U" + "S/FM\": {\"lang\": \"en\", \"zipex\": \"96941,96944\", \"name\": \"Mic" + "ronesia\", \"zip\": \"9694[1-4]\", \"key\": \"FM\", \"id\": \"data/US/" + "FM\"}, \"data/US/DE\": {\"lang\": \"en\", \"zipex\": \"19700,19999\"," + " \"name\": \"Delaware\", \"zip\": \"19[7-9]\", \"key\": \"DE\", \"id\"" + ": \"data/US/DE\"}, \"data/US/CA\": {\"lang\": \"en\", \"zipex\": \"900" + "00,96199\", \"name\": \"California\", \"zip\": \"9[0-5]|96[01]\", \"ke" + "y\": \"CA\", \"id\": \"data/US/CA\"}, \"data/US\": {\"lang\": \"en\"," + " \"upper\": \"CS\", \"sub_zipexs\": \"35000,36999~99500,99999~96799~85" + "000,86999~71600,72999~34000,34099~09000,09999~96200,96699~90000,96199~" + "80000,81999~06000,06999~19700,19999~20000,20099:20200,20599:56900,5699" + "9~32000,33999:34100,34999~30000,31999:39800,39899:39901~96910,96932~96" + "700,96798:96800,96899~83200,83999~60000,62999~46000,47999~50000,52999~" + "66000,67999~40000,42799~70000,71599~03900,04999~96960,96979~20600,2199" + "9~01000,02799:05501:05544~48000,49999~96941,96944~55000,56799~38600,39" + "799~63000,65999~59000,59999~68000,69999~88900,89999~03000,03899~07000," + "08999~87000,88499~10000,14999:06390:00501:00544~27000,28999~58000,5899" + "9~96950,96952~43000,45999~73000,74999~97000,97999~96940~15000,19699~00" + "600,00799:00900,00999~02800,02999~29000,29999~57000,57999~37000,38599~" + "75000,79999:88500,88599:73301:73344~84000,84999~05000,05999~00800,0089" + "9~20100,20199:22000,24699~98000,99499~24700,26999~53000,54999~82000,83" + "199:83414\", \"zipex\": \"95014,22162-1010\", \"name\": \"UNITED STATE" + "S\", \"zip\": \"\\\\d{5}([ \\\\-]\\\\d{4})?\", \"zip_name_type\": \"zi" + "p\", \"fmt\": \"%N%n%O%n%A%n%C %S %Z\", \"state_name_type\": \"state\"" + ", \"languages\": \"en\", \"sub_keys\": \"AL~AK~AS~AZ~AR~AA~AE~AP~CA~CO" + "~CT~DE~DC~FL~GA~GU~HI~ID~IL~IN~IA~KS~KY~LA~ME~MH~MD~MA~MI~FM~MN~MS~MO~" + "MT~NE~NV~NH~NJ~NM~NY~NC~ND~MP~OH~OK~OR~PW~PA~PR~RI~SC~SD~TN~TX~UT~VT~V" + "I~VA~WA~WV~WI~WY\"," + " \"key\": \"US\", \"require\": \"ACSZ\", \"posturl\": \"https://tools." + "usps.com/go/ZipLookupAction!input.action\", \"id\": \"dat" + "a/US\", \"sub_names\": \"Alabama~Alaska~American Samoa~Arizona~Arkansa" + "s~Armed Forces (AA)~Armed Forces (AE)~Armed Forces (AP)~California~Col" + "orado~Connecticut~Delaware~District of Columbia~Florida~Georgia~Guam~H" + "awaii~Idaho~Illinois~Indiana~Iowa~Kansas~Kentucky~Louisiana~Maine~Mars" + "hall Islands~Maryland~Massachusetts~Michigan~Micronesia~Minnesota~Miss" + "issippi~Missouri~Montana~Nebraska~Nevada~New Hampshire~New Jersey~New " + "Mexico~New York~North Carolina~North Dakota~Northern Mariana Islands~O" + "hio~Oklahoma~Oregon~Palau~Pennsylvania~Puerto Rico~Rhode Island~South " + "Carolina~South Dakota~Tennessee~Texas~Utah~Vermont~Virgin Islands~Virg" + "inia~Washington~West Virginia~Wisconsin~Wyoming\", \"sub_zips\": \"3[5" + "6]~99[5-9]~96799~8[56]~71[6-9]|72~340~09~96[2-6]~9[0-5]|96[01]~8[01]~0" + "6~19[7-9]~20[02-5]|569~3[23]|34[1-9]~3[01]|398|39901~969([1-2]\\\\d|3[12" + "])~967[0-8]|9679[0-8]|968~83[2-9]~6[0-2]~4[67]~5[0-2]~6[67]~4[01]|42[0" + "-7]~70|71[0-5]~039|04~969[67]~20[6-9]|21~01|02[0-7]|05501|05544~4[89]~" + "9694[1-4]~55|56[0-7]~38[6-9]|39[0-7]~6[3-5]~59~6[89]~889|89~03[0-8]~0[" + "78]~87|88[0-4]~1[0-4]|06390|00501|00544~2[78]~58~9695[0-2]~4[3-5]~7[34" + "]~97~969(39|40)~1[5-8]|19[0-6]~00[679]~02[89]~29~57~37|38[0-5]~7[5-9]|" + "885|73301|73344~84~05~008~201|2[23]|24[0-6]~98|99[0-4]~24[7-9]|2[56]~5" + "[34]~82|83[01]|83414\"}, \"data/US/TX\": {\"lang\": \"en\", \"zipex\":" + " \"75000,79999:88500,88599:73301:73344\", \"name\": \"Texas\", \"zip\"" + ": \"7[5-9]|885|73301|73344\", \"key\": \"TX\", \"id\": \"data/US/TX\"}" + ", \"data/US/WA\": {\"lang\": \"en\", \"zipex\": \"98000,99499\", \"nam" + "e\": \"Washington\", \"zip\": \"98|99[0-4]\", \"key\": \"WA\", \"id\":" + " \"data/US/WA\"}, \"data/US/DC\": {\"lang\": \"en\", \"zipex\": \"2000" + "0,20099:20200,20599:56900,56999\", \"name\": \"District of Columbia\"," + " \"zip\": \"20[02-5]|569\", \"key\": \"DC\", \"id\": \"data/US/DC\"}," + " \"data/US/HI\": {\"lang\": \"en\", \"zipex\": \"96700,96798:96800,968" + "99\", \"name\": \"Hawaii\", \"zip\": \"967[0-8]|9679[0-8]|968\", \"key" + "\": \"HI\", \"id\": \"data/US/HI\"}}"); + return true; +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/fallback_data_store.h b/chromium/third_party/libaddressinput/chromium/fallback_data_store.h new file mode 100644 index 00000000000..fd8d680576c --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/fallback_data_store.h @@ -0,0 +1,22 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_FALLBACK_DATA_STORE_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_FALLBACK_DATA_STORE_H_ + +#include <string> + +namespace autofill { + +class FallbackDataStore { + public: + // Gets stale, but valid static data for |key|. Should only be used as a last + // resort after attempts to check the local cache or the webserver have + // failed. + static bool Get(const std::string& key, std::string* data); +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_FALLBACK_DATA_STORE_H_ diff --git a/chromium/third_party/libaddressinput/chromium/fallback_data_store_unittest.cc b/chromium/third_party/libaddressinput/chromium/fallback_data_store_unittest.cc new file mode 100644 index 00000000000..558a0a6896d --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/fallback_data_store_unittest.cc @@ -0,0 +1,50 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/fallback_data_store.h" + +#include <cstddef> +#include <ctime> +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libaddressinput/src/cpp/src/util/json.h" +#include "third_party/libaddressinput/src/cpp/src/validating_util.h" + +namespace autofill { + +using i18n::addressinput::Json; +using i18n::addressinput::ValidatingUtil; + +TEST(FallbackDataStore, Parsability) { + std::string data; + ASSERT_TRUE(FallbackDataStore::Get("data/US", &data)); + + // Should be stale. + EXPECT_FALSE(ValidatingUtil::UnwrapTimestamp(&data, time(NULL))); + + // Should be uncorrupted. + EXPECT_TRUE(ValidatingUtil::UnwrapChecksum(&data)); + + // Should be valid JSON. + Json json; + ASSERT_TRUE(json.ParseObject(data)); + + // Should not have a string for "data/US", because "data/US" is a dictionary. + std::string value; + EXPECT_FALSE(json.GetStringValueForKey("data/US", &value)); + + // Should have a dictionary with "data/US" identifier. + const std::vector<const Json*>& sub_dicts = json.GetSubDictionaries(); + bool key_found = false; + for (std::vector<const Json*>::const_iterator it = sub_dicts.begin(); + it != sub_dicts.end(); ++it) { + const Json* sub_dict = *it; + EXPECT_TRUE(sub_dict->GetStringValueForKey("id", &value)); + key_found |= value == "data/US"; + } + EXPECT_TRUE(key_found); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/input_suggester.cc b/chromium/third_party/libaddressinput/chromium/input_suggester.cc new file mode 100644 index 00000000000..9b890f11171 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/input_suggester.cc @@ -0,0 +1,522 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/input_suggester.h" + +#include <cstddef> +#include <set> +#include <utility> + +#include "base/logging.h" +#include "base/macros.h" +#include "third_party/libaddressinput/chromium/trie.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data.h" + +namespace autofill { + +using ::i18n::addressinput::AddressData; +using ::i18n::addressinput::AddressField; +using ::i18n::addressinput::BuildCallback; +using ::i18n::addressinput::FieldProblemMap; +using ::i18n::addressinput::PreloadSupplier; +using ::i18n::addressinput::RegionData; +using ::i18n::addressinput::RegionDataBuilder; + +using ::i18n::addressinput::ADMIN_AREA; +using ::i18n::addressinput::COUNTRY; +using ::i18n::addressinput::DEPENDENT_LOCALITY; +using ::i18n::addressinput::LOCALITY; +using ::i18n::addressinput::POSTAL_CODE; + +using ::i18n::addressinput::INVALID_FORMAT; +using ::i18n::addressinput::MISMATCHING_VALUE; + +namespace { + +// Initial size for the buffer used in the canonicalizer. +static const size_t kInitialBufferSize = 32; + +// A region and its metadata useful for constructing a suggestion. +struct Suggestion { + public: + // Builds a suggestion of |region_to_suggest|. Does not take ownership of + // |region_to_suggest|, which should not be NULL. + Suggestion(const RegionData* region_to_suggest, + AddressField matching_address_field, + bool region_key_matches) + : region_to_suggest(region_to_suggest), + matching_address_field(matching_address_field), + region_key_matches(region_key_matches) { + DCHECK(region_to_suggest); + } + + ~Suggestion() {} + + // The region that should be suggested. For example, if the region is ("CA", + // "California"), then either "CA" or "California" should be suggested. + const RegionData* region_to_suggest; + + // The field in the address for which the suggestion should be made. For + // example, ADMIN_AREA in US means the suggestion should be made for the field + // labeled "State". + AddressField matching_address_field; + + // True if the key of the region matches user input (the name may or may not + // match). "CA" should be suggested for a ("CA", "California") region. + // + // False if only the name of the region matches user input (the key does not + // match). "California" should be suggested for a ("CA", "California") region. + bool region_key_matches; +}; + +// Suggestions for an address. Contains lists of suggestions for administrative +// area, locality, and dependent locality fields of an address. +class AddressSuggestions { + public: + AddressSuggestions() {} + ~AddressSuggestions() {} + + // Marks all regions at |address_field| level as matching user input. + void AllRegionsMatchForField(AddressField address_field) { + all_regions_match_input_.insert(address_field); + } + + // Marks given regions at |address_field| level as matching user input. The + // |regions_match_key| parameter contains the regions that match user input by + // their keys. The |regions_match_name| parameter contains the regions that + // match user input by their names. + // + // The |address_field| parameter should be either ADMIN_AREA, LOCALITY, or + // DEPENDENT_LOCALITY. + bool AddRegions(AddressField address_field, + const std::set<const RegionData*>& regions_match_key, + const std::set<const RegionData*>& regions_match_name) { + DCHECK(address_field >= ADMIN_AREA); + DCHECK(address_field <= DEPENDENT_LOCALITY); + + AddressField parent_address_field = + static_cast<AddressField>(address_field - 1); + + bool all_parents_match = + parent_address_field == COUNTRY || + all_regions_match_input_.find(parent_address_field) != + all_regions_match_input_.end(); + + // Cannot build |address_field| level suggestions if there are no matches in + // |parent_address_field| level regions. + const RegionsMatchInput* parents = NULL; + if (address_field > ADMIN_AREA && !all_parents_match) { + parents = ®ions_match_input_[parent_address_field]; + if (parents->keys.empty() && parents->names.empty()) + return false; + } + + RegionsMatchInput* regions = NULL; + if (address_field < DEPENDENT_LOCALITY) + regions = ®ions_match_input_[address_field]; + + std::vector<Suggestion>* suggestions = &suggestions_[address_field]; + bool added_suggestions = false; + + // Iterate over both |regions_match_key| and |regions_match_name| and build + // Suggestion objects based on the given RegionData objects. Advance either + // one iterator at a time (if they point to different data) or both + // iterators at once (if they point to the same data). + for (std::set<const RegionData*>::const_iterator + key_it = regions_match_key.begin(), + name_it = regions_match_name.begin(); + key_it != regions_match_key.end() || + name_it != regions_match_name.end();) { + const RegionData* key_region = + key_it != regions_match_key.end() ? *key_it : NULL; + const RegionData* name_region = + name_it != regions_match_name.end() ? *name_it : NULL; + + // Regions that do not have a parent that also matches input will not + // become suggestions. + bool key_region_has_parent = + all_parents_match || + (parents && !parents->keys.empty() && key_region && + parents->keys.find(&key_region->parent()) != parents->keys.end()); + bool name_region_has_parent = + all_parents_match || + (parents && !parents->names.empty() && name_region && + parents->names.find(&name_region->parent()) != parents->names.end()); + + if (name_region && (!key_region || name_region < key_region)) { + if (name_region_has_parent) { + suggestions->push_back(Suggestion(name_region, address_field, false)); + added_suggestions = true; + if (regions) + regions->names.insert(name_region); + } + + ++name_it; + } else if (key_region && (!name_region || key_region < name_region)) { + if (key_region_has_parent) { + suggestions->push_back(Suggestion(key_region, address_field, true)); + added_suggestions = true; + if (regions) + regions->keys.insert(key_region); + } + + ++key_it; + } else { + if (key_region_has_parent) { + suggestions->push_back(Suggestion(key_region, address_field, true)); + added_suggestions = true; + if (regions) { + regions->keys.insert(key_region); + regions->names.insert(name_region); + } + } + + ++key_it; + ++name_it; + } + } + + return added_suggestions; + } + + // Swaps the suggestions for the smallest sub-region into |suggestions|. + // |this| is not usable after this call due to using the swap() operation. + // + // The |suggestions| parameter should not be NULL. + void SwapSmallestSubRegionSuggestions(std::vector<Suggestion>* suggestions) { + DCHECK(suggestions); + for (int i = DEPENDENT_LOCALITY; i >= ADMIN_AREA; --i) { + std::vector<Suggestion>* result = + &suggestions_[static_cast<AddressField>(i)]; + if (!result->empty()) { + suggestions->swap(*result); + return; + } + } + } + + private: + // The sets of non-owned regions used for looking up regions that match user + // input by keys and names. + struct RegionsMatchInput { + std::set<const RegionData*> keys; + std::set<const RegionData*> names; + }; + + // The regions that match user input at ADMIN_AREA and LOCALITY levels. + std::map<AddressField, RegionsMatchInput> regions_match_input_; + + // The set of fields for which all regions match user input. Used to avoid + // storing a long list in |regions_match_input_| and later looking it up + // there. + std::set<AddressField> all_regions_match_input_; + + // Suggestions at ADMIN_AREA, LOCALITY, and DEPENDENT_LOCALITY levels. + std::map<AddressField, std::vector<Suggestion> > suggestions_; + + DISALLOW_COPY_AND_ASSIGN(AddressSuggestions); +}; + +} // namespace + +InputSuggester::StringCanonicalizer::StringCanonicalizer() + : buffer_(kInitialBufferSize, 0) { + UErrorCode error_code = U_ZERO_ERROR; + collator_.reset( + icu::Collator::createInstance(icu::Locale::getRoot(), error_code)); + DCHECK(U_SUCCESS(error_code)); + collator_->setStrength(icu::Collator::PRIMARY); +} + +InputSuggester::StringCanonicalizer::~StringCanonicalizer() {} + +const std::vector<uint8_t>& InputSuggester::StringCanonicalizer::Canonicalize( + const std::string& original) const { + DCHECK(!original.empty()); + + icu::UnicodeString icu_str(original.c_str(), + static_cast<int32_t>(original.length())); + int32_t sort_key_size = + collator_->getSortKey(icu_str, &buffer_[0], buffer_size()); + DCHECK_LT(0, sort_key_size); + + if (sort_key_size > buffer_size()) { + buffer_.resize(sort_key_size * 2, 0); + sort_key_size = collator_->getSortKey(icu_str, &buffer_[0], buffer_size()); + DCHECK_LT(0, sort_key_size); + DCHECK_GT(buffer_size(), sort_key_size); + } + + return buffer_; +} + +int32_t InputSuggester::StringCanonicalizer::buffer_size() const { + return static_cast<int32_t>(buffer_.size()); +} + +// All sub-regions of a COUNTRY level region, organized into tries for lookup by +// region name or key. +class InputSuggester::SubRegionData { + public: + SubRegionData() + : initialized_(false), + smallest_region_size_(COUNTRY), + canonicalizer_(NULL) {} + + ~SubRegionData() {} + + bool is_initialized() const { return initialized_; } + + // Adds the sub-regions of |country_region| into tries. Uses + // |shared_canonicalizer| for case and diacritic insensitive lookup of the + // sub-regions. Should be called at most once. + void Initialize(const RegionData& country_region, + const StringCanonicalizer& shared_canonicalizer) { + DCHECK(!initialized_); + DCHECK(!country_region.has_parent()); + + initialized_ = true; + canonicalizer_ = &shared_canonicalizer; + + if (!country_region.sub_regions().empty()) + AddSubRegionsOf(country_region, COUNTRY); + } + + // Adds the suggestions for |user_input| into |suggestions| when user is + // typing in |focused_field|. + void BuildSuggestions(const AddressData& user_input, + AddressField focused_field, + std::vector<Suggestion>* suggestions) { + DCHECK(initialized_); + + // Do not suggest anything if there's no suggestion data for the focused + // field. + if (focused_field != POSTAL_CODE && smallest_region_size_ < focused_field) + return; + + // Non-owned regions that match a field value by region key. + std::set<const RegionData*> regions_match_key; + + // Non-owned regions that match a field value by region name. + std::set<const RegionData*> regions_match_name; + + AddressSuggestions address_suggestions; + for (int i = ADMIN_AREA; i <= focused_field && i <= DEPENDENT_LOCALITY; + ++i) { + AddressField address_field = static_cast<AddressField>(i); + AddressField parent_address_field = static_cast<AddressField>(i - 1); + + const std::string& field_value = user_input.GetFieldValue(address_field); + const std::string& parent_field_value = + user_input.GetFieldValue(parent_address_field); + + if (field_value.empty() && + (address_field == ADMIN_AREA || parent_field_value.empty())) { + address_suggestions.AllRegionsMatchForField(address_field); + continue; + } + + if (field_value.empty()) { + DCHECK_NE(address_field, focused_field); + continue; + } + + regions_match_key.clear(); + regions_match_name.clear(); + + const FieldTries& field_tries = field_tries_[address_field]; + + const std::vector<uint8_t>& canonicalized_value = + canonicalizer_->Canonicalize(field_value); + + field_tries.keys.FindDataForKeyPrefix(canonicalized_value, + ®ions_match_key); + field_tries.names.FindDataForKeyPrefix(canonicalized_value, + ®ions_match_name); + + bool added_suggestions = address_suggestions.AddRegions( + address_field, regions_match_key, regions_match_name); + + // Do not suggest anything if the focused field does not have suggestions. + if (address_field == focused_field && !added_suggestions) + return; + } + + address_suggestions.SwapSmallestSubRegionSuggestions(suggestions); + } + + private: + // The tries to lookup regions for a specific field by keys and names. For + // example, the FieldTries for ADMIN_AREA in US will have keys for "AL", "AK", + // "AS", etc and names for "Alabama", "Alaska", "American Samoa", etc. The + // struct is uncopyable due to Trie objects being uncopyable. + struct FieldTries { + Trie<const RegionData*> keys; + Trie<const RegionData*> names; + }; + + // Adds the sub-regions of |parent_region| into tries. + void AddSubRegionsOf(const RegionData& parent_region, + AddressField parent_field) { + DCHECK(!parent_region.sub_regions().empty()); + + AddressField address_field = static_cast<AddressField>(parent_field + 1); + DCHECK(address_field >= ADMIN_AREA); + DCHECK(address_field <= DEPENDENT_LOCALITY); + + FieldTries* field_tries = &field_tries_[address_field]; + for (std::vector<const RegionData*>::const_iterator it = + parent_region.sub_regions().begin(); + it != parent_region.sub_regions().end(); + ++it) { + const RegionData* region = *it; + DCHECK(region); + DCHECK(!region->key().empty()); + DCHECK(!region->name().empty()); + + field_tries->keys.AddDataForKey( + canonicalizer_->Canonicalize(region->key()), region); + + field_tries->names.AddDataForKey( + canonicalizer_->Canonicalize(region->name()), region); + + if (smallest_region_size_ < address_field) + smallest_region_size_ = address_field; + + if (!region->sub_regions().empty()) + AddSubRegionsOf(*region, address_field); + } + } + + // True after Initialize() has been called. + bool initialized_; + + // The tries to lookup regions for ADMIN_AREA, LOCALITY, and + // DEPENDENT_LOCALITY. + std::map<AddressField, FieldTries> field_tries_; + + // The smallest size of a sub-region that has data. For example, this is + // ADMIN_AREA in US, but DEPENDENT_LOCALITY in CN. + AddressField smallest_region_size_; + + // A shared instance of string canonicalizer for case and diacritic comparison + // of region keys and names. + const StringCanonicalizer* canonicalizer_; +}; + +InputSuggester::InputSuggester(PreloadSupplier* supplier) + : region_data_builder_(supplier), + input_helper_(supplier), + validator_(supplier), + validated_(BuildCallback(this, &InputSuggester::Validated)) {} + +InputSuggester::~InputSuggester() {} + +void InputSuggester::GetSuggestions(const AddressData& user_input, + AddressField focused_field, + size_t suggestions_limit, + std::vector<AddressData>* suggestions) { + DCHECK(suggestions); + DCHECK(focused_field == POSTAL_CODE || + (focused_field >= ADMIN_AREA && focused_field <= DEPENDENT_LOCALITY)); + + AddressData address_copy = user_input; + + // Do not suggest anything if the user input is empty. + if (address_copy.IsFieldEmpty(focused_field)) + return; + + if (focused_field == POSTAL_CODE) { + // Do not suggest anything if the user is typing an invalid postal code. + FieldProblemMap problems; + FieldProblemMap filter; + filter.insert(std::make_pair(POSTAL_CODE, INVALID_FORMAT)); + validator_.Validate(address_copy, + true, // Allow postal office boxes. + false, // Do not require recipient name. + &filter, + &problems, + *validated_); + if (!problems.empty()) + return; + + // Fill in the sub-regions based on the postal code. + input_helper_.FillAddress(&address_copy); + } + + // Lazily initialize the mapping from COUNTRY level regions to all of their + // sub-regions with metadata for generating suggestions. + std::string unused_best_language; + const RegionData& region_data = + region_data_builder_.Build(address_copy.region_code, + address_copy.language_code, + &unused_best_language); + SubRegionData* sub_region_data = &sub_regions_[®ion_data]; + if (!sub_region_data->is_initialized()) + sub_region_data->Initialize(region_data, canonicalizer_); + + // Build the list of regions that match |address_copy| when the user is typing + // in the |focused_field|. + std::vector<Suggestion> suggested_regions; + sub_region_data->BuildSuggestions( + address_copy, focused_field, &suggested_regions); + + FieldProblemMap problems; + FieldProblemMap filter; + filter.insert(std::make_pair(POSTAL_CODE, MISMATCHING_VALUE)); + + // Generate suggestions based on the regions. + for (std::vector<Suggestion>::const_iterator suggested_region_it = + suggested_regions.begin(); + suggested_region_it != suggested_regions.end(); + ++suggested_region_it) { + AddressData address; + address.region_code = address_copy.region_code; + address.postal_code = address_copy.postal_code; + + // Traverse the tree of regions from the smallest |region_to_suggest| to the + // country-wide "root" of the tree. Use the region names or keys found at + // each of the levels of the tree to build the |address| to suggest. + AddressField address_field = suggested_region_it->matching_address_field; + for (const RegionData* region = suggested_region_it->region_to_suggest; + region->has_parent(); + region = ®ion->parent()) { + address.SetFieldValue(address_field, + suggested_region_it->region_key_matches + ? region->key() + : region->name()); + address_field = static_cast<AddressField>(address_field - 1); + } + + // Do not suggest an address with a mismatching postal code. + problems.clear(); + validator_.Validate(address, + true, // Allow postal office boxes. + false, // Do not require recipient name. + &filter, + &problems, + *validated_); + if (!problems.empty()) + continue; + + // Do not add more suggestions than |suggestions_limit|. + if (suggestions->size() >= suggestions_limit) { + suggestions->clear(); + return; + } + + suggestions->push_back(address); + } +} + +void InputSuggester::Validated(bool success, + const AddressData&, + const FieldProblemMap&) { + DCHECK(success); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/input_suggester.h b/chromium/third_party/libaddressinput/chromium/input_suggester.h new file mode 100644 index 00000000000..9d5fbcd4fcd --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/input_suggester.h @@ -0,0 +1,135 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_INPUT_SUGGESTER_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_INPUT_SUGGESTER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <map> +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/icu/source/i18n/unicode/coll.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_input_helper.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h" + +namespace i18n { +namespace addressinput { +class PreloadSupplier; +class RegionData; +struct AddressData; +} +} + +namespace autofill { + +// Suggests address completions for a partially entered address from the user. +class InputSuggester { + public: + // Does not take ownership of |supplier|, which should not be NULL. + explicit InputSuggester(::i18n::addressinput::PreloadSupplier* supplier); + ~InputSuggester(); + + // Fills in |suggestions| for the partially typed in |user_input|, assuming + // the user is typing in the |focused_field|. If the number of |suggestions| + // is over the |suggestion_limit|, then returns no |suggestions| at all. + // + // Sample user input 1: + // country code = "US" + // postal code = "90066" + // focused field = POSTAL_CODE + // suggestions limit = 1 + // Suggestion: + // [{administrative_area: "CA"}] + // + // Sample user input 2: + // country code = "CN" + // dependent locality = "Zongyang" + // focused field = DEPENDENT_LOCALITY + // suggestions limit = 10 + // Suggestion: + // [{dependent_locality: "Zongyang Xian", + // locality: "Anqing Shi", + // administrative_area: "Anhui Sheng"}] + // + // Builds the index for generating suggestions lazily. + // + // The |suggestions| parameter should not be NULL. The |focused_field| + // parameter should be either POSTAL_CODE or between ADMIN_AREA and + // DEPENDENT_LOCALITY inclusively. + void GetSuggestions( + const ::i18n::addressinput::AddressData& user_input, + ::i18n::addressinput::AddressField focused_field, + size_t suggestion_limit, + std::vector< ::i18n::addressinput::AddressData>* suggestions); + + private: + class SubRegionData; + + // Canonicalizes strings for case and diacritic insensitive comparison. + class StringCanonicalizer { + public: + // Initializes the canonicalizer. This is slow, so avoid calling it more + // often than necessary. + StringCanonicalizer(); + ~StringCanonicalizer(); + + // Returns a 0-terminated canonical version of the string that can be used + // for comparing strings regardless of diacritics and capitalization. + // Canonicalize("Texas") == Canonicalize("T\u00E9xas"); + // Canonicalize("Texas") == Canonicalize("teXas"); + // Canonicalize("Texas") != Canonicalize("California"); + // + // The output is not human-readable. + // Canonicalize("Texas") != "Texas"; + // + // The |original| parameter should not be empty. + const std::vector<uint8_t>& Canonicalize(const std::string& original) const; + + private: + int32_t buffer_size() const; + + mutable std::vector<uint8_t> buffer_; + scoped_ptr<icu::Collator> collator_; + + DISALLOW_COPY_AND_ASSIGN(StringCanonicalizer); + }; + + // The method to be invoked by |validated_| callback. + void Validated(bool success, + const ::i18n::addressinput::AddressData&, + const ::i18n::addressinput::FieldProblemMap&); + + // Data source for region data. + ::i18n::addressinput::RegionDataBuilder region_data_builder_; + + // Suggests sub-regions based on postal code. + const ::i18n::addressinput::AddressInputHelper input_helper_; + + // Verifies that suggested sub-regions match the postal code. + ::i18n::addressinput::AddressValidator validator_; + + // The callback for |validator_| to invoke when validation finishes. + const scoped_ptr<const ::i18n::addressinput::AddressValidator::Callback> + validated_; + + // A mapping from a COUNTRY level region to a collection of all of its + // sub-regions along with metadata used to construct suggestions. + std::map<const ::i18n::addressinput::RegionData*, SubRegionData> sub_regions_; + + // Canonicalizes strings for case and diacritic insensitive search of + // sub-region names. + StringCanonicalizer canonicalizer_; + + DISALLOW_COPY_AND_ASSIGN(InputSuggester); +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_INPUT_SUGGESTER_H_ diff --git a/chromium/third_party/libaddressinput/chromium/json.cc b/chromium/third_party/libaddressinput/chromium/json.cc new file mode 100644 index 00000000000..89c65bc1704 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/json.cc @@ -0,0 +1,109 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/src/cpp/src/util/json.h" + +#include <map> + +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/stl_util.h" +#include "base/values.h" + +namespace i18n { +namespace addressinput { + +namespace { + +// Returns |json| parsed into a JSON dictionary. Sets |parser_error| to true if +// parsing failed. +::scoped_ptr<const base::DictionaryValue> Parse(const std::string& json, + bool* parser_error) { + DCHECK(parser_error); + ::scoped_ptr<const base::DictionaryValue> result; + + // |json| is converted to a |c_str()| here because rapidjson and other parts + // of the standalone library use char* rather than std::string. + ::scoped_ptr<const base::Value> parsed(base::JSONReader::Read(json.c_str())); + *parser_error = !parsed || !parsed->IsType(base::Value::TYPE_DICTIONARY); + + if (*parser_error) + result.reset(new base::DictionaryValue); + else + result.reset(static_cast<const base::DictionaryValue*>(parsed.release())); + + return result; +} + +} // namespace + +// Implementation of JSON parser for libaddressinput using JSON parser in +// Chrome. +class Json::JsonImpl { + public: + explicit JsonImpl(const std::string& json) + : owned_(Parse(json, &parser_error_)), + dict_(*owned_) {} + + ~JsonImpl() { STLDeleteElements(&sub_dicts_); } + + bool parser_error() const { return parser_error_; } + + const std::vector<const Json*>& GetSubDictionaries() { + if (sub_dicts_.empty()) { + for (base::DictionaryValue::Iterator it(dict_); !it.IsAtEnd(); + it.Advance()) { + if (it.value().IsType(base::Value::TYPE_DICTIONARY)) { + const base::DictionaryValue* sub_dict = NULL; + it.value().GetAsDictionary(&sub_dict); + sub_dicts_.push_back(new Json(new JsonImpl(*sub_dict))); + } + } + } + return sub_dicts_; + } + + bool GetStringValueForKey(const std::string& key, std::string* value) const { + return dict_.GetStringWithoutPathExpansion(key, value); + } + + private: + explicit JsonImpl(const base::DictionaryValue& dict) + : parser_error_(false), dict_(dict) {} + + const ::scoped_ptr<const base::DictionaryValue> owned_; + bool parser_error_; + const base::DictionaryValue& dict_; + std::vector<const Json*> sub_dicts_; + + DISALLOW_COPY_AND_ASSIGN(JsonImpl); +}; + +Json::Json() {} + +Json::~Json() {} + +bool Json::ParseObject(const std::string& json) { + DCHECK(!impl_); + impl_.reset(new JsonImpl(json)); + if (impl_->parser_error()) + impl_.reset(); + return !!impl_; +} + +const std::vector<const Json*>& Json::GetSubDictionaries() const { + return impl_->GetSubDictionaries(); +} + +bool Json::GetStringValueForKey(const std::string& key, + std::string* value) const { + return impl_->GetStringValueForKey(key, value); +} + +Json::Json(JsonImpl* impl) : impl_(impl) {} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/chromium/override/basictypes_override.h b/chromium/third_party/libaddressinput/chromium/override/basictypes_override.h new file mode 100644 index 00000000000..651f506c790 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/override/basictypes_override.h @@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_BASICTYPES_OVERRIDE_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_BASICTYPES_OVERRIDE_H_ + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +#include "base/macros.h" + +// There is no more base/basictypes.h in Chromium. Even though libaddressinput +// has its own "basictypes.h" that defines a whole host of custom integers of +// specific lengths, the only one actually used is |uint32| in util/md5.cc. So +// here you go: + +typedef uint32_t uint32; + +// TODO: Switch libaddressinput to |uint32_t|. + +// Also, Chromium uses the C++11 |static_assert|, so here's a definition for the +// old COMPILE_ASSERT: + +#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) + +// TODO: Switch libaddressinput to |static_assert|. + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_BASICTYPES_OVERRIDE_H_ diff --git a/chromium/third_party/libaddressinput/chromium/storage_test_runner.cc b/chromium/third_party/libaddressinput/chromium/storage_test_runner.cc new file mode 100644 index 00000000000..453f0f29289 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/storage_test_runner.cc @@ -0,0 +1,88 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/storage_test_runner.h" + +#include <cassert> +#include <cstddef> +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h" + +namespace autofill { + +using ::i18n::addressinput::Storage; + +StorageTestRunner::StorageTestRunner(Storage* storage) + : storage_(storage), + success_(false), + key_(), + data_() {} + +StorageTestRunner::~StorageTestRunner() {} + +void StorageTestRunner::RunAllTests() { + EXPECT_NO_FATAL_FAILURE(GetWithoutPutReturnsEmptyData()); + EXPECT_NO_FATAL_FAILURE(GetReturnsWhatWasPut()); + EXPECT_NO_FATAL_FAILURE(SecondPutOverwritesData()); +} + +void StorageTestRunner::ClearValues() { + success_ = false; + key_.clear(); + data_.clear(); +} + +scoped_ptr<Storage::Callback> StorageTestRunner::BuildCallback() { + return scoped_ptr<Storage::Callback>(::i18n::addressinput::BuildCallback( + this, &StorageTestRunner::OnDataReady)); +} + +void StorageTestRunner::OnDataReady(bool success, + const std::string& key, + std::string* data) { + assert(!success || data != NULL); + success_ = success; + key_ = key; + if (data != NULL) { + data_ = *data; + delete data; + } +} + +void StorageTestRunner::GetWithoutPutReturnsEmptyData() { + ClearValues(); + scoped_ptr<Storage::Callback> callback(BuildCallback()); + storage_->Get("key", *callback); + + EXPECT_FALSE(success_); + EXPECT_EQ("key", key_); + EXPECT_TRUE(data_.empty()); +} + +void StorageTestRunner::GetReturnsWhatWasPut() { + ClearValues(); + storage_->Put("key", new std::string("value")); + scoped_ptr<Storage::Callback> callback(BuildCallback()); + storage_->Get("key", *callback); + + EXPECT_TRUE(success_); + EXPECT_EQ("key", key_); + EXPECT_EQ("value", data_); +} + +void StorageTestRunner::SecondPutOverwritesData() { + ClearValues(); + storage_->Put("key", new std::string("bad-value")); + storage_->Put("key", new std::string("good-value")); + scoped_ptr<Storage::Callback> callback(BuildCallback()); + storage_->Get("key", *callback); + + EXPECT_TRUE(success_); + EXPECT_EQ("key", key_); + EXPECT_EQ("good-value", data_); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/storage_test_runner.h b/chromium/third_party/libaddressinput/chromium/storage_test_runner.h new file mode 100644 index 00000000000..afbb8858edc --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/storage_test_runner.h @@ -0,0 +1,47 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_STORAGE_TEST_RUNNER_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_STORAGE_TEST_RUNNER_H_ + +#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h" + +#include <string> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace autofill { + +// A test sutie for ::i18n::addressinput::Storage. +class StorageTestRunner { + public: + // Does not take ownership of |storage|. + explicit StorageTestRunner(::i18n::addressinput::Storage* storage); + ~StorageTestRunner(); + + // Runs all the tests from the standard test suite. + void RunAllTests(); + + private: + void ClearValues(); + scoped_ptr< ::i18n::addressinput::Storage::Callback> BuildCallback(); + void OnDataReady(bool success, const std::string& key, std::string* data); + + // Test suite. + void GetWithoutPutReturnsEmptyData(); + void GetReturnsWhatWasPut(); + void SecondPutOverwritesData(); + + ::i18n::addressinput::Storage* storage_; // weak + bool success_; + std::string key_; + std::string data_; + + DISALLOW_COPY_AND_ASSIGN(StorageTestRunner); +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_STORAGE_TEST_RUNNER_H_ diff --git a/chromium/third_party/libaddressinput/chromium/string_compare.cc b/chromium/third_party/libaddressinput/chromium/string_compare.cc new file mode 100644 index 00000000000..8996cd8fadd --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/string_compare.cc @@ -0,0 +1,69 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/src/cpp/src/util/string_compare.h" + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/icu/source/i18n/unicode/coll.h" + +namespace i18n { +namespace addressinput { + +namespace { + +class IcuStringComparer { + public: + IcuStringComparer() { + UErrorCode error_code = U_ZERO_ERROR; + collator_.reset( + icu::Collator::createInstance(icu::Locale::getRoot(), error_code)); + DCHECK(U_SUCCESS(error_code)); + collator_->setStrength(icu::Collator::PRIMARY); + } + + ~IcuStringComparer() {} + + int Compare(const std::string& a, const std::string& b) const { + UErrorCode error_code = U_ZERO_ERROR; + int result = collator_->compareUTF8(a, b, error_code); + DCHECK(U_SUCCESS(error_code)); + return result; + } + + private: + // ::scoped_ptr is from "base/memory/scoped_ptr.h", which does not interfere + // with ::i18n::addressinput::scoped_ptr from + // <libaddressinput/util/scoped_ptr.h>. + ::scoped_ptr<icu::Collator> collator_; + + DISALLOW_COPY_AND_ASSIGN(IcuStringComparer); +}; + +static base::LazyInstance<IcuStringComparer> g_comparer = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// Dummy required for scoped_ptr<Impl>. +class StringCompare::Impl {}; + +StringCompare::StringCompare() {} + +StringCompare::~StringCompare() {} + +bool StringCompare::NaturalEquals(const std::string& a, + const std::string& b) const { + return g_comparer.Get().Compare(a, b) == 0; +} + +bool StringCompare::NaturalLess(const std::string& a, + const std::string& b) const { + return g_comparer.Get().Compare(a, b) < 0; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/chromium/string_compare_unittest.cc b/chromium/third_party/libaddressinput/chromium/string_compare_unittest.cc new file mode 100644 index 00000000000..a10e55ad727 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/string_compare_unittest.cc @@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/src/cpp/src/util/string_compare.h" + +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +TEST(ChromeStringCompareTest, IgnoreDiacritics) { + i18n::addressinput::StringCompare sc; + EXPECT_TRUE(sc.NaturalEquals("Texas", base::WideToUTF8(L"T\u00E9xas"))); +} + +TEST(ChromeStringCompareTest, IgnoreCapitalization) { + i18n::addressinput::StringCompare sc; + EXPECT_TRUE(sc.NaturalEquals("Texas", "teXas")); +} + +TEST(ChromeStringCompareTest, DifferentStringAreDifferent) { + i18n::addressinput::StringCompare sc; + EXPECT_FALSE(sc.NaturalEquals("Texas", "California")); +} + +} // namespace diff --git a/chromium/third_party/libaddressinput/chromium/tools/require_fields.py b/chromium/third_party/libaddressinput/chromium/tools/require_fields.py new file mode 100755 index 00000000000..b82afa2475d --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/tools/require_fields.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import urllib +from sys import exit as sys_exit + + +# Derived from region_data_constants.cc. +_COUNTRIES = [ + 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ', 'AR', 'AS', + 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', + 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', + 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', + 'CO', 'CR', 'CS', 'CV', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', + 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', + 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', + 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', + 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IS', 'IT', + 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KR', 'KW', + 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', + 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MN', 'MO', + 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', + 'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', + 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', + 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SE', + 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', + 'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', + 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', + 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'ZA', 'ZM', 'ZW' +] +_I18N_URL = 'https://i18napis.appspot.com/address/data/%s' + + +def main(): + for country in _COUNTRIES: + url = _I18N_URL % country + try: + data = json.load(urllib.urlopen(url)) + except Exception as e: + print 'Error: could not load %s' % url + return 1 + if 'require' in data: + print '%s: %s' % (country, data['require']) + return 0 + + +if __name__ == '__main__': + sys_exit(main()) diff --git a/chromium/third_party/libaddressinput/chromium/tools/update-strings.py b/chromium/third_party/libaddressinput/chromium/tools/update-strings.py new file mode 100755 index 00000000000..44e8351087f --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/tools/update-strings.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This script updates the address_input_strings.grdp file based on the strings +# in libaddressinput. + +import os +import sys + +HEADER = """<!-- + +DO NOT MODIFY. + +This file is generated by +third_party/libaddressinput/chromium/tools/update-strings.py from +src/third_party/libaddressinput/src/cpp/res/messages.grdp. Submit modifications +to the upstream library at https://github.com/googlei18n/libaddressinput. + +--> +""" + +script_dir = os.path.dirname(os.path.realpath(__file__)) +from_file = os.path.abspath(os.path.join( + script_dir, os.pardir, os.pardir, 'src', 'cpp', 'res', 'messages.grdp')) +to_file = os.path.abspath(os.path.join( + script_dir, os.pardir, os.pardir, os.pardir, os.pardir, 'chrome', 'app', + 'address_input_strings.grdp')) + +with open(from_file, 'r') as source: + with open(to_file, 'w') as destination: + destination.write(source.readline()) # XML declaration. + destination.write(HEADER) + destination.write(source.read()) diff --git a/chromium/third_party/libaddressinput/chromium/trie.cc b/chromium/third_party/libaddressinput/chromium/trie.cc new file mode 100644 index 00000000000..ccaf46e887b --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/trie.cc @@ -0,0 +1,83 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/trie.h" + +#include <stddef.h> + +#include <queue> +#include <string> + +#include "base/logging.h" + +// Separating template definitions and declarations requires defining all +// possible template parameters to avoid linking errors. +namespace i18n { +namespace addressinput { +class RegionData; +} +} + +namespace autofill { + +template <typename T> +Trie<T>::Trie() {} + +template <typename T> +Trie<T>::~Trie() {} + +template <typename T> +void Trie<T>::AddDataForKey(const std::vector<uint8_t>& key, + const T& data_item) { + Trie<T>* current_node = this; + for (std::vector<uint8_t>::size_type i = 0; i < key.size(); ++i) { + if (!key[i]) + break; + current_node = ¤t_node->sub_nodes_[key[i]]; + } + current_node->data_list_.insert(data_item); +} + +template <typename T> +void Trie<T>::FindDataForKeyPrefix(const std::vector<uint8_t>& key_prefix, + std::set<T>* results) const { + DCHECK(results); + + // Find the sub-trie for the key prefix. + const Trie<T>* current_node = this; + for (std::vector<uint8_t>::size_type i = 0; i < key_prefix.size(); ++i) { + if (!key_prefix[i]) + break; + + typename std::map<uint8_t, Trie<T> >::const_iterator sub_node_it = + current_node->sub_nodes_.find(key_prefix[i]); + if (sub_node_it == current_node->sub_nodes_.end()) + return; + + current_node = &sub_node_it->second; + } + + // Collect data from all sub-tries. + std::queue<const Trie<T>*> node_queue; + node_queue.push(current_node); + while (!node_queue.empty()) { + const Trie<T>* queue_front = node_queue.front(); + node_queue.pop(); + + results->insert(queue_front->data_list_.begin(), + queue_front->data_list_.end()); + + for (typename std::map<uint8_t, Trie<T> >::const_iterator sub_node_it = + queue_front->sub_nodes_.begin(); + sub_node_it != queue_front->sub_nodes_.end(); + ++sub_node_it) { + node_queue.push(&sub_node_it->second); + } + } +} + +template class Trie<const ::i18n::addressinput::RegionData*>; +template class Trie<std::string>; + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/chromium/trie.h b/chromium/third_party/libaddressinput/chromium/trie.h new file mode 100644 index 00000000000..914897e9b53 --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/trie.h @@ -0,0 +1,54 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_TRIE_H_ +#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_TRIE_H_ + +#include <stdint.h> +#include <map> +#include <set> +#include <vector> + +namespace autofill { + +// A prefix search tree. Can return all objects whose keys start with a prefix +// byte sequence. +// +// Maps keys to multiple objects. This property is useful when mapping region +// names to region objects. For example, there's a "St. Petersburg" in Florida, +// and there's a "St. Petersburg" in Russia. A lookup for "St. Petersburg" key +// should return two distinct objects. +template <typename T> +class Trie { + public: + Trie(); + ~Trie(); + + // Returns true if no data was added in AddDataForKey(). + bool empty() const { return data_list_.empty() && sub_nodes_.empty(); } + + // Adds a mapping from the 0 terminated |key| to |data_item|. Can be called + // with the same |key| multiple times. + void AddDataForKey(const std::vector<uint8_t>& key, const T& data_item); + + // Adds all objects whose keys start with the 0 terminated |key_prefix| to the + // |results| parameter. The |results| parameter should not be NULL. + void FindDataForKeyPrefix(const std::vector<uint8_t>& key_prefix, + std::set<T>* results) const; + + private: + // All objects for this node in the Trie. This field is a collection to enable + // mapping the same key to multiple objects. + std::set<T> data_list_; + + // Trie sub nodes. The root Trie stores the objects for the empty key. The + // children of the root Trie store the objects for the one-byte keys. The + // grand-children of the root Trie store the objects for the two-byte keys, + // and so on. + std::map<uint8_t, Trie<T> > sub_nodes_; +}; + +} // namespace autofill + +#endif // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_TRIE_H_ diff --git a/chromium/third_party/libaddressinput/chromium/trie_unittest.cc b/chromium/third_party/libaddressinput/chromium/trie_unittest.cc new file mode 100644 index 00000000000..32b0bb1d3ab --- /dev/null +++ b/chromium/third_party/libaddressinput/chromium/trie_unittest.cc @@ -0,0 +1,109 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/libaddressinput/chromium/trie.h" + +#include <stdint.h> +#include <set> +#include <string> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +namespace { + +std::vector<uint8_t> ToByteArray(const std::string& text) { + std::vector<uint8_t> result(text.length() + 1, 0); + result.assign(text.begin(), text.end()); + return result; +} + +} // namespace + +TEST(TrieTest, EmptyTrieHasNoData) { + Trie<std::string> trie; + std::set<std::string> result; + trie.FindDataForKeyPrefix(ToByteArray("key"), &result); + EXPECT_TRUE(result.empty()); +} + +TEST(TrieTest, CanGetDataByExactKey) { + Trie<std::string> trie; + trie.AddDataForKey(ToByteArray("hello"), "world"); + std::set<std::string> result; + trie.FindDataForKeyPrefix(ToByteArray("hello"), &result); + std::set<std::string> expected; + expected.insert("world"); + EXPECT_EQ(expected, result); +} + +TEST(TrieTest, CanGetDataByPrefix) { + Trie<std::string> trie; + trie.AddDataForKey(ToByteArray("hello"), "world"); + std::set<std::string> result; + trie.FindDataForKeyPrefix(ToByteArray("he"), &result); + std::set<std::string> expected; + expected.insert("world"); + EXPECT_EQ(expected, result); +} + +TEST(TrieTest, KeyTooLongNoData) { + Trie<std::string> trie; + trie.AddDataForKey(ToByteArray("hello"), "world"); + std::set<std::string> result; + trie.FindDataForKeyPrefix(ToByteArray("helloo"), &result); + EXPECT_TRUE(result.empty()); +} + +TEST(TrieTest, CommonPrefixFindsMultipleData) { + Trie<std::string> trie; + trie.AddDataForKey(ToByteArray("hello"), "world"); + trie.AddDataForKey(ToByteArray("howdy"), "buddy"); + trie.AddDataForKey(ToByteArray("foo"), "bar"); + std::set<std::string> results; + trie.FindDataForKeyPrefix(ToByteArray("h"), &results); + std::set<std::string> expected; + expected.insert("world"); + expected.insert("buddy"); + EXPECT_EQ(expected, results); +} + +TEST(TrieTest, KeyCanBePrefixOfOtherKey) { + Trie<std::string> trie; + trie.AddDataForKey(ToByteArray("hello"), "world"); + trie.AddDataForKey(ToByteArray("helloo"), "woorld"); + trie.AddDataForKey(ToByteArray("hella"), "warld"); + std::set<std::string> results; + trie.FindDataForKeyPrefix(ToByteArray("hello"), &results); + std::set<std::string> expected; + expected.insert("world"); + expected.insert("woorld"); + EXPECT_EQ(expected, results); +} + +TEST(TrieTest, AllowMutlipleKeys) { + Trie<std::string> trie; + trie.AddDataForKey(ToByteArray("hello"), "world"); + trie.AddDataForKey(ToByteArray("hello"), "woorld"); + std::set<std::string> results; + trie.FindDataForKeyPrefix(ToByteArray("hello"), &results); + std::set<std::string> expected; + expected.insert("world"); + expected.insert("woorld"); + EXPECT_EQ(expected, results); +} + +TEST(TrieTest, CanFindVeryLongKey) { + Trie<std::string> trie; + static const char kVeryLongKey[] = "1234567890qwertyuioasdfghj"; + trie.AddDataForKey(ToByteArray(kVeryLongKey), "world"); + std::set<std::string> result; + trie.FindDataForKeyPrefix(ToByteArray(kVeryLongKey), &result); + std::set<std::string> expected; + expected.insert("world"); + EXPECT_EQ(expected, result); +} + +} // namespace autofill diff --git a/chromium/third_party/libaddressinput/src/AUTHORS b/chromium/third_party/libaddressinput/src/AUTHORS new file mode 100644 index 00000000000..c42ee90e455 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/AUTHORS @@ -0,0 +1,9 @@ +# This is the official list of libaddressinput authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization <email address> +# The email address is not required for organizations. + +Google Inc. diff --git a/chromium/third_party/libaddressinput/src/CONTRIBUTORS b/chromium/third_party/libaddressinput/src/CONTRIBUTORS new file mode 100644 index 00000000000..f8840a56506 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/CONTRIBUTORS @@ -0,0 +1,20 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name <email address> + +David Beaumont <dbeaumont@google.com> +David Yonge-Mallo <davinci@google.com> +Dong Zhou <dongzhou@google.com> +Fredrik Roubert <roubert@google.com> +Jeanine Lilleng <jeanine@google.com> +Keghani Kouzoujian <keghani@google.com> +Lara Scheidegger <lararennie@google.com> +Rouslan Solomakhin <rouslan@chromium.org> +Shaopeng Jia <shaopengjia@google.com> diff --git a/chromium/third_party/libaddressinput/src/LICENSE b/chromium/third_party/libaddressinput/src/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/chromium/third_party/libaddressinput/src/README.md b/chromium/third_party/libaddressinput/src/README.md new file mode 100644 index 00000000000..0e67ff9240d --- /dev/null +++ b/chromium/third_party/libaddressinput/src/README.md @@ -0,0 +1,46 @@ +#  libaddressinput + +[](https://drone.io/github.com/googlei18n/libaddressinput/latest) + +The _libaddressinput_ project consists of two different libraries (one +implemented in C++, one implemented in Java for Android) that use +[address metadata](https://github.com/googlei18n/libaddressinput/wiki/AddressValidationMetadata) +from +[Google](https://developers.google.com/)'s +[I18n Services](https://i18napis.appspot.com/) +[Address Data Service](https://i18napis.appspot.com/address) +to assist application developers in collecting and handling _postal addresses_ +from all over the world. + +These libraries can provide information about what input fields are required for +a correct address input form for any country in the world and can validate an +address to highlight input errors like missing required fields or invalid +values. + +## C++ + +The C++ library (in very portable C++03) of _libaddressinput_ is the backend for +[requestAutocomplete()](http://www.html5rocks.com/en/tutorials/forms/requestautocomplete/) +in [Chromium](http://www.chromium.org/Home). The source code for that is a good +example of how to use this library to implement a complex feature in a real +application: + +https://src.chromium.org/viewvc/chrome/trunk/src/third_party/libaddressinput/ +https://chromium.googlesource.com/chromium/src/+/master/third_party/libaddressinput/ + +Video: [Easy International Checkout with Chrome](https://www.youtube.com/watch?v=ljYeHwGgzQk) + +## Java + +The Java library of _libaddressinput_ is written for use in +[Android](https://developer.android.com/) and includes an Android UI address +input widget ready for use, but only the UI parts are tied to Android. + +Non-UI code and tests can be run in Java SE, and the rest of the library could +easily be adapted to run in any Java environment. + +## Mailing List + +Using and developing libaddressinput is discussed on this mailing list: + +https://groups.google.com/forum/#!forum/libaddressinput-discuss diff --git a/chromium/third_party/libaddressinput/src/android/README b/chromium/third_party/libaddressinput/src/android/README new file mode 100644 index 00000000000..dada471f3e0 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/README @@ -0,0 +1,45 @@ +Building and running tests with Android +======================================= + +The easiest way to build libaddressinput for Android and run all the tests is +using the Gradle project automation tool: + +http://tools.android.com/tech-docs/new-build-system +http://www.gradle.org/ + + +Prerequisite dependencies for using Gradle with Android +------------------------------------------------------- +Android Studio: https://developer.android.com/sdk/index.html +or +Android SDK Tools: https://developer.android.com/sdk/index.html#Other + +Set the ANDROID_HOME environment variable to the root of the SDK. + +Install the following packages: +* Tools/Android SDK Build-tools (Rev. 21.1.2) +* Android 5.1 (API 22) +* Extras/Android Support Library + +Gradle (latest version): + https://services.gradle.org/distributions/gradle-2.3-bin.zip + +Note: Additionally you must take care to avoid having multiple versions of +Gradle on your path, as this can cause problems. + + +Building and Running +-------------------- +After installing all the prerequisites, check that everything is working by +running: + +$ gradle build + +With an Android emulator running or an Android device connected, the following +command line then builds the library and runs the tests: + +$ gradle connectedInstrumentTest + +The test runner logs to the system log, which can be viewed using logcat: + +$ adb logcat diff --git a/chromium/third_party/libaddressinput/src/android/build.gradle b/chromium/third_party/libaddressinput/src/android/build.gradle new file mode 100644 index 00000000000..0d48fc8c6d8 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/build.gradle @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * 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. + */ + +buildscript { + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0' + } +} + +apply plugin: 'com.android.library' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +dependencies { + compile project(':common') +} + +android { + /* + * If these are modified, update the README to reflect the new versions and + * update any related settings in the AdroidManifest.xml file. + * + * NOTE: Because the 'buildToolsVersion' directive only matches an exact + * release (rather than allowing wildcards) and Android remove older + * versions of the build tools very soon after a new revision is made + * available, we must never use the lastest major version of the build + * tools here (because it will quickly be superceded and become unavailable + * to anyone using a fresh install of the SDK). The "final" release of the + * previous major version remains available for much longer however, so as + * a workaround we always use that. + * + * So when the build tools version 23.0.0 is released, the buildToolsVersion + * below should be bumped to the last released version of the 22.x.x series. + * + * The obvious way to fix this would be allow wildcards (ie, "22.+") but + * Android have explicitly said that they won't do this. + */ + compileSdkVersion 22 + buildToolsVersion '21.1.2' +} + diff --git a/chromium/third_party/libaddressinput/src/android/src/androidTest/AndroidManifest.xml b/chromium/third_party/libaddressinput/src/android/src/androidTest/AndroidManifest.xml new file mode 100644 index 00000000000..d16ab0d834f --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/androidTest/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.i18n.addressinput" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="9" + android:targetSdkVersion="22" /> + +<!-- + <instrumentation + android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.i18n.addressinput" /> +--> + + <uses-permission android:name="android.permission.INTERNET" /> + + <application + android:allowBackup="false" + android:icon="@android:drawable/sym_def_app_icon" > + <uses-library android:name="android.test.runner" /> + <activity android:name=".testing.TestActivity" /> + </application> + +</manifest> diff --git a/chromium/third_party/libaddressinput/src/android/src/main/AndroidManifest.xml b/chromium/third_party/libaddressinput/src/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..e4b72013c16 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.i18n.addressinput" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="9" + android:targetSdkVersion="22" /> + <application/> + +</manifest> diff --git a/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_edittext.xml b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_edittext.xml new file mode 100644 index 00000000000..e36c330c767 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_edittext.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (C) 2010 Google Inc. + * + * 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. + */ +--> +<EditText + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/address_edit_text" + android:singleLine="true" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:inputType = "textPostalAddress|textCapWords" /> diff --git a/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_layout.xml b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_layout.xml new file mode 100644 index 00000000000..1256968e967 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_layout.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (C) 2010 Google Inc. + * + * 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. + */ +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/address_layout" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> diff --git a/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_spinner.xml b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_spinner.xml new file mode 100644 index 00000000000..9f2bf3068c4 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_spinner.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (C) 2010 Google Inc. + * + * 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. + */ +--> +<Spinner + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/address_spinner" + android:drawSelectorOnTop="true" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> diff --git a/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_textview.xml b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_textview.xml new file mode 100644 index 00000000000..f112a5a03e3 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/main/res/layout/address_textview.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (C) 2010 Google Inc. + * + * 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. + */ +--> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/address_text_view" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dip" + android:layout_marginLeft="3dip" + android:textColor="?android:attr/textColorPrimary" + android:focusableInTouchMode="true" /> diff --git a/chromium/third_party/libaddressinput/src/android/src/main/res/values/address_strings.xml b/chromium/third_party/libaddressinput/src/android/src/main/res/values/address_strings.xml new file mode 100644 index 00000000000..7a6d2bd74e4 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/android/src/main/res/values/address_strings.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (C) 2010 Google Inc. + * + * 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. + */ + +/* + * Strings used in the AddressInput widget. The first section contains strings + * that may need to be changed for consistency with the client application, the + * second section contains widget-specific labels and error messages. + */ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- The first section of strings are for strings that may need to be changed + to be consistent with other parts of the client application. --> + + <string name="address_data_loading" translation_description="Message displayed to the user when data is being loaded from the server. The u2026 is the unicode character for the ellipses (...)">Loading\u2026</string> + + <string name="please_select" translation_description="Message shown for a dropdown menu in which nothing is yet selected.">Please select</string> + + <!-- Strings below this point are address-specific and relate either to + labels for input fields or to error messages that the widget may report. --> + + <string name="i18n_country_or_region_label" translation_description="A country or a political region (Countries like the United States or regions like Hong Kong or Macao, or places like Taiwan, where whether it is a country or not is a politically sensitive question). [CHAR LIMIT=30]">Country / Region</string> + + <string name="i18n_locality_label" translation_description="A city or town, such as New York City [CHAR LIMIT=30]">City</string> + + <string name="i18n_post_town" translation_description="The name of a town through which postal deliveries are routed, present in UK addresses. See: http://en.wikipedia.org/wiki/Post_town [CHAR LIMIT=30]">Post Town</string> + + <string name="i18n_suburb" translation_description="Smaller part of a city used in some addresses in countries like New Zealand to give a more specific location in a postal address. [CHAR LIMIT=30]">Suburb</string> + + <string name="i18n_village_township" translation_description="A unit used in postal addresses in Malaysia, which is smaller than the city/town, and represents a village, township, or precinct. [CHAR LIMIT=30]">Village / Township</string> + + <string name="i18n_address_line1_label" translation_description="Street-level part of an address, e.g. "18th Street, Unit 3". [CHAR LIMIT=30]">Street address</string> + + <string name="i18n_pin_code_label" translation_description="PIN (Postal Index Number) Code. Values are numeric. Used in India. [CHAR LIMIT=30]">PIN code</string> + + <string name="i18n_postal_code_label" translation_description="Postal Code. Values are frequently alphanumeric. Used in countries such as Switzerland. [CHAR LIMIT=30]">Postal code</string> + + <string name="i18n_zip_code_label" translation_description="ZIP code. Used in countries like the US. [CHAR LIMIT=30]">ZIP code</string> + + <string name="i18n_area" translation_description="Administrative Area for Hong Kong (e.g. Kowloon). [CHAR LIMIT=30]">Area</string> + + <string name="i18n_county" translation_description="Administrative Area for the United Kingdom (e.g. Yorkshire). [CHAR LIMIT=30]">County</string> + + <string name="i18n_department" translation_description="Administrative Area, as used for countries like Nicaragua (e.g. Boaco). [CHAR LIMIT=30]">Department</string> + + <string name="i18n_district" translation_description="Administrative Area for Nauru Central Pacific (e.g. Aiwo district), or area of a town (a neighborhood/suburb) used for addresses in Korea and China. [CHAR LIMIT=30]">District</string> + + <string name="i18n_do_si" translation_description="Administrative Area for Korea (e.g. Gyeonggi-do or Busan-si). [CHAR LIMIT=30]">Do/Si</string> + + <string name="i18n_emirate" translation_description="Administrative Area for United Arab Emirates (e.g. Abu Dhabi). [CHAR LIMIT=30]">Emirate</string> + + <string name="i18n_island" translation_description="Administrative Area for certain countries (e.g. Bahama's Cat Island). [CHAR LIMIT=30]">Island</string> + + <string name="i18n_oblast" translation_description="Administrative Area for certain countries (e.g. Russia's Leningrad). [CHAR LIMIT=30]">Oblast</string> + + <string name="i18n_parish" translation_description="Administrative Area for certain countries (e.g. Andorra's Canillo). [CHAR LIMIT=30]">Parish</string> + + <string name="i18n_prefecture" translation_description="Administrative Area for Japan (e.g. Hokkaido). [CHAR LIMIT=30]">Prefecture</string> + + <string name="i18n_province" translation_description="Administrative Area for certain countries (e.g. Canada's Ontario). [CHAR LIMIT=30]">Province</string> + + <string name="i18n_state" translation_description="Administrative Area for certain countries (e.g. California in the USA). [CHAR LIMIT=30]">State</string> + + <string name="i18n_recipient_label" translation_description="Label indicating the person to be contacted as part of this address, to be used for example as "Name: John Doe". [CHAR LIMIT=30]">Name</string> + + <string name="i18n_neighborhood" translation_description="Label for a neighborhood, shown as part of an address input form. [CHAR LIMIT=30]">Neighborhood</string> + + <string name="i18n_organization_label" translation_description="Label for the field of organization, firm, company, or institution in an address. Examples of values in this field: Google, Department of Transportation, University of Cambridge. [CHAR LIMIT=30]">Organization</string> + + <string name="i18n_missing_required_field" translation_description="Error message shown with a UI field when it is a required field and the user has not filled it out. [CHAR LIMIT=30]">You can\u0027t leave this empty.</string> + + <string name="unknown_entry" translation_description="Occurs when the user fills out the wrong value for an address field. For example, this would be shown when putting 'Cupertino' in United States' State field. [CHAR LIMIT=60]">%1$s is not recognized as a known value for this field.</string> + + <string name="unrecognized_format_pin_code" translation_description="Occurs when the user fills out a PIN code that does not conform to the country's PIN code format. For example, this would be shown when using '123' as an Indian PIN code, which is normally 6 digits long. [CHAR LIMIT=60]">This PIN code format is not recognized.</string> + + <string name="unrecognized_format_postal_code" translation_description="Occurs when the user fills out a postal code that does not conform to the country's postal code format. For example, this would be shown when using '80' as a Swiss postal code, which is normally 4 digits long. [CHAR LIMIT=60]">This postal code format is not recognized.</string> + + <string name="unrecognized_format_zip_code" translation_description="Occurs when the user fills out a ZIP code that does not conform to the country's ZIP code format. For example, this would be shown when using '901' as a ZIP code for the United States. [CHAR LIMIT=60]">This ZIP code format is not recognized.</string> + + <string name="mismatching_value_pin_code" translation_description="Occurs when the user fills out the wrong PIN code for a certain location. For example, this would be shown when using 456001 for New Delhi, India. [CHAR LIMIT=70]">This PIN code does not appear to match the rest of this address.</string> + + <string name="mismatching_value_postal_code" translation_description="Occurs when the user fills out the wrong postal code for a certain location. For example, this would be shown when using Z3Z 2Y7 for Alberta, Canada. [CHAR LIMIT=70]">This postal code does not appear to match the rest of this address.</string> + + <string name="mismatching_value_zip_code" translation_description="Occurs when the user fills out the wrong ZIP code for a certain location. For example, this would be shown when using 10001 for Arizona state. [CHAR LIMIT=70]">This ZIP code does not appear to match the rest of this address.</string> + + <string name="i18n_address_line1_accessibility_label" translation_description="Accessibility label for the text field of the first street address line. [CHAR LIMIT=50]">Street address: line 1</string> + + <string name="i18n_address_line2_accessibility_label" translation_description="Accessibility label for the text field of the second street address line. [CHAR LIMIT=50]">Street address: line 2</string> +</resources> diff --git a/chromium/third_party/libaddressinput/src/build.gradle b/chromium/third_party/libaddressinput/src/build.gradle new file mode 100644 index 00000000000..b63b0b7286a --- /dev/null +++ b/chromium/third_party/libaddressinput/src/build.gradle @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * 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. + */ + +/* + * Root Gradle file for Java address input widget (under "common" and "android") + */ +allprojects { + repositories { + mavenCentral() + mavenLocal() + } +} diff --git a/chromium/third_party/libaddressinput/src/common/README b/chromium/third_party/libaddressinput/src/common/README new file mode 100644 index 00000000000..fdec1bdcec6 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/common/README @@ -0,0 +1,26 @@ +Building and running tests +========================== + +The common (non-UI) parts of libaddressinput are built and run using the Gradle +project automation tool: + +http://tools.android.com/tech-docs/new-build-system +http://www.gradle.org/ + + +Prerequisite dependencies for using Gradle +------------------------------------------ +Gradle (latest version): + https://services.gradle.org/distributions/gradle-2.3-bin.zip + +Note: Additionally you must take care to avoid having multiple versions of +Gradle on your path, as this can cause problems. + + +Building and Running +-------------------- +After installing all the prerequisites, check that everything is working by +running: + +$ gradle build +$ gradle test diff --git a/chromium/third_party/libaddressinput/src/common/build.gradle b/chromium/third_party/libaddressinput/src/common/build.gradle new file mode 100644 index 00000000000..a03c619c4d1 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/common/build.gradle @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * 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. + */ + +buildscript { + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0' + } +} + +apply plugin: 'java' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +sourceSets { + /* It's simpler if the test resources are next to the java sources. */ + test { + resources { + srcDir 'src/test/java' + } + } +} + +test { + /* Listen to events in the test execution lifecycle. */ + beforeTest { descriptor -> logger.lifecycle("Running test: " + descriptor) } + + /* Show standard out and standard error of the test JVM(s) on the console. */ + // testLogging.showStandardStreams = true + + /* Listen to standard out and standard error of the test JVM(s). */ + // onOutput { descriptor, event -> + // logger.lifecycle("Test: " + descriptor + " produced standard out/err: " + event.message ) + // } +} + +dependencies { + compile 'com.google.guava:guava-gwt:18.0' + /* Note that gradle will warn about this not being the same version as * + * the Android JSON library (but will not compile if it's removed). */ + compile 'org.json:json:20090211' + testCompile 'junit:junit:4.11' + testCompile 'com.google.truth:truth:0.25' + testCompile 'org.mockito:mockito-core:1.9.5' +} + diff --git a/chromium/third_party/libaddressinput/src/cpp/LICENSE.chromium b/chromium/third_party/libaddressinput/src/cpp/LICENSE.chromium new file mode 100644 index 00000000000..3d0f7d3edfd --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/LICENSE.chromium @@ -0,0 +1,27 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/chromium/third_party/libaddressinput/src/cpp/README b/chromium/third_party/libaddressinput/src/cpp/README new file mode 100644 index 00000000000..d6fbf447545 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/README @@ -0,0 +1,82 @@ +Intro +===== + +The C++ version of libaddressinput library provides UI layout information and +validation for address input forms. + +The library does not provide a UI. The user of the library must provide the user +interface that uses libaddressinput. The user of the library must also provide a +way to store data on disk and download data from the internet. + +The first client of the library is Chrome web browser. This motivates not +providing UI or networking capabilities. Chrome will provide those. + +When including the library in your project, you can override the dependencies +and include directories in libaddressinput.gypi to link with your own +third-party libraries. + +Dependencies +============ + +The library depends on these tools and libraries: + +GYP: Generates the build files. +Ninja: Executes the build files. +GTest: Used for unit tests. +Python: Used by GRIT, which generates localization files. +RE2: Used for validating postal code format. + +Most of these packages are available on Debian-like distributions. You can +install them with this command: + +$ sudo apt-get install gyp ninja-build libgtest-dev python libre2-dev + +Make sure that your version of GYP is at least 0.1~svn1395. Older versions of +GYP do not generate the Ninja build files correctly. You can download a +new-enough version from http://packages.ubuntu.com/saucy/gyp. + +Make sure that your version of RE2 is at least 20140111+dfsg-1. Older versions +of RE2 don't support set_never_capture() and the packages don't provide shared +libraries. + +If your distribution does not include the binary packages for the dependencies, +you can download them from these locations: + +http://packages.ubuntu.com/saucy/gyp +http://packages.ubuntu.com/saucy/ninja-build +http://packages.ubuntu.com/saucy/libgtest-dev +http://packages.ubuntu.com/saucy/python +http://packages.ubuntu.com/utopic/libre2-1 +http://packages.ubuntu.com/utopic/libre2-dev + +Alternatively, you can download, build, and install these tools and libraries +from source code. Their home pages contain information on how to accomplish +that. + +https://code.google.com/p/gyp/ +http://martine.github.io/ninja/ +https://code.google.com/p/googletest/ +http://python.org/ +https://code.google.com/p/re2/ + +Build +===== + +Building the library involves generating an out/Default/build.ninja file and +running ninja: + +$ export GYP_GENERATORS='ninja' +$ gyp --depth . +$ ninja -C out/Default + +Overriding paths defined in the *.gyp files can be done by setting the +GYP_DEFINES environment variable before running gyp: + +$ export GYP_DEFINES="gtest_dir='/xxx/include' gtest_src_dir='/xxx'" + +Test +==== + +This command will execute the unit tests for the library: + +$ out/Default/unit_tests diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h new file mode 100644 index 00000000000..89d32737235 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h @@ -0,0 +1,96 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// A struct for storing address data: country code, administrative area, +// locality, etc. The field names correspond to the OASIS xAL standard: +// https://www.oasis-open.org/committees/ciq/download.shtml + +#ifndef I18N_ADDRESSINPUT_ADDRESS_DATA_H_ +#define I18N_ADDRESSINPUT_ADDRESS_DATA_H_ + +#include <libaddressinput/address_field.h> + +#include <iosfwd> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +struct AddressData { + // CLDR (Common Locale Data Repository) region code. + std::string region_code; + + // The address lines represent the most specific part of any address. + std::vector<std::string> address_line; + + // Top-level administrative subdivision of this country. + std::string administrative_area; + + // Generally refers to the city/town portion of an address. + std::string locality; + + // Dependent locality or sublocality. Used for UK dependent localities, or + // neighborhoods or boroughs in other locations. + std::string dependent_locality; + + // Values are frequently alphanumeric. + std::string postal_code; + + // This corresponds to the SortingCode sub-element of the xAL + // PostalServiceElements element. Use is very country-specific. + std::string sorting_code; + + // Language code of the address. Should be in BCP-47 format. + std::string language_code; + + // The organization, firm, company, or institution at this address. This + // corresponds to the FirmName sub-element of the xAL FirmType element. + std::string organization; + + // Name of recipient or contact person. Not present in xAL. + std::string recipient; + + // Returns whether the |field| is empty. + bool IsFieldEmpty(AddressField field) const; + + // Returns the value of the |field|. The parameter must not be STREET_ADDRESS, + // which comprises multiple fields (will crash otherwise). + const std::string& GetFieldValue(AddressField field) const; + + // Copies |value| into the |field|. The parameter must not be STREET_ADDRESS, + // which comprises multiple fields (will crash otherwise). + void SetFieldValue(AddressField field, const std::string& value); + + // Returns the value of the |field|. The parameter must be STREET_ADDRESS, + // which comprises multiple fields (will crash otherwise). + const std::vector<std::string>& GetRepeatedFieldValue( + AddressField field) const; + + bool operator==(const AddressData& other) const; + + // Returns true if the parameter comprises multiple fields, false otherwise. + // Use it to determine whether to call |GetFieldValue| or + // |GetRepeatedFieldValue|. + static bool IsRepeatedFieldValue(AddressField field); +}; + +} // namespace addressinput +} // namespace i18n + +// Produces human-readable output in logging, for example in unit tests. +std::ostream& operator<<(std::ostream& o, + const i18n::addressinput::AddressData& address); + +#endif // I18N_ADDRESSINPUT_ADDRESS_DATA_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h new file mode 100644 index 00000000000..8f2ee05e4c9 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h @@ -0,0 +1,47 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_FIELD_H_ +#define I18N_ADDRESSINPUT_ADDRESS_FIELD_H_ + +#include <iosfwd> + +namespace i18n { +namespace addressinput { + +// Address field types, ordered by size, from largest to smallest. +enum AddressField { + COUNTRY, // Country code. + ADMIN_AREA, // Administrative area such as a state, province, + // island, etc. + LOCALITY, // City or locality. + DEPENDENT_LOCALITY, // Dependent locality (may be an inner-city district or + // a suburb). + SORTING_CODE, // Sorting code. + POSTAL_CODE, // Zip or postal code. + STREET_ADDRESS, // Street address lines. + ORGANIZATION, // Organization, company, firm, institution, etc. + RECIPIENT // Name. +}; + +} // namespace addressinput +} // namespace i18n + +// Produces human-readable output in logging, for example in unit tests. Prints +// what you would expect for valid fields, e.g. "COUNTRY" for COUNTRY. For +// invalid values, prints "[INVALID ENUM VALUE x]". +std::ostream& operator<<(std::ostream& o, + i18n::addressinput::AddressField field); + +#endif // I18N_ADDRESSINPUT_ADDRESS_FIELD_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h new file mode 100644 index 00000000000..e267884bf67 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h @@ -0,0 +1,51 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// Utility functions for formatting the addresses represented as AddressData. +// +// Note these work best if the address has a language code specified - this can +// be obtained when building the UI components (calling BuildComponents on +// address_ui.h). + +#ifndef I18N_ADDRESSINPUT_ADDRESS_FORMATTER_H_ +#define I18N_ADDRESSINPUT_ADDRESS_FORMATTER_H_ + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +struct AddressData; + +// Formats the address onto multiple lines. This formats the address in national +// format; without the country. +void GetFormattedNationalAddress( + const AddressData& address_data, std::vector<std::string>* lines); + +// Formats the address as a single line. This formats the address in national +// format; without the country. +void GetFormattedNationalAddressLine( + const AddressData& address_data, std::string* line); + +// Formats the street-level part of an address as a single line. For example, +// two lines of "Apt 1", "10 Red St." will be concatenated in a +// language-appropriate way, to give something like "Apt 1, 10 Red St". +void GetStreetAddressLinesAsSingleLine( + const AddressData& address_data, std::string* line); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_FORMATTER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_input_helper.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_input_helper.h new file mode 100644 index 00000000000..feb04d7ae83 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_input_helper.h @@ -0,0 +1,67 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_INPUT_HELPER_H_ +#define I18N_ADDRESSINPUT_ADDRESS_INPUT_HELPER_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <vector> + +namespace i18n { +namespace addressinput { + +class LookupKey; +class PreloadSupplier; +struct AddressData; +struct Node; + +class AddressInputHelper { + public: + // Creates an input helper that uses the supplier provided to get metadata to + // help a user complete or fix an address. Doesn't take ownership of + // |supplier|. Since latency is important for these kinds of tasks, we expect + // the supplier to have the data already. + AddressInputHelper(PreloadSupplier* supplier); + + ~AddressInputHelper(); + + // Fill in missing components of an address as best as we can based on + // existing data. For example, for some countries only one postal code is + // valid; this would enter that one. For others, the postal code indicates + // what state should be selected. Existing data will never be overwritten. + // + // Note that the preload supplier must have had the rules for the country + // represented by this address loaded before this method is called - otherwise + // an assertion failure will result. + // + // The address should have the best language tag as returned from + // BuildComponents(). + void FillAddress(AddressData* address) const; + + private: + void CheckChildrenForPostCodeMatches( + const AddressData& address, const LookupKey& lookup_key, + const Node* parent, std::vector<Node>* hierarchy) const; + + // We don't own the supplier_. + PreloadSupplier* const supplier_; + + DISALLOW_COPY_AND_ASSIGN(AddressInputHelper); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_INPUT_HELPER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h new file mode 100644 index 00000000000..cbe72db52b3 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h @@ -0,0 +1,38 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_METADATA_H_ +#define I18N_ADDRESSINPUT_ADDRESS_METADATA_H_ + +#include <libaddressinput/address_field.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +// Checks whether |field| is a required field for |region_code|. Returns false +// also if no data could be found for region_code. Note: COUNTRY is always +// required. +bool IsFieldRequired(AddressField field, const std::string& region_code); + +// Checks whether |field| is a field that is used for |region_code|. Returns +// false also if no data could be found for region_code. Note: COUNTRY is always +// used. +bool IsFieldUsed(AddressField field, const std::string& region_code); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_METADATA_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_normalizer.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_normalizer.h new file mode 100644 index 00000000000..06b7eb2b3fd --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_normalizer.h @@ -0,0 +1,49 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_NORMALIZER_H_ +#define I18N_ADDRESSINPUT_ADDRESS_NORMALIZER_H_ + +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +namespace i18n { +namespace addressinput { + +class PreloadSupplier; +class StringCompare; +struct AddressData; + +class AddressNormalizer { + public: + // Does not take ownership of |supplier|. + explicit AddressNormalizer(const PreloadSupplier* supplier); + ~AddressNormalizer(); + + // Converts the names of different fields in the address into their canonical + // form. Should be called only when supplier->IsLoaded() returns true for + // the region code of the |address|. + void Normalize(AddressData* address) const; + + private: + const PreloadSupplier* const supplier_; // Not owned. + const scoped_ptr<const StringCompare> compare_; + + DISALLOW_COPY_AND_ASSIGN(AddressNormalizer); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_NORMALIZER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h new file mode 100644 index 00000000000..743b9e86aa4 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h @@ -0,0 +1,68 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_PROBLEM_H_ +#define I18N_ADDRESSINPUT_ADDRESS_PROBLEM_H_ + +#include <iosfwd> + +namespace i18n { +namespace addressinput { + +// Address problem types, in no particular order. +enum AddressProblem { + // The field is not null and not whitespace, and the field should not be used + // by addresses in this country. For example, in the U.S. the SORTING_CODE + // field is unused, so its presence is an error. + UNEXPECTED_FIELD, + + // The field is null or whitespace, and the field is required. For example, + // in the U.S. ADMIN_AREA is a required field. + MISSING_REQUIRED_FIELD, + + // A list of values for the field is defined and the value does not occur in + // the list. Applies to hierarchical elements like REGION, ADMIN_AREA, + // LOCALITY, and DEPENDENT_LOCALITY. For example, in the US, the values for + // ADMIN_AREA include "CA" but not "XX". + UNKNOWN_VALUE, + + // A format for the field is defined and the value does not match. This is + // used to match POSTAL_CODE against the the format pattern generally. Formats + // indicate how many digits/letters should be present, and what punctuation is + // allowed. For example, in the U.S. postal codes are five digits with an + // optional hyphen followed by four digits. + INVALID_FORMAT, + + // A specific pattern for the field is defined based on a specific sub-region + // (an ADMIN_AREA for example) and the value does not match. This is used to + // match POSTAL_CODE against a regular expression. For example, in the U.S. + // postal codes in the state of California start with '9'. + MISMATCHING_VALUE, + + // The value contains a P.O. box and the widget options have acceptPostal set + // to false. For example, a street address line that contained "P.O. Box 3456" + // would fire this error. + USES_P_O_BOX +}; + +} // namespace addressinput +} // namespace i18n + +// Produces human-readable output in logging, for example in unit tests. Prints +// what you would expect for valid values, e.g. "UNEXPECTED_FIELD" for +// UNEXPECTED_FIELD. For invalid values, prints "[INVALID ENUM VALUE x]". +std::ostream& operator<<(std::ostream& o, + i18n::addressinput::AddressProblem problem); + +#endif // I18N_ADDRESSINPUT_ADDRESS_PROBLEM_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h new file mode 100644 index 00000000000..cc39f6a1204 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h @@ -0,0 +1,49 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_UI_H_ +#define I18N_ADDRESSINPUT_ADDRESS_UI_H_ + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +class Localization; +struct AddressUiComponent; + +// Returns the list of supported CLDR region codes. +const std::vector<std::string>& GetRegionCodes(); + +// Returns the UI components for the CLDR |region_code|. Uses the strings from +// |localization|. The components can be in default or Latin order, depending on +// the BCP 47 |ui_language_tag|. +// +// Sets the |best_address_language_tag| to the BCP 47 language tag that should +// be saved with this address. This language will be used to get drop-downs to +// help users fill in their address, and to format the address that the user +// entered. The parameter should not be NULL. +// +// Returns an empty vector on error. +std::vector<AddressUiComponent> BuildComponents( + const std::string& region_code, + const Localization& localization, + const std::string& ui_language_tag, + std::string* best_address_language_tag); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_UI_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h new file mode 100644 index 00000000000..5982a29f003 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h @@ -0,0 +1,49 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_UI_COMPONENT_H_ +#define I18N_ADDRESSINPUT_ADDRESS_UI_COMPONENT_H_ + +#include <libaddressinput/address_field.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +// A description of an input field in an address form. The user of the library +// will use a list of these elements to layout the address form input fields. +struct AddressUiComponent { + // The types of hints for how large the field should be in a multiline address + // form. + enum LengthHint { + HINT_LONG, // The field should take up the whole line. + HINT_SHORT // The field does not need to take up the whole line. + }; + + // The address field type for this UI component, for example LOCALITY. + AddressField field; + + // The name of the field, for example "City". + std::string name; + + // The hint for how large the input field should be in a multiline address + // form. + LengthHint length_hint; +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_UI_COMPONENT_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h new file mode 100644 index 00000000000..cdb1edf1286 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h @@ -0,0 +1,113 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// The public interface to the address validation features of libaddressinput. +// The AddressValidator will examine an AddressData struct and return a map of +// the problems found with the different fields of this struct. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_VALIDATOR_H_ +#define I18N_ADDRESSINPUT_ADDRESS_VALIDATOR_H_ + +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_problem.h> +#include <libaddressinput/callback.h> +#include <libaddressinput/util/basictypes.h> + +#include <map> + +namespace i18n { +namespace addressinput { + +class Supplier; +struct AddressData; + +typedef std::multimap<AddressField, AddressProblem> FieldProblemMap; + +// Validates an AddressData struct. Sample usage: +// class MyClass { +// public: +// MyClass() +// : supplier_(new MySupplier), +// validator_(new AddressValidator(supplier_.get())), +// validated_(BuildCallback(this, &MyClass::Validated)) {} +// +// virtual ~MyClass() {} +// +// void ValidateAddress() const { +// address_.region_code = "US"; +// address_.administrative_area = "CA"; +// validator_.Validate(address_, filter_, &problems_, *validated_); +// } +// +// void Validated(bool success, +// const AddressData& address, +// const FieldProblemMap& problems) { +// if (success && problems.empty()) { +// ... +// } +// } +// +// private: +// AddressData address_; +// FieldProblemMap filter_; +// FieldProblemMap problems_; +// const scoped_ptr<Supplier> supplier_; +// const scoped_ptr<AddressValidator> validator_; +// const scoped_ptr<const AddressValidator::Callback> validated_; +// }; +class AddressValidator { + public: + typedef i18n::addressinput::Callback<const AddressData&, + const FieldProblemMap&> Callback; + + // Does not take ownership of |supplier|. + AddressValidator(Supplier* supplier); + + ~AddressValidator(); + + // Validates the |address| and populates |problems| with the validation + // problems, filtered according to the |filter| parameter. + // + // Set |allow_postal| to allow postal addresses, rather than only addresses + // describing physical locations. + // + // Set |require_name| if recipient should be considered a required field. + // + // If the |filter| is NULL or empty, then all discovered validation problems + // are returned. If the |filter| contains problem elements, then only those + // field-problem pairs present in the |filter| will be returned. + // + // Calls the |validated| callback when validation is done. All objects passed + // as parameters must be kept available until the callback has been called. + // + // The |success| parameter of the callback indicates whether it was possible + // to perform validation. If |success| is true, then |problems| will contain + // information about any problems found with the |address|. + void Validate(const AddressData& address, + bool allow_postal, + bool require_name, + const FieldProblemMap* filter, + FieldProblemMap* problems, + const Callback& validated) const; + + private: + Supplier* const supplier_; + + DISALLOW_COPY_AND_ASSIGN(AddressValidator); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_VALIDATOR_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h new file mode 100644 index 00000000000..d8c4ea65efb --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/callback.h @@ -0,0 +1,95 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// An object to store a pointer to a method in an object with the following +// signature: +// +// void Observer::ObserveEvent(bool success, Key key, Data data); + +#ifndef I18N_ADDRESSINPUT_CALLBACK_H_ +#define I18N_ADDRESSINPUT_CALLBACK_H_ + +#include <cassert> +#include <cstddef> + +namespace i18n { +namespace addressinput { + +// Stores a pointer to a method in an object. Sample usage: +// class MyClass { +// public: +// typedef Callback<const MyType&, const MyDataType&> MyCallback; +// +// void GetDataAsynchronously() { +// scoped_ptr<MyCallback> callback(BuildCallback( +// this, &MyClass::OnDataReady)); +// bool success = ... +// MyKeyType key = ... +// MyDataType data = ... +// (*callback)(success, key, data); +// } +// +// void OnDataReady(bool success, +// const MyKeyType& key, +// const MyDataType& data) { +// ... +// } +// }; +template <typename Key, typename Data> +class Callback { + public: + virtual ~Callback() {} + virtual void operator()(bool success, Key key, Data data) const = 0; +}; + +namespace { + +template <typename Observer, typename Key, typename Data> +class CallbackImpl : public Callback<Key, Data> { + public: + typedef void (Observer::*ObserveEvent)(bool, Key, Data); + + CallbackImpl(Observer* observer, ObserveEvent observe_event) + : observer_(observer), + observe_event_(observe_event) { + assert(observer_ != NULL); + assert(observe_event_ != NULL); + } + + virtual ~CallbackImpl() {} + + virtual void operator()(bool success, Key key, Data data) const { + (observer_->*observe_event_)(success, key, data); + } + + private: + Observer* observer_; + ObserveEvent observe_event_; +}; + +} // namespace + +// Returns a callback to |observer->observe_event| method. The caller owns the +// result. +template <typename Observer, typename Key, typename Data> +Callback<Key, Data>* BuildCallback( + Observer* observer, + void (Observer::*observe_event)(bool, Key, Data)) { + return new CallbackImpl<Observer, Key, Data>(observer, observe_event); +} + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_CALLBACK_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h new file mode 100644 index 00000000000..5e7896d9f10 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h @@ -0,0 +1,94 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_LOCALIZATION_H_ +#define I18N_ADDRESSINPUT_LOCALIZATION_H_ + +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_problem.h> +#include <libaddressinput/util/basictypes.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +struct AddressData; + +// The object to retrieve localized strings based on message IDs. It returns +// English by default. Sample usage: +// Localization localization; +// std::string best_language_tag; +// Process(BuildComponents("CA", localization, "en-US", &best_language_tag)); +// +// Alternative usage: +// Localization localization; +// localization.SetGetter(&MyStringGetter); +// std::string best_language_tag; +// Process(BuildComponents("CA", localization, "fr-CA", &best_language_tag)); +class Localization { + public: + // Initializes with English messages by default. + Localization(); + ~Localization(); + + // Returns the localized string for |message_id|. Returns an empty string if + // there's no message with this identifier. + std::string GetString(int message_id) const; + + // Returns the error message. If |enable_examples| is false, then the error + // message will not contain examples of valid input. If |enable_links| is + // false, then the error message will not contain HTML links. (Some error + // messages contain postal code examples or link to post office websites to + // look up the postal code for an address). Vector field values (e.g. for + // street address) should not be empty if problem is UNKNOWN_VALUE. The + // POSTAL_CODE field should only be used with MISSING_REQUIRED_FIELD, + // INVALID_FORMAT, and MISMATCHING_VALUE problem codes. All other fields + // should only be used with MISSING_REQUIRED_FIELD, UNKNOWN_VALUE, and + // USES_P_O_BOX problem codes. + std::string GetErrorMessage(const AddressData& address, + AddressField field, + AddressProblem problem, + bool enable_examples, + bool enable_links) const; + + // Sets the string getter that takes a message identifier and returns the + // corresponding localized string. For example, in Chromium there is + // l10n_util::GetStringUTF8 which always returns strings in the current + // application locale. + void SetGetter(std::string (*getter)(int)); + + private: + // Returns the error message where the address field is a postal code. Helper + // to |GetErrorMessage|. If |postal_code_example| is empty, then the error + // message will not contain examples of valid postal codes. If + // |post_service_url| is empty, then the error message will not contain a post + // service URL. The problem should only be one of MISSING_REQUIRED_FIELD, + // INVALID_FORMAT, or MISMATCHING_VALUE. + std::string GetErrorMessageForPostalCode(const AddressData& address, + AddressProblem problem, + bool uses_postal_code_as_label, + std::string postal_code_example, + std::string post_service_url) const; + + // The string getter. + std::string (*get_string_)(int); + + DISALLOW_COPY_AND_ASSIGN(Localization); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_LOCALIZATION_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h new file mode 100644 index 00000000000..66d9ab5216e --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h @@ -0,0 +1,48 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// It is not always desirable to cache libaddressinput data. Sometimes it might +// give better performance characteristics to not cache. This implementation of +// the Storage interface therefore doesn't actually store anything. + +#ifndef I18N_ADDRESSINPUT_NULL_STORAGE_H_ +#define I18N_ADDRESSINPUT_NULL_STORAGE_H_ + +#include <libaddressinput/storage.h> +#include <libaddressinput/util/basictypes.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +class NullStorage : public Storage { + public: + NullStorage(); + virtual ~NullStorage(); + + // No-op. + virtual void Put(const std::string& key, std::string* data); + + // Always calls the |data_ready| callback function signalling failure. + virtual void Get(const std::string& key, const Callback& data_ready) const; + + private: + DISALLOW_COPY_AND_ASSIGN(NullStorage); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_NULL_STORAGE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/ondemand_supplier.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/ondemand_supplier.h new file mode 100644 index 00000000000..6212d34b6e3 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/ondemand_supplier.h @@ -0,0 +1,66 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ONDEMAND_SUPPLIER_H_ +#define I18N_ADDRESSINPUT_ONDEMAND_SUPPLIER_H_ + +#include <libaddressinput/callback.h> +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <map> +#include <string> + +namespace i18n { +namespace addressinput { + +class LookupKey; +class Retriever; +class Rule; +class Source; +class Storage; + +// An implementation of the Supplier interface that owns a Retriever object, +// through which it loads address metadata as needed, creating Rule objects and +// caching these. +// +// When using an OndemandSupplier, address validation will benefit from address +// metadata server synonym resolution, because the server will be contacted for +// every new LookupKey (ie. every LookupKey that isn't on canonical form and +// isn't already cached). +// +// The maximum size of this cache is naturally limited to the amount of data +// available from the data server. (Currently this is less than 12,000 items of +// in total less than 2 MB of JSON data.) +class OndemandSupplier : public Supplier { + public: + // Takes ownership of |source| and |storage|. + OndemandSupplier(const Source* source, Storage* storage); + virtual ~OndemandSupplier(); + + // Loads the metadata needed for |lookup_key|, then calls |supplied|. + virtual void Supply(const LookupKey& lookup_key, const Callback& supplied); + + private: + const scoped_ptr<const Retriever> retriever_; + std::map<std::string, const Rule*> rule_cache_; + + DISALLOW_COPY_AND_ASSIGN(OndemandSupplier); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ONDEMAND_SUPPLIER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h new file mode 100644 index 00000000000..5987c7980da --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/preload_supplier.h @@ -0,0 +1,103 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_PRELOAD_SUPPLIER_H_ +#define I18N_ADDRESSINPUT_PRELOAD_SUPPLIER_H_ + +#include <libaddressinput/callback.h> +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <map> +#include <set> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +class IndexMap; +class LookupKey; +class Retriever; +class Rule; +class Source; +class Storage; + +// An implementation of the Supplier interface that owns a Retriever object, +// through which it can load aggregated address metadata for a region when +// instructed to, creating Rule objects and caching these. It also provides +// methods to check whether metadata for a particular region is already loaded +// or in progress of being loaded. +// +// When using a PreloadSupplier, it becomes possible to do synchronous address +// validation using an asynchronous Source, and to have full control over when +// network access is being done. +// +// The maximum size of this cache is naturally limited to the amount of data +// available from the data server. (Currently this is less than 12,000 items of +// in total less than 2 MB of JSON data.) +class PreloadSupplier : public Supplier { + public: + typedef i18n::addressinput::Callback<const std::string&, int> Callback; + + // Takes ownership of |source| and |storage|. + PreloadSupplier(const Source* source, Storage* storage); + virtual ~PreloadSupplier(); + + // Collects the metadata needed for |lookup_key| from the cache, then calls + // |supplied|. If the metadata needed isn't found in the cache, it will call + // the callback with status false. + virtual void Supply(const LookupKey& lookup_key, + const Supplier::Callback& supplied); + + // Should be called only when IsLoaded() returns true for the region code of + // the |lookup_key|. Can return NULL if the |lookup_key| does not correspond + // to any rule data. The caller does not own the result. + const Rule* GetRule(const LookupKey& lookup_key) const; + + // Loads all address metadata available for |region_code|. (A typical data + // size is 10 kB. The largest is 250 kB.) + // + // If the rules are already in progress of being loaded, it does nothing. + // Calls |loaded| when the loading has finished. + void LoadRules(const std::string& region_code, const Callback& loaded); + + // Returns a mapping of lookup keys to rules. Should be called only when + // IsLoaded() returns true for the |region_code|. + const std::map<std::string, const Rule*>& GetRulesForRegion( + const std::string& region_code) const; + + bool IsLoaded(const std::string& region_code) const; + bool IsPending(const std::string& region_code) const; + + private: + bool GetRuleHierarchy(const LookupKey& lookup_key, + RuleHierarchy* hierarchy) const; + bool IsLoadedKey(const std::string& key) const; + bool IsPendingKey(const std::string& key) const; + + const scoped_ptr<const Retriever> retriever_; + std::set<std::string> pending_; + const scoped_ptr<IndexMap> rule_index_; + std::vector<const Rule*> rule_storage_; + std::map<std::string, std::map<std::string, const Rule*> > region_rules_; + + DISALLOW_COPY_AND_ASSIGN(PreloadSupplier); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_PRELOAD_SUPPLIER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/region_data.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/region_data.h new file mode 100644 index 00000000000..92438dc6787 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/region_data.h @@ -0,0 +1,77 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_REGION_DATA_H_ +#define I18N_ADDRESSINPUT_REGION_DATA_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +// The key and name of a region that can be used as one of the items in a +// dropdown UI element. +class RegionData { + public: + // Creates a top-level RegionData object. Use AddSubRegion() to add data below + // it. Does not make a copy of data in |region_code|. + explicit RegionData(const std::string& region_code); + + ~RegionData(); + + // Creates a sub-level RegionData object, with this object as its parent and + // owner. Does not make copies of the data in |key| or |name|. + RegionData* AddSubRegion(const std::string& key, const std::string& name); + + const std::string& key() const { return key_; } + + const std::string& name() const { return name_; } + + bool has_parent() const { return parent_ != NULL; } + + // Should be called only if has_parent() returns true. + const RegionData& parent() const { + assert(parent_ != NULL); + return *parent_; + } + + // The caller does not own the results. The results are not NULL and have a + // parent. + const std::vector<const RegionData*>& sub_regions() const { + return sub_regions_; + } + + private: + // Private constructor used by AddSubRegion(). + RegionData(const std::string& key, + const std::string& name, + RegionData* parent); + + const std::string& key_; + const std::string& name_; + const RegionData* const parent_; // Not owned. + std::vector<const RegionData*> sub_regions_; // Owned. + + DISALLOW_COPY_AND_ASSIGN(RegionData); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_REGION_DATA_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h new file mode 100644 index 00000000000..906ca36fa3a --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h @@ -0,0 +1,80 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_REGION_DATA_BUILDER_H_ +#define I18N_ADDRESSINPUT_REGION_DATA_BUILDER_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <map> +#include <string> + +namespace i18n { +namespace addressinput { + +class PreloadSupplier; +class RegionData; + +class RegionDataBuilder { + public: + // Does not take ownership of |supplier|, which should not be NULL. + explicit RegionDataBuilder(PreloadSupplier* supplier); + ~RegionDataBuilder(); + + // Returns a tree of administrative subdivisions for the |region_code|. + // Examples: + // US with en-US UI language. + // |______________________ + // | | | + // v v v + // AL:Alabama AK:Alaska AS:American Samoa ... + // + // KR with ko-Latn UI language. + // |______________________________________ + // | | | + // v v v + // 강원도:Gangwon 경기도:Gyeonggi 경상남도:Gyeongnam ... + // + // KR with ko-KR UI language. + // |_______________________________ + // | | | + // v v v + // 강원도:강원 경기도:경기 경상남도:경남 ... + // + // The BCP 47 |ui_language_tag| is used to choose the best supported language + // tag for this region (assigned to |best_region_tree_language_tag|). For + // example, Canada has both English and French names for its administrative + // subdivisions. If the UI language is French, then the French names are used. + // The |best_region_tree_language_tag| value may be an empty string. + // + // Should be called only if supplier->IsLoaded(region_code) returns true. The + // |best_region_tree_language_tag| parameter should not be NULL. + const RegionData& Build(const std::string& region_code, + const std::string& ui_language_tag, + std::string* best_region_tree_language_tag); + + private: + typedef std::map<std::string, const RegionData*> LanguageRegionMap; + typedef std::map<std::string, LanguageRegionMap*> RegionCodeDataMap; + + PreloadSupplier* const supplier_; // Not owned. + RegionCodeDataMap cache_; + + DISALLOW_COPY_AND_ASSIGN(RegionDataBuilder); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_REGION_DATA_BUILDER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/source.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/source.h new file mode 100644 index 00000000000..4d91b68565b --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/source.h @@ -0,0 +1,56 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// The interface to be implemented by the user of the library to access address +// metadata, typically by downloading this from the address metadata server or +// by linking the metadata into the binary. + +#ifndef I18N_ADDRESSINPUT_SOURCE_H_ +#define I18N_ADDRESSINPUT_SOURCE_H_ + +#include <libaddressinput/callback.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +// Gets address metadata. The callback data must be allocated on the heap, +// passing ownership to the callback. Sample usage: +// +// class MySource : public Source { +// public: +// virtual void Get(const std::string& key, +// const Callback& data_ready) const { +// bool success = ... +// std::string* data = new ... +// data_ready(success, key, data); +// } +// }; +class Source { + public: + typedef i18n::addressinput::Callback<const std::string&, + std::string*> Callback; + + virtual ~Source() {} + + // Gets metadata for |key| and invokes the |data_ready| callback. + virtual void Get(const std::string& key, + const Callback& data_ready) const = 0; +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_SOURCE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h new file mode 100644 index 00000000000..94ad13bdd20 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h @@ -0,0 +1,64 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// The interface to be implemented by the user of the library to enable storing +// address metadata (e.g. on disk). + +#ifndef I18N_ADDRESSINPUT_STORAGE_H_ +#define I18N_ADDRESSINPUT_STORAGE_H_ + +#include <libaddressinput/callback.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +// Stores address metadata. The data must be allocated on the heap, passing +// ownership to the called function. Sample usage: +// +// class MyStorage : public Storage { +// public: +// virtual void Put(const std::string& key, std::string* data) { +// ... +// delete data; +// } +// +// virtual void Get(const std::string& key, +// const Callback& data_ready) const { +// bool success = ... +// std::string* data = new ... +// data_ready(success, key, data); +// } +// }; +class Storage { + public: + typedef i18n::addressinput::Callback<const std::string&, + std::string*> Callback; + + virtual ~Storage() {} + + // Stores |data| for |key|, where |data| is an object allocated on the heap, + // which Storage takes ownership of. + virtual void Put(const std::string& key, std::string* data) = 0; + + // Retrieves the data for |key| and invokes the |data_ready| callback. + virtual void Get(const std::string& key, + const Callback& data_ready) const = 0; +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_STORAGE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/supplier.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/supplier.h new file mode 100644 index 00000000000..7d079cff450 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/supplier.h @@ -0,0 +1,54 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_SUPPLIER_H_ +#define I18N_ADDRESSINPUT_SUPPLIER_H_ + +#include <libaddressinput/callback.h> + +namespace i18n { +namespace addressinput { + +class LookupKey; +class Rule; + +// Interface for objects that are able to supply the AddressValidator with the +// metadata needed to validate an address, as described by a LookupKey. +class Supplier { + public: + struct RuleHierarchy; + typedef i18n::addressinput::Callback<const LookupKey&, + const RuleHierarchy&> Callback; + + virtual ~Supplier() {} + + // Aggregates the metadata needed for |lookup_key| into a RuleHierarchy + // object, then calls |supplied|. Implementations of this interface may + // either load the necessary data on demand, or fail if the necessary data + // hasn't already been loaded. + virtual void Supply(const LookupKey& lookup_key, + const Callback& supplied) = 0; + + // A RuleHierarchy object encapsulates the hierarchical list of Rule objects + // that corresponds to a particular LookupKey. + struct RuleHierarchy { + RuleHierarchy() : rule() {} + const Rule* rule[4]; // Cf. LookupKey::kHierarchy. + }; +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_SUPPLIER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/basictypes.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/basictypes.h new file mode 100644 index 00000000000..663133fc0a9 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/basictypes.h @@ -0,0 +1,213 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// https://code.google.com/p/libphonenumber/source/browse/trunk/cpp/src/phonenumbers/base/basictypes.h?r=621 + +#if I18N_ADDRESSINPUT_USE_BASICTYPES_OVERRIDE + +// If building libaddressinput in an environment where there already is another +// implementation of the basictypes.h header file (like in Chromium), then pass +// the command line flag -DI18N_ADDRESSINPUT_USE_BASICTYPES_OVERRIDE=1 to the +// compiler and provide a file named basictypes_override.h, in a location where +// the compiler will look for it, which provides the desired implementation. + +#include "basictypes_override.h" + +#else + +#ifndef I18N_ADDRESSINPUT_UTIL_BASICTYPES_H_ +#define I18N_ADDRESSINPUT_UTIL_BASICTYPES_H_ + +#include <climits> // So we can set the bounds of our types +#include <cstddef> // For size_t + +#if !defined(_WIN32) +// stdint.h is part of C99 but MSVC doesn't have it. +#include <stdint.h> // For intptr_t. +#endif + +#ifdef INT64_MAX + +// INT64_MAX is defined if C99 stdint.h is included; use the +// native types if available. +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +const uint8 kuint8max = UINT8_MAX; +const uint16 kuint16max = UINT16_MAX; +const uint32 kuint32max = UINT32_MAX; +const uint64 kuint64max = UINT64_MAX; +const int8 kint8min = INT8_MIN; +const int8 kint8max = INT8_MAX; +const int16 kint16min = INT16_MIN; +const int16 kint16max = INT16_MAX; +const int32 kint32min = INT32_MIN; +const int32 kint32max = INT32_MAX; +const int64 kint64min = INT64_MIN; +const int64 kint64max = INT64_MAX; + +#else // !INT64_MAX + +typedef signed char int8; +typedef short int16; +// TODO: Remove these type guards. These are to avoid conflicts with +// obsolete/protypes.h in the Gecko SDK. +#ifndef _INT32 +#define _INT32 +typedef int int32; +#endif + +// The NSPR system headers define 64-bit as |long| when possible. In order to +// not have typedef mismatches, we do the same on LP64. +#if __LP64__ +typedef long int64; +#else +typedef long long int64; +#endif + +// NOTE: unsigned types are DANGEROUS in loops and other arithmetical +// places. Use the signed types unless your variable represents a bit +// pattern (eg a hash value) or you really need the extra bit. Do NOT +// use 'unsigned' to express "this value should always be positive"; +// use assertions for this. + +typedef unsigned char uint8; +typedef unsigned short uint16; +// TODO: Remove these type guards. These are to avoid conflicts with +// obsolete/protypes.h in the Gecko SDK. +#ifndef _UINT32 +#define _UINT32 +typedef unsigned int uint32; +#endif + +// See the comment above about NSPR and 64-bit. +#if __LP64__ +typedef unsigned long uint64; +#else +typedef unsigned long long uint64; +#endif + +#endif // !INT64_MAX + +typedef signed char schar; + +// A type to represent a Unicode code-point value. As of Unicode 4.0, +// such values require up to 21 bits. +// (For type-checking on pointers, make this explicitly signed, +// and it should always be the signed version of whatever int32 is.) +typedef signed int char32; + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#if !defined(DISALLOW_COPY_AND_ASSIGN) +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// +// One caveat is that arraysize() doesn't accept any array of an +// anonymous type or a type defined inside a function. In these rare +// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is +// due to a limitation in C++'s template system. The limitation might +// eventually be removed, but it hasn't happened yet. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template <typename T, size_t N> +char (&ArraySizeHelper(T (&array)[N]))[N]; + +// That gcc wants both of these prototypes seems mysterious. VC, for +// its part, can't decide which to use (another mystery). Matching of +// template overloads: the final frontier. +#ifndef _MSC_VER +template <typename T, size_t N> +char (&ArraySizeHelper(const T (&array)[N]))[N]; +#endif + +#if !defined(arraysize) +#define arraysize(array) (sizeof(ArraySizeHelper(array))) +#endif + +// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize, +// but can be used on anonymous types or types defined inside +// functions. It's less safe than arraysize as it accepts some +// (although not all) pointers. Therefore, you should use arraysize +// whenever possible. +// +// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type +// size_t. +// +// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error +// +// "warning: division by zero in ..." +// +// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer. +// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays. +// +// The following comments are on the implementation details, and can +// be ignored by the users. +// +// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in +// the array) and sizeof(*(arr)) (the # of bytes in one array +// element). If the former is divisible by the latter, perhaps arr is +// indeed an array, in which case the division result is the # of +// elements in the array. Otherwise, arr cannot possibly be an array, +// and we generate a compiler error to prevent the code from +// compiling. +// +// Since the size of bool is implementation-defined, we need to cast +// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final +// result has type size_t. +// +// This macro is not perfect as it wrongfully accepts certain +// pointers, namely where the pointer size is divisible by the pointee +// size. Since all our code has to go through a 32-bit compiler, +// where a pointer is 4 bytes, this means all pointers to a type whose +// size is 3 or greater than 4 will be (righteously) rejected. + +#if !defined(ARRAYSIZE_UNSAFE) +#define ARRAYSIZE_UNSAFE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) +#endif + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template <bool> +struct CompileAssert { +}; + +#if !defined(COMPILE_ASSERT) +#define COMPILE_ASSERT(expr, msg) \ + typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] +#endif + +#endif // I18N_ADDRESSINPUT_UTIL_BASICTYPES_H_ +#endif // I18N_ADDRESSINPUT_USE_BASICTYPES_OVERRIDE diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/scoped_ptr.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/scoped_ptr.h new file mode 100644 index 00000000000..a88c2a9f6ab --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/scoped_ptr.h @@ -0,0 +1,444 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// https://code.google.com/p/libphonenumber/source/browse/trunk/cpp/src/phonenumbers/base/memory/scoped_ptr.h?r=621 + +#ifndef I18N_ADDRESSINPUT_UTIL_SCOPED_PTR_H_ +#define I18N_ADDRESSINPUT_UTIL_SCOPED_PTR_H_ + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class and scoped_ptr_malloc (deprecated). + +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/template_util.h> + +#include <algorithm> // For std::swap(). +#include <cassert> +#include <cstddef> +#include <cstdlib> + +namespace i18n { +namespace addressinput { + +// Function object which deletes its parameter, which must be a pointer. +// If C is an array type, invokes 'delete[]' on the parameter; otherwise, +// invokes 'delete'. The default deleter for scoped_ptr<T>. +template <class T> +struct DefaultDeleter { + DefaultDeleter() {} + template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) { + // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor + // if U* is implicitly convertible to T* and U is not an array type. + // + // Correct implementation should use SFINAE to disable this + // constructor. However, since there are no other 1-argument constructors, + // using a COMPILE_ASSERT() based on is_convertible<> and requiring + // complete types is simpler and will cause compile failures for equivalent + // misuses. + // + // Note, the is_convertible<U*, T*> check also ensures that U is not an + // array. T is guaranteed to be a non-array, so any U* where U is an array + // cannot convert to T*. + enum { T_must_be_complete = sizeof(T) }; + enum { U_must_be_complete = sizeof(U) }; + COMPILE_ASSERT((is_convertible<U*, T*>::value), + U_ptr_must_implicitly_convert_to_T_ptr); + } + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete ptr; + } +}; + +// Specialization of DefaultDeleter for array types. +template <class T> +struct DefaultDeleter<T[]> { + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete[] ptr; + } + + private: + // Disable this operator for any U != T because it is undefined to execute + // an array delete when the static type of the array mismatches the dynamic + // type. + // + // References: + // C++98 [expr.delete]p3 + // http://cplusplus.github.com/LWG/lwg-defects.html#938 + template <typename U> void operator()(U* array) const; +}; + +template <class T, int n> +struct DefaultDeleter<T[n]> { + // Never allow someone to declare something like scoped_ptr<int[10]>. + COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type); +}; + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr: +// +// scoped_ptr<int, base::FreeDeleter> foo_ptr( +// static_cast<int*>(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { + free(ptr); + } +}; + +// Minimal implementation of the core logic of scoped_ptr, suitable for +// reuse in both scoped_ptr and its specializations. +template <class T, class D> +class scoped_ptr_impl { + public: + explicit scoped_ptr_impl(T* p) : data_(p) { } + + // Initializer for deleters that have data parameters. + scoped_ptr_impl(T* p, const D& d) : data_(p, d) {} + + // Templated constructor that destructively takes the value from another + // scoped_ptr_impl. + template <typename U, typename V> + scoped_ptr_impl(scoped_ptr_impl<U, V>* other) + : data_(other->release(), other->get_deleter()) { + // We do not support move-only deleters. We could modify our move + // emulation to have base::subtle::move() and base::subtle::forward() + // functions that are imperfect emulations of their C++11 equivalents, + // but until there's a requirement, just assume deleters are copyable. + } + + template <typename U, typename V> + void TakeState(scoped_ptr_impl<U, V>* other) { + // See comment in templated constructor above regarding lack of support + // for move-only deleters. + reset(other->release()); + get_deleter() = other->get_deleter(); + } + + ~scoped_ptr_impl() { + if (data_.ptr != NULL) { + // Not using get_deleter() saves one function call in non-optimized + // builds. + static_cast<D&>(data_)(data_.ptr); + } + } + + void reset(T* p) { + // This is a self-reset, which is no longer allowed: http://crbug.com/162971 + if (p != NULL && p == data_.ptr) + abort(); + + // Note that running data_.ptr = p can lead to undefined behavior if + // get_deleter()(get()) deletes this. In order to pevent this, reset() + // should update the stored pointer before deleting its old value. + // + // However, changing reset() to use that behavior may cause current code to + // break in unexpected ways. If the destruction of the owned object + // dereferences the scoped_ptr when it is destroyed by a call to reset(), + // then it will incorrectly dispatch calls to |p| rather than the original + // value of |data_.ptr|. + // + // During the transition period, set the stored pointer to NULL while + // deleting the object. Eventually, this safety check will be removed to + // prevent the scenario initially described from occuring and + // http://crbug.com/176091 can be closed. + T* old = data_.ptr; + data_.ptr = NULL; + if (old != NULL) + static_cast<D&>(data_)(old); + data_.ptr = p; + } + + T* get() const { return data_.ptr; } + + D& get_deleter() { return data_; } + const D& get_deleter() const { return data_; } + + void swap(scoped_ptr_impl& p2) { + // Standard swap idiom: 'using std::swap' ensures that std::swap is + // present in the overload set, but we call swap unqualified so that + // any more-specific overloads can be used, if available. + using std::swap; + swap(static_cast<D&>(data_), static_cast<D&>(p2.data_)); + swap(data_.ptr, p2.data_.ptr); + } + + T* release() { + T* old_ptr = data_.ptr; + data_.ptr = NULL; + return old_ptr; + } + + private: + // Needed to allow type-converting constructor. + template <typename U, typename V> friend class scoped_ptr_impl; + + // Use the empty base class optimization to allow us to have a D + // member, while avoiding any space overhead for it when D is an + // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good + // discussion of this technique. + struct Data : public D { + explicit Data(T* ptr_in) : ptr(ptr_in) {} + Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {} + T* ptr; + }; + + Data data_; + + DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl); +}; + +// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T> +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr<T> owns the T object that it points to. +// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object. +// Also like T*, scoped_ptr<T> is thread-compatible, and once you +// dereference it, you get the thread safety guarantees of T. +// +// The size of scoped_ptr is small. On most compilers, when using the +// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will +// increase the size proportional to whatever state they need to have. See +// comments inside scoped_ptr_impl<> for details. +// +// Current implementation targets having a strict subset of C++11's +// unique_ptr<> features. Known deficiencies include not supporting move-only +// deleteres, function pointers as deleters, and deleters with reference +// types. +template <class T, class D = DefaultDeleter<T> > +class scoped_ptr { + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with NULL. + scoped_ptr() : impl_(NULL) { } + + // Constructor. Takes ownership of p. + explicit scoped_ptr(element_type* p) : impl_(p) { } + + // Constructor. Allows initialization of a stateful deleter. + scoped_ptr(element_type* p, const D& d) : impl_(p, d) { } + + // Constructor. Allows construction from a scoped_ptr rvalue for a + // convertible type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct + // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor + // has different post-conditions if D is a reference type. Since this + // implementation does not support deleters with reference type, + // we do not need a separate move constructor allowing us to avoid one + // use of SFINAE. You only need to care about this if you modify the + // implementation of scoped_ptr. + template <typename U, typename V> + scoped_ptr(scoped_ptr<U, V> other) : impl_(&other.impl_) { + COMPILE_ASSERT(!is_array<U>::value, U_cannot_be_an_array); + } + + // operator=. Allows assignment from a scoped_ptr rvalue for a convertible + // type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from + // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated + // form has different requirements on for move-only Deleters. Since this + // implementation does not support move-only Deleters, we do not need a + // separate move assignment operator allowing us to avoid one use of SFINAE. + // You only need to care about this if you modify the implementation of + // scoped_ptr. + template <typename U, typename V> + scoped_ptr& operator=(scoped_ptr<U, V> rhs) { + COMPILE_ASSERT(!is_array<U>::value, U_cannot_be_an_array); + impl_.TakeState(&rhs.impl_); + return *this; + } + + // Reset. Deletes the currently owned object, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* p = NULL) { impl_.reset(p); } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + element_type& operator*() const { + assert(impl_.get() != NULL); + return *impl_.get(); + } + element_type* operator->() const { + assert(impl_.get() != NULL); + return impl_.get(); + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr<element_type> to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + private: + typedef scoped_ptr_impl<element_type, deleter_type> scoped_ptr::*Testable; + + public: + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(const element_type* p) const { return impl_.get() == p; } + bool operator!=(const element_type* p) const { return impl_.get() != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + element_type* release() { + return impl_.release(); + } + + private: + // Needed to reach into |impl_| in the constructor. + template <typename U, typename V> friend class scoped_ptr; + scoped_ptr_impl<element_type, deleter_type> impl_; + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template <class U> bool operator==(scoped_ptr<U> const& p2) const; + template <class U> bool operator!=(scoped_ptr<U> const& p2) const; +}; + +template <class T, class D> +class scoped_ptr<T[], D> { + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with NULL. + scoped_ptr() : impl_(NULL) { } + + // Constructor. Stores the given array. Note that the argument's type + // must exactly match T*. In particular: + // - it cannot be a pointer to a type derived from T, because it is + // inherently unsafe in the general case to access an array through a + // pointer whose dynamic type does not match its static type (eg., if + // T and the derived types had different sizes access would be + // incorrectly calculated). Deletion is also always undefined + // (C++98 [expr.delete]p3). If you're doing this, fix your code. + // - it cannot be NULL, because NULL is an integral expression, not a + // pointer to T. Use the no-argument version instead of explicitly + // passing NULL. + // - it cannot be const-qualified differently from T per unique_ptr spec + // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting + // to work around this may use implicit_cast<const T*>(). + // However, because of the first bullet in this comment, users MUST + // NOT use implicit_cast<Base*>() to upcast the static type of the array. + explicit scoped_ptr(element_type* array) : impl_(array) { } + + // Reset. Deletes the currently owned array, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* array = NULL) { impl_.reset(array); } + + // Accessors to get the owned array. + element_type& operator[](size_t i) const { + assert(impl_.get() != NULL); + return impl_.get()[i]; + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr<element_type> to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + private: + typedef scoped_ptr_impl<element_type, deleter_type> scoped_ptr::*Testable; + + public: + operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(element_type* array) const { return impl_.get() == array; } + bool operator!=(element_type* array) const { return impl_.get() != array; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + element_type* release() { + return impl_.release(); + } + + private: + // Force element_type to be a complete type. + enum { type_must_be_complete = sizeof(element_type) }; + + // Actually hold the data. + scoped_ptr_impl<element_type, deleter_type> impl_; + + // Disable initialization from any type other than element_type*, by + // providing a constructor that matches such an initialization, but is + // private and has no definition. This is disabled because it is not safe to + // call delete[] on an array whose static type does not match its dynamic + // type. + template <typename U> explicit scoped_ptr(U* array); + explicit scoped_ptr(int disallow_construction_from_null); + + // Disable reset() from any type other than element_type*, for the same + // reasons as the constructor above. + template <typename U> void reset(U* array); + void reset(int disallow_reset_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template <class U> bool operator==(scoped_ptr<U> const& p2) const; + template <class U> bool operator!=(scoped_ptr<U> const& p2) const; +}; + +// Free functions +template <class T, class D> +void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) { + p1.swap(p2); +} + +template <class T, class D> +bool operator==(T* p1, const scoped_ptr<T, D>& p2) { + return p1 == p2.get(); +} + +template <class T, class D> +bool operator!=(T* p1, const scoped_ptr<T, D>& p2) { + return p1 != p2.get(); +} + +// A function to convert T* into scoped_ptr<T> +// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation +// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg)) +template <typename T> +scoped_ptr<T> make_scoped_ptr(T* ptr) { + return scoped_ptr<T>(ptr); +} + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_SCOPED_PTR_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/template_util.h b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/template_util.h new file mode 100644 index 00000000000..35125e12d0b --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/include/libaddressinput/util/template_util.h @@ -0,0 +1,111 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// https://code.google.com/p/libphonenumber/source/browse/trunk/cpp/src/phonenumbers/base/template_util.h?r=621 + +#ifndef I18N_ADDRESSINPUT_UTIL_TEMPLATE_UTIL_H_ +#define I18N_ADDRESSINPUT_UTIL_TEMPLATE_UTIL_H_ + +#include <cstddef> // For size_t. + +namespace i18n { +namespace addressinput { + +// template definitions from tr1 + +template<class T, T v> +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant<T, v> type; +}; + +template <class T, T v> const T integral_constant<T, v>::value; + +typedef integral_constant<bool, true> true_type; +typedef integral_constant<bool, false> false_type; + +template <class T> struct is_pointer : false_type {}; +template <class T> struct is_pointer<T*> : true_type {}; + +template <class T, class U> struct is_same : public false_type {}; +template <class T> struct is_same<T,T> : true_type {}; + +template<class> struct is_array : public false_type {}; +template<class T, size_t n> struct is_array<T[n]> : public true_type {}; +template<class T> struct is_array<T[]> : public true_type {}; + +template <class T> struct is_non_const_reference : false_type {}; +template <class T> struct is_non_const_reference<T&> : true_type {}; +template <class T> struct is_non_const_reference<const T&> : false_type {}; + +template <class T> struct is_void : false_type {}; +template <> struct is_void<void> : true_type {}; + +namespace internal { + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +struct ConvertHelper { + template <typename To> + static YesType Test(To); + + template <typename To> + static NoType Test(...); + + template <typename From> + static From& Create(); +}; + +// Used to determine if a type is a struct/union/class. Inspired by Boost's +// is_class type_trait implementation. +struct IsClassHelper { + template <typename C> + static YesType Test(void(C::*)(void)); + + template <typename C> + static NoType Test(...); +}; + +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +// +// Note that if the type is convertible, this will be a true_type REGARDLESS +// of whether or not the conversion would emit a warning. +template <typename From, typename To> +struct is_convertible + : integral_constant<bool, + sizeof(internal::ConvertHelper::Test<To>( + internal::ConvertHelper::Create<From>())) == + sizeof(internal::YesType)> { +}; + +template <typename T> +struct is_class + : integral_constant<bool, + sizeof(internal::IsClassHelper::Test<T>(0)) == + sizeof(internal::YesType)> { +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_TEMPLATE_UTIL_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/res/messages.grd b/chromium/third_party/libaddressinput/src/cpp/res/messages.grd new file mode 100644 index 00000000000..dd3aa64e8f1 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/res/messages.grd @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2013 Google Inc. + +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. +--> +<grit base_dir="." latest_public_release="0" current_release="1" + source_lang_id="en" enc_check="möl"> + <outputs> + <output filename="messages.h" type="rc_header" lang="en"> + <emit> + <!-- If the emit element is not specified, then the generated + messages.h includes an atlres.h file from Windows Template + Library (WTL). --> + </emit> + </output> + <output filename="en_messages.cc" lang="en" type="c_format" /> + </outputs> + <release seq="1" allow_pseudo="false"> + <messages fallback_to_english="true"> + <part file="messages.grdp" /> + </messages> + </release> +</grit> diff --git a/chromium/third_party/libaddressinput/src/cpp/res/messages.grdp b/chromium/third_party/libaddressinput/src/cpp/res/messages.grdp new file mode 100644 index 00000000000..ca893542bc6 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/res/messages.grdp @@ -0,0 +1,286 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2013 Google Inc. + +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. +--> +<grit-part> + <message + name="IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL" + desc="A country or a political region (Countries like the United States or + regions like Hong Kong or Macao, or places like Taiwan, where + whether it is a country or not is a politically sensitive + question)."> + Country / Region + </message> + <message + name="IDS_LIBADDRESSINPUT_LOCALITY_LABEL" + desc="E.g., New York City."> + City + </message> + <message + name="IDS_LIBADDRESSINPUT_POST_TOWN" + desc="The name of a town through + which postal deliveries are routed, present in UK addresses. + See: http://en.wikipedia.org/wiki/Post_town"> + Post Town + </message> + <message + name="IDS_LIBADDRESSINPUT_SUBURB" + desc="Smaller part of a city used in some addresses in countries like New + Zealand to give a more specific location in a postal address."> + Suburb + </message> + <message + name="IDS_LIBADDRESSINPUT_VILLAGE_TOWNSHIP" + desc="A unit used in postal addresses in Malaysia, which is smaller than the + city/town, and represents a village, township, or precinct."> + Village / Township + </message> + <message + name="IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL" + desc="E.g., 18th Street, Unit 3."> + Street address + </message> + <message + name="IDS_LIBADDRESSINPUT_PIN_CODE_LABEL" + desc="PIN (Postal Index Number) Code. Values are numeric. Used in India."> + PIN code + </message> + <message + name="IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL" + desc="Postal Code. Values are frequently alphanumeric. Used in countries + such as Switzerland."> + Postal code + </message> + <message + name="IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL" + desc="ZIP code. Values are frequently alphanumeric. Used in countries such + as the US."> + ZIP code + </message> + <message + name="IDS_LIBADDRESSINPUT_AREA" + desc="Administrative Area for Hong Kong (e.g., Kowloon)."> + Area + </message> + <message + name="IDS_LIBADDRESSINPUT_COUNTY" + desc="Administrative Area for United Kingdoms (e.g. York) or for the + United States (e.g. Orange County)."> + County + </message> + <message + name="IDS_LIBADDRESSINPUT_DEPARTMENT" + desc="Administrative Area for Nicaragua (e.g., Boaco) or France."> + Department + </message> + <message + name="IDS_LIBADDRESSINPUT_DISTRICT" + desc="Administrative Area for Nauru Central Pacific (e.g., Aiwo district), + or area of a town (a neighbourhood/suburb) used for addresses in + Korea and China."> + District + </message> + <message + name="IDS_LIBADDRESSINPUT_DO_SI" + desc="Administrative Area for Korea (e.g., Gyeonggi-do or Busan-si)."> + Do/Si + </message> + <message + name="IDS_LIBADDRESSINPUT_EMIRATE" + desc="Administrative Area for United Arab Emirates (e.g., Abu Dhabi)."> + Emirate + </message> + <message + name="IDS_LIBADDRESSINPUT_ISLAND" + desc="Administrative Area for certain countries (e.g., Bahama's Cat + Island)."> + Island + </message> + <message + name="IDS_LIBADDRESSINPUT_OBLAST" + desc="Administrative Area for certain countries (e.g., Russia's + Leningrad)."> + Oblast + </message> + <message + name="IDS_LIBADDRESSINPUT_PARISH" + desc="Administrative Area for certain countries (e.g., Andorra's + Canillo)."> + Parish + </message> + <message + name="IDS_LIBADDRESSINPUT_PREFECTURE" + desc="Administrative Area for Japan (e.g., Hokkaido)."> + Prefecture + </message> + <message + name="IDS_LIBADDRESSINPUT_PROVINCE" + desc="Administrative Area for certain countries (e.g., France's + Champagne)."> + Province + </message> + <message + name="IDS_LIBADDRESSINPUT_STATE" + desc="Administrative Area for certain countries (e.g., US' California)."> + State + </message> + <message + name="IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL" + desc="Label for the field of organization, firm, company, or institution + in an address. Examples of values in this field: Google, + Department of Transportation, University of Cambridge."> + Organization + </message> + <message + name="IDS_LIBADDRESSINPUT_RECIPIENT_LABEL" + desc="Label for the field for a person's name in an address."> + Name + </message> + <message + name="IDS_LIBADDRESSINPUT_NEIGHBORHOOD" + desc="Label for a neighborhood, shown as part of an address input form."> + Neighborhood + </message> + <message + name="IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD" + desc="Error message shown with a UI field when it is a required field and + the user has not filled it out."> + You can't leave this empty. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL" + desc="Error message shown with the postal code field when it is a required + field and the user has not filled it out, providing an example + postal code and a link to this country's postal service that a user + can use to look up their postal code."> + You must provide a postal code, for example <ph name="EXAMPLE">$1<ex>90291</ex></ph>. Don't know your postal code? Find it out <ph name="BEGIN_LINK">$2</ph>here<ph name="END_LINK">$3</ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE" + desc="Error message shown with the postal code field when it is a required + field and the user has not filled it out, providing an example + postal code."> + You must provide a postal code, for example <ph name="EXAMPLE">$1<ex>90291</ex></ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL" + desc="Error message shown with the ZIP code field when it is a required + field and the user has not filled it out, providing an example ZIP + code and a link to this country's postal service that a user can use + to look up their ZIP code. This is specifically for countries using + ZIP codes instead of Postal codes, such as America."> + You must provide a ZIP code, for example <ph name="EXAMPLE">$1<ex>90291</ex></ph>. Don't know your ZIP code? Find it out <ph name="BEGIN_LINK">$2</ph>here<ph name="END_LINK">$3</ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE" + desc="Error message shown with the ZIP code field when it is a required + field and the user has not filled it out, providing an example ZIP + code."> + You must provide a ZIP code, for example <ph name="EXAMPLE">$1<ex>90291</ex></ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNKNOWN_VALUE" + desc="Occurs when the user fills out the wrong value for an address field. + For example, this would be shown when putting 'Cupertino' in United + States' State field."> + <ph name="FIELD_VALUE">$1<ex>Cupertino</ex></ph> is not recognized as a known value for this field. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL" + desc="Occurs when the user fills out a postal code that does not conform + to the country's postal code format. For example, this would be + shown when using '80' as a Swiss postal code, which is normally 4 + digits long. Provides an example postal code and a link to this + country's postal service that a user can use to look up their postal + code."> + This postal code format is not recognized. Example of a valid postal code: <ph name="EXAMPLE">$1<ex>90291</ex></ph>. Don't know your postal code? Find it out <ph name="BEGIN_LINK">$2</ph>here<ph name="END_LINK">$3</ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE" + desc="Occurs when the user fills out a postal code that does not conform + to the country's postal code format. For example, this would be + shown when using '80' as a Swiss postal code, which is normally 4 + digits long. Provides an example postal code."> + This postal code format is not recognized. Example of a valid postal code: <ph name="EXAMPLE">$1<ex>90291</ex></ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE" + desc="Occurs when the user fills out a postal code that does not conform + to the country's postal code format. For example, this would be + shown when using '80' as a Swiss postal code, which is normally 4 + digits long."> + This postal code format is not recognized. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL" + desc="Occurs when the user fills out a ZIP code that does not conform to + the country's ZIP code format. For example, this would be shown when + using '901' as a ZIP code for the United States. Provides an example + ZIP code and a link to this country's postal service that a user can + use to look up their ZIP code."> + This ZIP code format is not recognized. Example of a valid ZIP code: <ph name="EXAMPLE">$1<ex>90291</ex></ph>. Don't know your ZIP code? Find it out <ph name="BEGIN_LINK">$2</ph>here<ph name="END_LINK">$3</ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE" + desc="Occurs when the user fills out a ZIP code that does not conform to + the country's ZIP code format. For example, this would be shown when + using '901' as a ZIP code for the United States. Provides an example + ZIP code."> + This ZIP code format is not recognized. Example of a valid ZIP code: <ph name="EXAMPLE">$1<ex>90291</ex></ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP" + desc="Occurs when the user fills out a ZIP code that does not conform to + the country's ZIP code format. For example, this would be shown when + using '901' as a ZIP code for the United States."> + This ZIP code format is not recognized. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL" + desc="Occurs when the user fills out the wrong postal code for a certain + location. For example, this would be shown when using Z3Z 2Y7 for + Alberta, Canada. Provides a link to this country's postal service + that a user can use to look up their postal code."> + This postal code does not appear to match the rest of this address. Don't know your postal code? Find it out <ph name="BEGIN_LINK">$1</ph>here<ph name="END_LINK">$2</ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE" + desc="Occurs when the user fills out the wrong postal code for a certain + location. For example, this would be shown when using Z3Z 2Y7 for + Alberta, Canada."> + This postal code does not appear to match the rest of this address. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL" + desc="Occurs when the user fills out the wrong ZIP code for a certain + location. For example, this would be shown when using 10001 for + Arizona state. Provides a link to this country's postal service that + a user can use to look up their ZIP code."> + This ZIP code does not appear to match the rest of this address. Don't know your ZIP code? Find it out <ph name="BEGIN_LINK">$1</ph>here<ph name="END_LINK">$2</ph>. + </message> + <message + name="IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP" + desc="Occurs when the user fills out the wrong ZIP code for a certain + location. For example, this would be shown when using 10001 for + Arizona state."> + This ZIP code does not appear to match the rest of this address. + </message> + <message + name="IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE" + desc="Occurs when the user fills out a P.O. box as part of a physical + address."> + This address line appears to contain a post office box. Please use a street or building address. + </message> +</grit-part> diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_data.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_data.cc new file mode 100644 index 00000000000..40d3ee76535 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_data.cc @@ -0,0 +1,153 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_data.h> + +#include <libaddressinput/address_field.h> +#include <libaddressinput/util/basictypes.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <ostream> +#include <string> +#include <vector> + +#include <re2/re2.h> + +namespace i18n { +namespace addressinput { + +namespace { + +// Mapping from AddressField value to pointer to AddressData member. +std::string AddressData::*kStringField[] = { + &AddressData::region_code, + &AddressData::administrative_area, + &AddressData::locality, + &AddressData::dependent_locality, + &AddressData::sorting_code, + &AddressData::postal_code, + NULL, + &AddressData::organization, + &AddressData::recipient +}; + +// Mapping from AddressField value to pointer to AddressData member. +const std::vector<std::string> AddressData::*kVectorStringField[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &AddressData::address_line, + NULL, + NULL +}; + +COMPILE_ASSERT(arraysize(kStringField) == arraysize(kVectorStringField), + field_mapping_array_size_mismatch); + +// A string is considered to be "empty" not only if it actually is empty, but +// also if it contains nothing but whitespace. +bool IsStringEmpty(const std::string& str) { + static const RE2 kMatcher("\\S"); + return str.empty() || !RE2::PartialMatch(str, kMatcher); +} + +} // namespace + +bool AddressData::IsFieldEmpty(AddressField field) const { + assert(field >= 0); + assert(static_cast<size_t>(field) < arraysize(kStringField)); + if (kStringField[field] != NULL) { + const std::string& value = GetFieldValue(field); + return IsStringEmpty(value); + } else { + const std::vector<std::string>& value = GetRepeatedFieldValue(field); + return std::find_if(value.begin(), + value.end(), + std::not1(std::ptr_fun(&IsStringEmpty))) == value.end(); + } +} + +const std::string& AddressData::GetFieldValue( + AddressField field) const { + assert(field >= 0); + assert(static_cast<size_t>(field) < arraysize(kStringField)); + assert(kStringField[field] != NULL); + return this->*kStringField[field]; +} + +void AddressData::SetFieldValue(AddressField field, const std::string& value) { + assert(field >= 0); + assert(static_cast<size_t>(field) < arraysize(kStringField)); + assert(kStringField[field] != NULL); + (this->*kStringField[field]).assign(value); +} + +const std::vector<std::string>& AddressData::GetRepeatedFieldValue( + AddressField field) const { + assert(IsRepeatedFieldValue(field)); + return this->*kVectorStringField[field]; +} + +bool AddressData::operator==(const AddressData& other) const { + return region_code == other.region_code && + address_line == other.address_line && + administrative_area == other.administrative_area && + locality == other.locality && + dependent_locality == other.dependent_locality && + postal_code == other.postal_code && + sorting_code == other.sorting_code && + language_code == other.language_code && + organization == other.organization && + recipient == other.recipient; +} + +// static +bool AddressData::IsRepeatedFieldValue(AddressField field) { + assert(field >= 0); + assert(static_cast<size_t>(field) < arraysize(kVectorStringField)); + return kVectorStringField[field] != NULL; +} + +} // namespace addressinput +} // namespace i18n + +std::ostream& operator<<(std::ostream& o, + const i18n::addressinput::AddressData& address) { + o << "region_code: \"" << address.region_code << "\"\n" + "administrative_area: \"" << address.administrative_area << "\"\n" + "locality: \"" << address.locality << "\"\n" + "dependent_locality: \"" << address.dependent_locality << "\"\n" + "postal_code: \"" << address.postal_code << "\"\n" + "sorting_code: \"" << address.sorting_code << "\"\n"; + + // TODO: Update the field order in the .h file to match the order they are + // printed out here, for consistency. + for (std::vector<std::string>::const_iterator it = + address.address_line.begin(); + it != address.address_line.end(); ++it) { + o << "address_line: \"" << *it << "\"\n"; + } + + o << "language_code: \"" << address.language_code << "\"\n" + "organization: \"" << address.organization << "\"\n" + "recipient: \"" << address.recipient << "\"\n"; + + return o; +} diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_field.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_field.cc new file mode 100644 index 00000000000..c5c96d86896 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_field.cc @@ -0,0 +1,47 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include <libaddressinput/address_field.h> + +#include <libaddressinput/util/basictypes.h> + +#include <cstddef> +#include <ostream> + +using i18n::addressinput::AddressField; +using i18n::addressinput::COUNTRY; +using i18n::addressinput::RECIPIENT; + +std::ostream& operator<<(std::ostream& o, AddressField field) { + static const char* const kFieldNames[] = { + "COUNTRY", + "ADMIN_AREA", + "LOCALITY", + "DEPENDENT_LOCALITY", + "SORTING_CODE", + "POSTAL_CODE", + "STREET_ADDRESS", + "ORGANIZATION", + "RECIPIENT" + }; + COMPILE_ASSERT(COUNTRY == 0, bad_base); + COMPILE_ASSERT(RECIPIENT == arraysize(kFieldNames) - 1, bad_length); + + if (field < 0 || static_cast<size_t>(field) >= arraysize(kFieldNames)) { + o << "[INVALID ENUM VALUE " << static_cast<int>(field) << "]"; + } else { + o << kFieldNames[field]; + } + return o; +} diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_field_util.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_field_util.cc new file mode 100644 index 00000000000..26de3c04859 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_field_util.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include "address_field_util.h" + +#include <libaddressinput/address_field.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "format_element.h" + +namespace i18n { +namespace addressinput { + +namespace { + +std::map<char, AddressField> InitFields() { + std::map<char, AddressField> fields; + fields.insert(std::make_pair('R', COUNTRY)); + fields.insert(std::make_pair('S', ADMIN_AREA)); + fields.insert(std::make_pair('C', LOCALITY)); + fields.insert(std::make_pair('D', DEPENDENT_LOCALITY)); + fields.insert(std::make_pair('X', SORTING_CODE)); + fields.insert(std::make_pair('Z', POSTAL_CODE)); + fields.insert(std::make_pair('A', STREET_ADDRESS)); + fields.insert(std::make_pair('O', ORGANIZATION)); + fields.insert(std::make_pair('N', RECIPIENT)); + return fields; +} + +const std::map<char, AddressField>& GetFields() { + static const std::map<char, AddressField> kFields(InitFields()); + return kFields; +} + +bool IsFieldToken(char c) { + return GetFields().find(c) != GetFields().end(); +} + +AddressField ParseFieldToken(char c) { + std::map<char, AddressField>::const_iterator it = GetFields().find(c); + assert(it != GetFields().end()); + return it->second; +} + +} // namespace + +void ParseFormatRule(const std::string& format, + std::vector<FormatElement>* elements) { + assert(elements != NULL); + elements->clear(); + + std::string::const_iterator prev = format.begin(); + for (std::string::const_iterator next = format.begin(); + next != format.end(); prev = ++next) { + // Find the next field element or newline (indicated by %<TOKEN>). + if ((next = std::find(next, format.end(), '%')) == format.end()) { + // No more tokens in the format string. + break; + } + if (prev < next) { + // Push back preceding literal. + elements->push_back(FormatElement(std::string(prev, next))); + } + if ((prev = ++next) == format.end()) { + // Move forward and check we haven't reached the end of the string + // (unlikely, it shouldn't end with %). + break; + } + // Process the token after the %. + if (*next == 'n') { + elements->push_back(FormatElement()); + } else if (IsFieldToken(*next)) { + elements->push_back(FormatElement(ParseFieldToken(*next))); + } // Else it's an unknown token, we ignore it. + } + // Push back any trailing literal. + if (prev != format.end()) { + elements->push_back(FormatElement(std::string(prev, format.end()))); + } +} + +void ParseAddressFieldsRequired(const std::string& required, + std::vector<AddressField>* fields) { + assert(fields != NULL); + fields->clear(); + for (std::string::const_iterator it = required.begin(); + it != required.end(); ++it) { + if (IsFieldToken(*it)) { + fields->push_back(ParseFieldToken(*it)); + } + } +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_field_util.h b/chromium/third_party/libaddressinput/src/cpp/src/address_field_util.h new file mode 100644 index 00000000000..123672b0ac5 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_field_util.h @@ -0,0 +1,44 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ADDRESS_FIELD_UTIL_H_ +#define I18N_ADDRESSINPUT_ADDRESS_FIELD_UTIL_H_ + +#include <libaddressinput/address_field.h> + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +class FormatElement; + +// Clears |fields|, parses |format|, and adds the format address fields to +// |fields|. The |fields| may also contain NEWLINE elements. For example, parses +// "%S%C%n%D%X" into {ADMIN_AREA, LOCALITY, NEWLINE, DEPENDENT_LOCALITY, +// SORTING_CODE}. +void ParseFormatRule(const std::string& format, + std::vector<FormatElement>* fields); + +// Clears |fields|, parses |required|, and adds the required fields to |fields|. +// For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY, +// SORTING_CODE}. +void ParseAddressFieldsRequired(const std::string& required, + std::vector<AddressField>* fields); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ADDRESS_FIELD_UTIL_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_formatter.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_formatter.cc new file mode 100644 index 00000000000..b54cbac122c --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_formatter.cc @@ -0,0 +1,230 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_formatter.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/util/basictypes.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <string> +#include <vector> + +#include "format_element.h" +#include "language.h" +#include "region_data_constants.h" +#include "rule.h" +#include "util/cctype_tolower_equal.h" + +namespace i18n { +namespace addressinput { + +namespace { + +const char kCommaSeparator[] = ", "; +const char kSpaceSeparator[] = " "; +const char kArabicCommaSeparator[] = "\xD8\x8C" " "; /* "، " */ + +const char* kLanguagesThatUseSpace[] = { + "th", + "ko" +}; + +const char* kLanguagesThatHaveNoSeparator[] = { + "ja", + "zh" // All Chinese variants. +}; + +// This data is based on CLDR, for languages that are in official use in some +// country, where Arabic is the most likely script tag. +// TODO: Consider supporting variants such as tr-Arab by detecting the script +// code. +const char* kLanguagesThatUseAnArabicComma[] = { + "ar", + "az", + "fa", + "kk", + "ku", + "ky", + "ps", + "tg", + "tk", + "ur", + "uz" +}; + +std::string GetLineSeparatorForLanguage(const std::string& language_tag) { + Language address_language(language_tag); + + // First deal with explicit script tags. + if (address_language.has_latin_script) { + return kCommaSeparator; + } + + // Now guess something appropriate based on the base language. + const std::string& base_language = address_language.base; + if (std::find_if(kLanguagesThatUseSpace, + kLanguagesThatUseSpace + arraysize(kLanguagesThatUseSpace), + std::bind2nd(EqualToTolowerString(), base_language)) != + kLanguagesThatUseSpace + arraysize(kLanguagesThatUseSpace)) { + return kSpaceSeparator; + } else if (std::find_if( + kLanguagesThatHaveNoSeparator, + kLanguagesThatHaveNoSeparator + + arraysize(kLanguagesThatHaveNoSeparator), + std::bind2nd(EqualToTolowerString(), base_language)) != + kLanguagesThatHaveNoSeparator + + arraysize(kLanguagesThatHaveNoSeparator)) { + return ""; + } else if (std::find_if( + kLanguagesThatUseAnArabicComma, + kLanguagesThatUseAnArabicComma + + arraysize(kLanguagesThatUseAnArabicComma), + std::bind2nd(EqualToTolowerString(), base_language)) != + kLanguagesThatUseAnArabicComma + + arraysize(kLanguagesThatUseAnArabicComma)) { + return kArabicCommaSeparator; + } + // Either the language is a Latin-script language, or no language was + // specified. In the latter case we still return ", " as the most common + // separator in use. In countries that don't use this, e.g. Thailand, + // addresses are often written in Latin script where this would still be + // appropriate, so this is a reasonable default in the absence of information. + return kCommaSeparator; +} + +void CombineLinesForLanguage(const std::vector<std::string>& lines, + const std::string& language_tag, + std::string* line) { + line->clear(); + std::string separator = GetLineSeparatorForLanguage(language_tag); + for (std::vector<std::string>::const_iterator it = lines.begin(); + it != lines.end(); + ++it) { + if (it != lines.begin()) { + line->append(separator); + } + line->append(*it); + } +} + +} // namespace + +void GetFormattedNationalAddress( + const AddressData& address_data, std::vector<std::string>* lines) { + assert(lines != NULL); + lines->clear(); + + Rule rule; + rule.CopyFrom(Rule::GetDefault()); + // TODO: Eventually, we should get the best rule for this country and + // language, rather than just for the country. + rule.ParseSerializedRule(RegionDataConstants::GetRegionData( + address_data.region_code)); + + Language language(address_data.language_code); + + // If Latin-script rules are available and the |language_code| of this address + // is explicitly tagged as being Latin, then use the Latin-script formatting + // rules. + const std::vector<FormatElement>& format = + language.has_latin_script && !rule.GetLatinFormat().empty() + ? rule.GetLatinFormat() + : rule.GetFormat(); + + // Address format without the unnecessary elements (based on which address + // fields are empty). We assume all literal strings that are not at the start + // or end of a line are separators, and therefore only relevant if the + // surrounding fields are filled in. This works with the data we have + // currently. + std::vector<FormatElement> pruned_format; + for (std::vector<FormatElement>::const_iterator + element_it = format.begin(); + element_it != format.end(); + ++element_it) { + // Always keep the newlines. + if (element_it->IsNewline() || + // Always keep the non-empty address fields. + (element_it->IsField() && + !address_data.IsFieldEmpty(element_it->GetField())) || + // Only keep literals that satisfy these 2 conditions: + (!element_it->IsField() && + // (1) Not preceding an empty field. + (element_it + 1 == format.end() || + !(element_it + 1)->IsField() || + !address_data.IsFieldEmpty((element_it + 1)->GetField())) && + // (2) Not following a removed field. + (element_it == format.begin() || + !(element_it - 1)->IsField() || + (!pruned_format.empty() && pruned_format.back().IsField())))) { + pruned_format.push_back(*element_it); + } + } + + std::string line; + for (std::vector<FormatElement>::const_iterator + element_it = pruned_format.begin(); + element_it != pruned_format.end(); + ++element_it) { + if (element_it->IsNewline()) { + if (!line.empty()) { + lines->push_back(line); + line.clear(); + } + } else if (element_it->IsField()) { + AddressField field = element_it->GetField(); + if (field == STREET_ADDRESS) { + // The field "street address" represents the street address lines of an + // address, so there can be multiple values. + if (!address_data.IsFieldEmpty(field)) { + line.append(address_data.address_line.front()); + if (address_data.address_line.size() > 1U) { + lines->push_back(line); + line.clear(); + lines->insert(lines->end(), + address_data.address_line.begin() + 1, + address_data.address_line.end()); + } + } + } else { + line.append(address_data.GetFieldValue(field)); + } + } else { + line.append(element_it->GetLiteral()); + } + } + if (!line.empty()) { + lines->push_back(line); + } +} + +void GetFormattedNationalAddressLine( + const AddressData& address_data, std::string* line) { + std::vector<std::string> address_lines; + GetFormattedNationalAddress(address_data, &address_lines); + CombineLinesForLanguage(address_lines, address_data.language_code, line); +} + +void GetStreetAddressLinesAsSingleLine( + const AddressData& address_data, std::string* line) { + CombineLinesForLanguage( + address_data.address_line, address_data.language_code, line); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_input_helper.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_input_helper.cc new file mode 100644 index 00000000000..82ea6fc2bbd --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_input_helper.cc @@ -0,0 +1,186 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_input_helper.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_metadata.h> +#include <libaddressinput/preload_supplier.h> +#include <libaddressinput/util/basictypes.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <vector> + +#include <re2/re2.h> + +#include "language.h" +#include "lookup_key.h" +#include "region_data_constants.h" +#include "rule.h" +#include "util/re2ptr.h" + +namespace i18n { +namespace addressinput { + +// Used for building a hierarchy of rules, each one connected to its parent. +struct Node { + const Node* parent; + const Rule* rule; +}; + +namespace { + +const char kLookupKeySeparator = '/'; + +const size_t kHierarchyDepth = arraysize(LookupKey::kHierarchy); + +// Gets the best name for the entity represented by the current rule, using the +// language provided. The language is currently used to distinguish whether a +// Latin-script name should be fetched; if it is not explicitly Latin-script, we +// prefer IDs over names (so return CA instead of California for an English +// user.) If there is no Latin-script name, we fall back to the ID. +std::string GetBestName(const Language& language, const Rule& rule) { + if (language.has_latin_script) { + const std::string& name = rule.GetLatinName(); + if (!name.empty()) { + return name; + } + } + // The ID is stored as data/US/CA for "CA", for example, and we only want the + // last part. + const std::string& id = rule.GetId(); + std::string::size_type pos = id.rfind(kLookupKeySeparator); + assert(pos != std::string::npos); + return id.substr(pos + 1); +} + +void FillAddressFromMatchedRules( + const std::vector<Node>* hierarchy, + AddressData* address) { + assert(hierarchy != NULL); + assert(address != NULL); + // We skip region code, because we never try and fill that in if it isn't + // already set. + Language language(address->language_code); + for (size_t depth = kHierarchyDepth - 1; depth > 0; --depth) { + // If there is only one match at this depth, then we should populate the + // address, using this rule and its parents. + if (hierarchy[depth].size() == 1) { + for (const Node* node = &hierarchy[depth].front(); + node != NULL; node = node->parent, --depth) { + const Rule* rule = node->rule; + assert(rule != NULL); + + AddressField field = LookupKey::kHierarchy[depth]; + // Note only empty fields are permitted to be overwritten. + if (address->IsFieldEmpty(field)) { + address->SetFieldValue(field, GetBestName(language, *rule)); + } + } + break; + } + } +} + +} // namespace; + +AddressInputHelper::AddressInputHelper(PreloadSupplier* supplier) + : supplier_(supplier) { + assert(supplier_ != NULL); +} + +AddressInputHelper::~AddressInputHelper() { +} + +void AddressInputHelper::FillAddress(AddressData* address) const { + assert(address != NULL); + const std::string& region_code = address->region_code; + if (!RegionDataConstants::IsSupported(region_code)) { + // If we don't have a region code, we can't do anything reliably to fill + // this address. + return; + } + + AddressData lookup_key_address; + lookup_key_address.region_code = region_code; + // First try and fill in the postal code if it is missing. + LookupKey lookup_key; + lookup_key.FromAddress(lookup_key_address); + const Rule* region_rule = supplier_->GetRule(lookup_key); + // We have already checked that the region is supported; and users of this + // method must have called LoadRules() first, so we check this here. + assert(region_rule != NULL); + + const RE2ptr* postal_code_reg_exp = region_rule->GetPostalCodeMatcher(); + if (postal_code_reg_exp != NULL) { + if (address->postal_code.empty()) { + address->postal_code = region_rule->GetSolePostalCode(); + } + + // If we have a valid postal code, try and work out the most specific + // hierarchy that matches the postal code. Note that the postal code might + // have been added in the previous check. + if (!address->postal_code.empty() && + RE2::FullMatch(address->postal_code, *postal_code_reg_exp->ptr)) { + + // This hierarchy is used to store rules that represent possible matches + // at each level of the hierarchy. + std::vector<Node> hierarchy[kHierarchyDepth]; + CheckChildrenForPostCodeMatches(*address, lookup_key, NULL, hierarchy); + + FillAddressFromMatchedRules(hierarchy, address); + } + } + + // TODO: When we have the data, we should fill in the state for countries with + // state required and only one possible value, e.g. American Samoa. +} + +void AddressInputHelper::CheckChildrenForPostCodeMatches( + const AddressData& address, + const LookupKey& lookup_key, + const Node* parent, + // An array of vectors. + std::vector<Node>* hierarchy) const { + const Rule* rule = supplier_->GetRule(lookup_key); + assert(rule != NULL); + + const RE2ptr* postal_code_prefix = rule->GetPostalCodeMatcher(); + if (postal_code_prefix == NULL || + RE2::PartialMatch(address.postal_code, *postal_code_prefix->ptr)) { + // This was a match, so store it and its parent in the hierarchy. + hierarchy[lookup_key.GetDepth()].push_back(Node()); + Node* node = &hierarchy[lookup_key.GetDepth()].back(); + node->parent = parent; + node->rule = rule; + + if (IsFieldUsed(LookupKey::kHierarchy[lookup_key.GetDepth() + 1], + address.region_code)) { + // If children are used and present, check them too. + for (std::vector<std::string>::const_iterator child_it = + rule->GetSubKeys().begin(); + child_it != rule->GetSubKeys().end(); ++child_it) { + LookupKey child_key; + child_key.FromLookupKey(lookup_key, *child_it); + CheckChildrenForPostCodeMatches(address, child_key, node, hierarchy); + } + } + } +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_metadata.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_metadata.cc new file mode 100644 index 00000000000..c088e0d600d --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_metadata.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_metadata.h> + +#include <libaddressinput/address_field.h> + +#include <algorithm> +#include <string> + +#include "format_element.h" +#include "region_data_constants.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +bool IsFieldRequired(AddressField field, const std::string& region_code) { + if (field == COUNTRY) { + return true; + } + + Rule rule; + rule.CopyFrom(Rule::GetDefault()); + if (!rule.ParseSerializedRule( + RegionDataConstants::GetRegionData(region_code))) { + return false; + } + + return std::find(rule.GetRequired().begin(), + rule.GetRequired().end(), + field) != rule.GetRequired().end(); +} + +bool IsFieldUsed(AddressField field, const std::string& region_code) { + if (field == COUNTRY) { + return true; + } + + Rule rule; + rule.CopyFrom(Rule::GetDefault()); + if (!rule.ParseSerializedRule( + RegionDataConstants::GetRegionData(region_code))) { + return false; + } + + return std::find(rule.GetFormat().begin(), + rule.GetFormat().end(), + FormatElement(field)) != rule.GetFormat().end(); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_normalizer.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_normalizer.cc new file mode 100644 index 00000000000..562203e2ae5 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_normalizer.cc @@ -0,0 +1,89 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_normalizer.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/preload_supplier.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <vector> + +#include "lookup_key.h" +#include "rule.h" +#include "util/string_compare.h" + +namespace i18n { +namespace addressinput { + +AddressNormalizer::AddressNormalizer(const PreloadSupplier* supplier) + : supplier_(supplier), + compare_(new StringCompare) { + assert(supplier_ != NULL); +} + +AddressNormalizer::~AddressNormalizer() {} + +void AddressNormalizer::Normalize(AddressData* address) const { + assert(address != NULL); + assert(supplier_->IsLoaded(address->region_code)); + + AddressData region_address; + region_address.region_code = address->region_code; + LookupKey parent_key; + parent_key.FromAddress(region_address); + const Rule* parent_rule = supplier_->GetRule(parent_key); + assert(parent_rule != NULL); + + LookupKey lookup_key; + for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) { + AddressField field = LookupKey::kHierarchy[depth]; + if (address->IsFieldEmpty(field)) { + return; + } + const std::string& field_value = address->GetFieldValue(field); + bool no_match_found_yet = true; + for (std::vector<std::string>::const_iterator + key_it = parent_rule->GetSubKeys().begin(); + key_it != parent_rule->GetSubKeys().end(); ++key_it) { + lookup_key.FromLookupKey(parent_key, *key_it); + const Rule* rule = supplier_->GetRule(lookup_key); + assert(rule != NULL); + + bool matches_latin_name = + compare_->NaturalEquals(field_value, rule->GetLatinName()); + bool matches_local_name_id = + compare_->NaturalEquals(field_value, *key_it) || + compare_->NaturalEquals(field_value, rule->GetName()); + if (matches_latin_name || matches_local_name_id) { + address->SetFieldValue( + field, matches_latin_name ? rule->GetLatinName() : *key_it); + no_match_found_yet = false; + parent_key.FromLookupKey(parent_key, *key_it); + parent_rule = supplier_->GetRule(parent_key); + assert(parent_rule != NULL); + break; + } + } + if (no_match_found_yet) { + return; // Abort search. + } + } +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_problem.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_problem.cc new file mode 100644 index 00000000000..0fade172adb --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_problem.cc @@ -0,0 +1,44 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_problem.h> + +#include <libaddressinput/util/basictypes.h> + +#include <cstddef> +#include <ostream> + +using i18n::addressinput::AddressProblem; +using i18n::addressinput::UNEXPECTED_FIELD; +using i18n::addressinput::USES_P_O_BOX; + +std::ostream& operator<<(std::ostream& o, AddressProblem problem) { + static const char* const kProblemNames[] = { + "UNEXPECTED_FIELD", + "MISSING_REQUIRED_FIELD", + "UNKNOWN_VALUE", + "INVALID_FORMAT", + "MISMATCHING_VALUE", + "USES_P_O_BOX" + }; + COMPILE_ASSERT(UNEXPECTED_FIELD == 0, bad_base); + COMPILE_ASSERT(USES_P_O_BOX == arraysize(kProblemNames) - 1, bad_length); + + if (problem < 0 || static_cast<size_t>(problem) >= arraysize(kProblemNames)) { + o << "[INVALID ENUM VALUE " << static_cast<int>(problem) << "]"; + } else { + o << kProblemNames[problem]; + } + return o; +} diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_ui.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_ui.cc new file mode 100644 index 00000000000..5df8b3d0438 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_ui.cc @@ -0,0 +1,147 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include <libaddressinput/address_ui.h> + +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_ui_component.h> +#include <libaddressinput/localization.h> + +#include <cassert> +#include <cstddef> +#include <set> +#include <string> +#include <vector> + +#include "format_element.h" +#include "grit.h" +#include "language.h" +#include "messages.h" +#include "region_data_constants.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +namespace { + +std::string GetLabelForField(const Localization& localization, + AddressField field, + int admin_area_name_message_id, + int postal_code_name_message_id, + int locality_name_message_id, + int sublocality_name_message_id) { + int messageId; + switch (field) { + case SORTING_CODE: + // This needs no translation as it's used only in one locale. + return "CEDEX"; + case COUNTRY: + messageId = IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL; + break; + case ADMIN_AREA: + messageId = admin_area_name_message_id; + break; + case LOCALITY: + messageId = locality_name_message_id; + break; + case DEPENDENT_LOCALITY: + messageId = sublocality_name_message_id; + break; + case POSTAL_CODE: + messageId = postal_code_name_message_id; + break; + case STREET_ADDRESS: + messageId = IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL; + break; + case ORGANIZATION: + messageId = IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL; + break; + case RECIPIENT: + messageId = IDS_LIBADDRESSINPUT_RECIPIENT_LABEL; + break; + default: + messageId = INVALID_MESSAGE_ID; + } + return localization.GetString(messageId); +} + +} // namespace + +const std::vector<std::string>& GetRegionCodes() { + return RegionDataConstants::GetRegionCodes(); +} + +std::vector<AddressUiComponent> BuildComponents( + const std::string& region_code, + const Localization& localization, + const std::string& ui_language_tag, + std::string* best_address_language_tag) { + assert(best_address_language_tag != NULL); + std::vector<AddressUiComponent> result; + + Rule rule; + rule.CopyFrom(Rule::GetDefault()); + if (!rule.ParseSerializedRule( + RegionDataConstants::GetRegionData(region_code))) { + return result; + } + + const Language& best_address_language = + ChooseBestAddressLanguage(rule, Language(ui_language_tag)); + *best_address_language_tag = best_address_language.tag; + + const std::vector<FormatElement>& format = + !rule.GetLatinFormat().empty() && best_address_language.has_latin_script + ? rule.GetLatinFormat() + : rule.GetFormat(); + + // For avoiding showing an input field twice, when the field is displayed + // twice on an envelope. + std::set<AddressField> fields; + + bool preceded_by_newline = true; + bool followed_by_newline = true; + for (std::vector<FormatElement>::const_iterator format_it = format.begin(); + format_it != format.end(); ++format_it) { + if (format_it->IsNewline()) { + preceded_by_newline = true; + continue; + } else if (!format_it->IsField() || + !fields.insert(format_it->GetField()).second) { + continue; + } + AddressUiComponent component; + std::vector<FormatElement>::const_iterator next_format_it = format_it + 1; + followed_by_newline = + next_format_it == format.end() || next_format_it->IsNewline(); + component.length_hint = preceded_by_newline && followed_by_newline + ? AddressUiComponent::HINT_LONG + : AddressUiComponent::HINT_SHORT; + preceded_by_newline = false; + component.field = format_it->GetField(); + component.name = GetLabelForField(localization, + format_it->GetField(), + rule.GetAdminAreaNameMessageId(), + rule.GetPostalCodeNameMessageId(), + rule.GetLocalityNameMessageId(), + rule.GetSublocalityNameMessageId()); + result.push_back(component); + } + + return result; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/address_validator.cc b/chromium/third_party/libaddressinput/src/cpp/src/address_validator.cc new file mode 100644 index 00000000000..8f0c33cf38f --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/address_validator.cc @@ -0,0 +1,49 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/address_validator.h> + +#include <cassert> +#include <cstddef> + +#include "validation_task.h" + +namespace i18n { +namespace addressinput { + +AddressValidator::AddressValidator(Supplier* supplier) : supplier_(supplier) { + assert(supplier_ != NULL); +} + +AddressValidator::~AddressValidator() { +} + +void AddressValidator::Validate(const AddressData& address, + bool allow_postal, + bool require_name, + const FieldProblemMap* filter, + FieldProblemMap* problems, + const Callback& validated) const { + // The ValidationTask object will delete itself after Run() has finished. + (new ValidationTask( + address, + allow_postal, + require_name, + filter, + problems, + validated))->Run(supplier_); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/format_element.cc b/chromium/third_party/libaddressinput/src/cpp/src/format_element.cc new file mode 100644 index 00000000000..8f9669c8845 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/format_element.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "format_element.h" + +#include <libaddressinput/address_field.h> + +#include <cassert> +#include <ostream> + +namespace i18n { +namespace addressinput { + +FormatElement::FormatElement(AddressField field) : field_(field), literal_() {} + +FormatElement::FormatElement(const std::string& literal) + : field_(static_cast<AddressField>(-1)), literal_(literal) { + assert(!literal.empty()); +} + +FormatElement::FormatElement() + : field_(static_cast<AddressField>(-1)), literal_("\n") {} + +bool FormatElement::operator==(const FormatElement& other) const { + return field_ == other.field_ && literal_ == other.literal_; +} + +} // namespace addressinput +} // namespace i18n + +std::ostream& operator<<(std::ostream& o, + const i18n::addressinput::FormatElement& element) { + if (element.IsField()) { + o << "Field: " << element.GetField(); + } else if (element.IsNewline()) { + o << "Newline"; + } else { + o << "Literal: " << element.GetLiteral(); + } + return o; +} diff --git a/chromium/third_party/libaddressinput/src/cpp/src/format_element.h b/chromium/third_party/libaddressinput/src/cpp/src/format_element.h new file mode 100644 index 00000000000..e37a1883856 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/format_element.h @@ -0,0 +1,70 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// An object representing a token in a formatting string. This may be a +// placeholder for a field in the address data such as ADMIN_AREA, a literal +// string such as " ", or a newline. + +#ifndef I18N_ADDRESSINPUT_FORMAT_ELEMENT_H_ +#define I18N_ADDRESSINPUT_FORMAT_ELEMENT_H_ + +#include <libaddressinput/address_field.h> + +#include <iosfwd> +#include <string> + +namespace i18n { +namespace addressinput { + +class FormatElement { + public: + // Builds a format element to represent |field|. + explicit FormatElement(AddressField field); + + // Builds an element representing a literal string |literal|. + explicit FormatElement(const std::string& literal); + + // Builds a newline element. + FormatElement(); + + // Returns true if this element represents a field element. + bool IsField() const { return literal_.empty(); } + + // Returns true if this element represents a new line. + bool IsNewline() const { return literal_ == "\n"; } + + AddressField GetField() const { return field_; } + const std::string& GetLiteral() const { return literal_; } + + bool operator==(const FormatElement& other) const; + + private: + // The field this element represents. Should only be used if |literal| is an + // empty string. + AddressField field_; + + // The literal string for this element. This will be "\n" if this is a + // newline - but IsNewline() is preferred to determine this. If empty, then + // this FormatElement represents an address field. + std::string literal_; +}; + +} // namespace addressinput +} // namespace i18n + +// Produces human-readable output in logging, for example in unit tests. +std::ostream& operator<<(std::ostream& o, + const i18n::addressinput::FormatElement& field); + +#endif // I18N_ADDRESSINPUT_FORMAT_ELEMENT_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/grit.h b/chromium/third_party/libaddressinput/src/cpp/src/grit.h new file mode 100644 index 00000000000..c4c23f3116d --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/grit.h @@ -0,0 +1,36 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_GRIT_H_ +#define I18N_ADDRESSINPUT_GRIT_H_ + +namespace i18n { +namespace addressinput { + +// A message identifier that is guaranteed to not clash with any +// IDS_ADDRESSINPUT_I18N_* identifiers that are generated by GRIT. GRIT +// generates messages in the range from decimal 101 to 0x7FFF in order to work +// with Windows. +// https://code.google.com/p/grit-i18n/source/browse/trunk/grit/format/rc_header.py?r=94#169 +// http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx +// +// The enum must be named to enable using it in gtest templates, e.g. +// EXPECT_EQ(INVALID_MESSAGE_ID, my_id) will not compile on some platforms when +// the enum is unnamed. +enum MessageIdentifier { INVALID_MESSAGE_ID = 0 }; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_GRIT_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/language.cc b/chromium/third_party/libaddressinput/src/cpp/src/language.cc new file mode 100644 index 00000000000..28817dc12d2 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/language.cc @@ -0,0 +1,102 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "language.h" + +#include <algorithm> +#include <cctype> +#include <string> +#include <vector> + +#include "rule.h" +#include "util/string_split.h" + +namespace i18n { +namespace addressinput { + +Language::Language(const std::string& language_tag) : tag(language_tag), + base(), + has_latin_script(false) { + // Character '-' is the separator for subtags in the BCP 47. However, some + // legacy code generates tags with '_' instead of '-'. + static const char kSubtagsSeparator = '-'; + static const char kAlternativeSubtagsSeparator = '_'; + std::replace( + tag.begin(), tag.end(), kAlternativeSubtagsSeparator, kSubtagsSeparator); + + // OK to use 'tolower' because BCP 47 tags are always in ASCII. + std::string lowercase = tag; + std::transform( + lowercase.begin(), lowercase.end(), lowercase.begin(), tolower); + + base = lowercase.substr(0, lowercase.find(kSubtagsSeparator)); + + // The lowercase BCP 47 subtag for Latin script. + static const char kLowercaseLatinScript[] = "latn"; + std::vector<std::string> subtags; + SplitString(lowercase, kSubtagsSeparator, &subtags); + + // Support only the second and third position for the script. + has_latin_script = + (subtags.size() > 1 && subtags[1] == kLowercaseLatinScript) || + (subtags.size() > 2 && subtags[2] == kLowercaseLatinScript); +} + +Language::~Language() {} + +Language ChooseBestAddressLanguage(const Rule& address_region_rule, + const Language& ui_language) { + if (address_region_rule.GetLanguages().empty()) { + return ui_language; + } + + std::vector<Language> available_languages; + for (std::vector<std::string>::const_iterator + language_tag_it = address_region_rule.GetLanguages().begin(); + language_tag_it != address_region_rule.GetLanguages().end(); + ++language_tag_it) { + available_languages.push_back(Language(*language_tag_it)); + } + + if (ui_language.tag.empty()) { + return available_languages.front(); + } + + bool has_latin_format = !address_region_rule.GetLatinFormat().empty(); + + // The conventionally formatted BCP 47 Latin script with a preceding subtag + // separator. + static const char kLatinScriptSuffix[] = "-Latn"; + Language latin_script_language( + available_languages.front().base + kLatinScriptSuffix); + if (has_latin_format && ui_language.has_latin_script) { + return latin_script_language; + } + + for (std::vector<Language>::const_iterator + available_lang_it = available_languages.begin(); + available_lang_it != available_languages.end(); ++available_lang_it) { + // Base language comparison works because no region supports the same base + // language with different scripts, for now. For example, no region supports + // "zh-Hant" and "zh-Hans" at the same time. + if (ui_language.base == available_lang_it->base) { + return *available_lang_it; + } + } + + return has_latin_format ? latin_script_language : available_languages.front(); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/language.h b/chromium/third_party/libaddressinput/src/cpp/src/language.h new file mode 100644 index 00000000000..561c79fa690 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/language.h @@ -0,0 +1,49 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_LANGUAGE_H_ +#define I18N_ADDRESSINPUT_LANGUAGE_H_ + +#include <string> + +namespace i18n { +namespace addressinput { + +class Rule; + +// Helper for working with a BCP 47 language tag. +// http://tools.ietf.org/html/bcp47 +struct Language { + explicit Language(const std::string& language_tag); + ~Language(); + + // The language tag (with '_' replaced with '-'), for example "zh-Latn-CN". + std::string tag; + + // The base language, for example "zh". Always lowercase. + std::string base; + + // True if the language tag explicitly has a Latin script. For example, this + // is true for "zh-Latn", but false for "zh". Only the second and third subtag + // positions are supported for script. + bool has_latin_script; +}; + +Language ChooseBestAddressLanguage(const Rule& address_region_rule, + const Language& ui_language); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_LANGUAGE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/localization.cc b/chromium/third_party/libaddressinput/src/cpp/src/localization.cc new file mode 100644 index 00000000000..b544cd9f067 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/localization.cc @@ -0,0 +1,190 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include <libaddressinput/localization.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_problem.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <vector> + +#include "messages.h" +#include "region_data_constants.h" +#include "rule.h" +#include "util/string_split.h" +#include "util/string_util.h" + +namespace { + +void PushBackUrl(const std::string& url, std::vector<std::string>* parameters) { + assert(parameters != NULL); + // TODO: HTML-escape the "url". + parameters->push_back("<a href=\"" + url + "\">"); + parameters->push_back("</a>"); +} + +} // namespace + +namespace i18n { +namespace addressinput { + +namespace { + +#include "en_messages.cc" + +std::string GetEnglishString(int message_id) { + const char* str = GetString(message_id); + return str != NULL ? std::string(str) : std::string(); +} + +} // namespace + +Localization::Localization() : get_string_(&GetEnglishString) {} + +Localization::~Localization() {} + +std::string Localization::GetString(int message_id) const { + return get_string_(message_id); +} + +std::string Localization::GetErrorMessage(const AddressData& address, + AddressField field, + AddressProblem problem, + bool enable_examples, + bool enable_links) const { + if (field == POSTAL_CODE) { + Rule rule; + rule.CopyFrom(Rule::GetDefault()); + std::string postal_code_example, post_service_url; + if (rule.ParseSerializedRule( + RegionDataConstants::GetRegionData(address.region_code))) { + if (enable_examples) { + std::vector<std::string> examples_list; + SplitString(rule.GetPostalCodeExample(), ',', &examples_list); + if (!examples_list.empty()) { + postal_code_example = examples_list.front(); + } + } + if (enable_links) { + post_service_url = rule.GetPostServiceUrl(); + } + } else { + assert(false); + } + // If we can't parse the serialized rule |uses_postal_code_as_label| will be + // determined from the default rule. + bool uses_postal_code_as_label = + rule.GetPostalCodeNameMessageId() == + IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL; + return GetErrorMessageForPostalCode(address, problem, + uses_postal_code_as_label, + postal_code_example, post_service_url); + } else { + if (problem == MISSING_REQUIRED_FIELD) { + return get_string_(IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD); + } else if (problem == UNKNOWN_VALUE) { + std::vector<std::string> parameters; + if (AddressData::IsRepeatedFieldValue(field)) { + std::vector<std::string> values = address.GetRepeatedFieldValue(field); + assert(!values.empty()); + parameters.push_back(values.front()); + } else { + parameters.push_back(address.GetFieldValue(field)); + } + return DoReplaceStringPlaceholders( + get_string_(IDS_LIBADDRESSINPUT_UNKNOWN_VALUE), parameters); + } else if (problem == USES_P_O_BOX) { + return get_string_(IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE); + } else { + // Keep the default under "else" so the compiler helps us check that all + // handled cases return and don't fall through. + assert(false); + return ""; + } + } +} + +void Localization::SetGetter(std::string (*getter)(int)) { + assert(getter != NULL); + get_string_ = getter; +} + +std::string Localization::GetErrorMessageForPostalCode( + const AddressData& address, + AddressProblem problem, + bool uses_postal_code_as_label, + std::string postal_code_example, + std::string post_service_url) const { + int message_id; + std::vector<std::string> parameters; + if (problem == MISSING_REQUIRED_FIELD) { + if (!postal_code_example.empty() && !post_service_url.empty()) { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL : + IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL; + parameters.push_back(postal_code_example); + PushBackUrl(post_service_url, ¶meters); + } else if (!postal_code_example.empty()) { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE : + IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE ; + parameters.push_back(postal_code_example); + } else { + message_id = IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD; + } + return DoReplaceStringPlaceholders(get_string_(message_id), parameters); + } else if (problem == INVALID_FORMAT) { + if (!postal_code_example.empty() && !post_service_url.empty()) { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL : + IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL; + parameters.push_back(postal_code_example); + PushBackUrl(post_service_url, ¶meters); + } else if (!postal_code_example.empty()) { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE : + IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE; + parameters.push_back(postal_code_example); + } else { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE : + IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP; + } + return DoReplaceStringPlaceholders(get_string_(message_id), parameters); + } else if (problem == MISMATCHING_VALUE) { + if (!post_service_url.empty()) { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL : + IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL; + PushBackUrl(post_service_url, ¶meters); + } else { + message_id = uses_postal_code_as_label ? + IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE : + IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP; + } + return DoReplaceStringPlaceholders(get_string_(message_id), parameters); + } else { + // Keep the default under "else" so the compiler helps us check that all + // handled cases return and don't fall through. + assert(false); + return ""; + } +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/lookup_key.cc b/chromium/third_party/libaddressinput/src/cpp/src/lookup_key.cc new file mode 100644 index 00000000000..d793a2beae5 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/lookup_key.cc @@ -0,0 +1,153 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "lookup_key.h" + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/util/basictypes.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "language.h" +#include "region_data_constants.h" +#include "rule.h" +#include "util/cctype_tolower_equal.h" + +namespace i18n { +namespace addressinput { + +namespace { + +const char kSlashDelim[] = "/"; +const char kDashDelim[] = "--"; +const char kData[] = "data"; +const char kUnknown[] = "ZZ"; + +// Assume the language_tag has had "Latn" script removed when this is called. +bool ShouldSetLanguageForKey(const std::string& language_tag, + const std::string& region_code) { + // We only need a language in the key if there is subregion data at all. + if (RegionDataConstants::GetMaxLookupKeyDepth(region_code) == 0) { + return false; + } + Rule rule; + rule.CopyFrom(Rule::GetDefault()); + // TODO: Pre-parse the rules and have a map from region code to rule. + if (!rule.ParseSerializedRule( + RegionDataConstants::GetRegionData(region_code))) { + return false; + } + const std::vector<std::string>& languages = rule.GetLanguages(); + // Do not add the default language (we want "data/US", not "data/US--en"). + // (empty should not happen here because we have some sub-region data). + if (languages.empty() || languages[0] == language_tag) { + return false; + } + // Finally, only return true if the language is one of the remaining ones. + return std::find_if(languages.begin() + 1, languages.end(), + std::bind2nd(EqualToTolowerString(), language_tag)) != + languages.end(); +} + +} // namespace + +const AddressField LookupKey::kHierarchy[] = { + COUNTRY, + ADMIN_AREA, + LOCALITY, + DEPENDENT_LOCALITY +}; + +LookupKey::LookupKey() { +} + +LookupKey::~LookupKey() { +} + +void LookupKey::FromAddress(const AddressData& address) { + nodes_.clear(); + if (address.region_code.empty()) { + nodes_.insert(std::make_pair(COUNTRY, kUnknown)); + } else { + for (size_t i = 0; i < arraysize(kHierarchy); ++i) { + AddressField field = kHierarchy[i]; + const std::string& value = address.GetFieldValue(field); + if (value.empty()) { + break; + } + nodes_.insert(std::make_pair(field, value)); + } + } + Language address_language(address.language_code); + std::string language_tag_no_latn = address_language.has_latin_script + ? address_language.base + : address_language.tag; + if (ShouldSetLanguageForKey(language_tag_no_latn, address.region_code)) { + language_ = language_tag_no_latn; + } +} + +void LookupKey::FromLookupKey(const LookupKey& parent, + const std::string& child_node) { + assert(parent.nodes_.size() < arraysize(kHierarchy)); + assert(!child_node.empty()); + + // Copy its nodes if this isn't the parent object. + if (this != &parent) nodes_ = parent.nodes_; + AddressField child_field = kHierarchy[nodes_.size()]; + nodes_.insert(std::make_pair(child_field, child_node)); +} + +std::string LookupKey::ToKeyString(size_t max_depth) const { + assert(max_depth < arraysize(kHierarchy)); + std::string key_string(kData); + + for (size_t i = 0; i <= max_depth; ++i) { + AddressField field = kHierarchy[i]; + std::map<AddressField, std::string>::const_iterator it = nodes_.find(field); + if (it == nodes_.end()) { + break; + } + key_string.append(kSlashDelim); + key_string.append(it->second); + } + if (!language_.empty()) { + key_string.append(kDashDelim); + key_string.append(language_); + } + return key_string; +} + +const std::string& LookupKey::GetRegionCode() const { + std::map<AddressField, std::string>::const_iterator it = nodes_.find(COUNTRY); + assert(it != nodes_.end()); + return it->second; +} + +size_t LookupKey::GetDepth() const { + size_t depth = nodes_.size() - 1; + assert(depth < arraysize(kHierarchy)); + return depth; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/lookup_key.h b/chromium/third_party/libaddressinput/src/cpp/src/lookup_key.h new file mode 100644 index 00000000000..0b74cd3d938 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/lookup_key.h @@ -0,0 +1,75 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_LOOKUP_KEY_H_ +#define I18N_ADDRESSINPUT_LOOKUP_KEY_H_ + +#include <libaddressinput/address_field.h> +#include <libaddressinput/util/basictypes.h> + +#include <cstddef> +#include <map> +#include <string> + +namespace i18n { +namespace addressinput { + +struct AddressData; + +// A LookupKey maps between an AddressData struct and the key string used to +// request address data from an address data server. +class LookupKey { + public: + // The array length is explicitly specified here, to make it possible to get + // the length through arraysize(LookupKey::kHierarchy). + static const AddressField kHierarchy[4]; + + LookupKey(); + ~LookupKey(); + + // Initializes this object by parsing |address|. + void FromAddress(const AddressData& address); + + // Initializes this object to be a copy of |parent| key that's one level + // deeper with the next level node being |child_node|. + // + // For example, if |parent| is "data/US" and |child_node| is "CA", then this + // key becomes "data/US/CA". + // + // The |parent| can be at most LOCALITY level. The |child_node| cannot be + // empty. + void FromLookupKey(const LookupKey& parent, const std::string& child_node); + + // Returns the lookup key string (of |max_depth|). + std::string ToKeyString(size_t max_depth) const; + + // Returns the region code. Must not be called on an empty object. + const std::string& GetRegionCode() const; + + // Returns the depth. Must not be called on an empty object. + size_t GetDepth() const; + + private: + std::map<AddressField, std::string> nodes_; + // The language of the key, obtained from the address (empty for default + // language). + std::string language_; + + DISALLOW_COPY_AND_ASSIGN(LookupKey); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_LOOKUP_KEY_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/null_storage.cc b/chromium/third_party/libaddressinput/src/cpp/src/null_storage.cc new file mode 100644 index 00000000000..7786a0dcd4f --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/null_storage.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/null_storage.h> + +#include <cassert> +#include <cstddef> +#include <string> + +namespace i18n { +namespace addressinput { + +NullStorage::NullStorage() { +} + +NullStorage::~NullStorage() { +} + +void NullStorage::Put(const std::string& key, std::string* data) { + assert(data != NULL); // Sanity check. + delete data; +} + +void NullStorage::Get(const std::string& key, + const Callback& data_ready) const { + data_ready(false, key, NULL); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supplier.cc b/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supplier.cc new file mode 100644 index 00000000000..fa3f88e8701 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supplier.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/ondemand_supplier.h> + +#include <algorithm> +#include <cstddef> +#include <map> +#include <string> + +#include "lookup_key.h" +#include "ondemand_supply_task.h" +#include "region_data_constants.h" +#include "retriever.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +OndemandSupplier::OndemandSupplier(const Source* source, Storage* storage) + : retriever_(new Retriever(source, storage)) { +} + +OndemandSupplier::~OndemandSupplier() { + for (std::map<std::string, const Rule*>::const_iterator + it = rule_cache_.begin(); it != rule_cache_.end(); ++it) { + delete it->second; + } +} + +void OndemandSupplier::Supply(const LookupKey& lookup_key, + const Callback& supplied) { + OndemandSupplyTask* task = + new OndemandSupplyTask(lookup_key, &rule_cache_, supplied); + + if (RegionDataConstants::IsSupported(lookup_key.GetRegionCode())) { + size_t max_depth = std::min( + lookup_key.GetDepth(), + RegionDataConstants::GetMaxLookupKeyDepth(lookup_key.GetRegionCode())); + + for (size_t depth = 0; depth <= max_depth; ++depth) { + const std::string& key = lookup_key.ToKeyString(depth); + std::map<std::string, const Rule*>::const_iterator it = + rule_cache_.find(key); + if (it != rule_cache_.end()) { + task->hierarchy_.rule[depth] = it->second; + } else { + task->Queue(key); // If not in the cache, it needs to be loaded. + } + } + } + + task->Retrieve(*retriever_); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supply_task.cc b/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supply_task.cc new file mode 100644 index 00000000000..a4f6a12049a --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supply_task.cc @@ -0,0 +1,139 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "ondemand_supply_task.h" + +#include <libaddressinput/address_field.h> +#include <libaddressinput/callback.h> +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <map> +#include <set> +#include <string> +#include <utility> + +#include "lookup_key.h" +#include "retriever.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +OndemandSupplyTask::OndemandSupplyTask( + const LookupKey& lookup_key, + std::map<std::string, const Rule*>* rules, + const Supplier::Callback& supplied) + : hierarchy_(), + pending_(), + lookup_key_(lookup_key), + rule_cache_(rules), + supplied_(supplied), + retrieved_(BuildCallback(this, &OndemandSupplyTask::Load)), + success_(true) { + assert(rule_cache_ != NULL); + assert(retrieved_ != NULL); +} + +OndemandSupplyTask::~OndemandSupplyTask() { +} + +void OndemandSupplyTask::Queue(const std::string& key) { + assert(pending_.find(key) == pending_.end()); + pending_.insert(key); +} + +void OndemandSupplyTask::Retrieve(const Retriever& retriever) { + if (pending_.empty()) { + Loaded(); + } else { + // When the final pending rule has been retrieved, the retrieved_ callback, + // implemented by Load(), will finish by calling Loaded(), which will finish + // by delete'ing this OndemandSupplyTask object. So after the final call to + // retriever.Retrieve() no attributes of this object can be accessed (as the + // object then no longer will exist, if the final callback has finished by + // then), and the condition statement of the loop must therefore not use the + // otherwise obvious it != pending_.end() but instead test a local variable + // that isn't affected by the object being deleted. + bool done = false; + for (std::set<std::string>::const_iterator it = pending_.begin(); !done; ) { + const std::string& key = *it++; + done = it == pending_.end(); + retriever.Retrieve(key, *retrieved_); + } + } +} + +void OndemandSupplyTask::Load(bool success, + const std::string& key, + const std::string& data) { + size_t depth = std::count(key.begin(), key.end(), '/') - 1; + assert(depth < arraysize(LookupKey::kHierarchy)); + + // Sanity check: This key should be present in the set of pending requests. + size_t status = pending_.erase(key); + assert(status == 1); // There will always be one item erased from the set. + (void)status; // Prevent unused variable if assert() is optimized away. + + if (success) { + // The address metadata server will return the empty JSON "{}" when it + // successfully performed a lookup, but didn't find any data for that key. + if (data != "{}") { + Rule* rule = new Rule; + if (LookupKey::kHierarchy[depth] == COUNTRY) { + // All rules on the COUNTRY level inherit from the default rule. + rule->CopyFrom(Rule::GetDefault()); + } + if (rule->ParseSerializedRule(data)) { + // Try inserting the Rule object into the rule_cache_ map, or else find + // the already existing Rule object with the same ID already in the map. + // It is possible that a key was queued even though the corresponding + // Rule object is already in the cache, as the data server is free to do + // advanced normalization and aliasing so that the ID of the data + // returned is different from the key requested. (It would be possible + // to cache such aliases, to increase performance in the case where a + // certain alias is requested repeatedly, but such a cache would then + // have to be kept to some limited size to not grow indefinitely with + // every possible permutation of a name recognized by the data server.) + std::pair<std::map<std::string, const Rule*>::iterator, bool> result = + rule_cache_->insert(std::make_pair(rule->GetId(), rule)); + if (!result.second) { // There was already an entry with this ID. + delete rule; + } + // Pointer to object in the map. + hierarchy_.rule[depth] = result.first->second; + } else { + delete rule; + success_ = false; + } + } + } else { + success_ = false; + } + + if (pending_.empty()) { + Loaded(); + } +} + +void OndemandSupplyTask::Loaded() { + supplied_(success_, lookup_key_, hierarchy_); + delete this; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supply_task.h b/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supply_task.h new file mode 100644 index 00000000000..45b33c90508 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/ondemand_supply_task.h @@ -0,0 +1,71 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_ONDEMAND_SUPPLY_TASK_H_ +#define I18N_ADDRESSINPUT_ONDEMAND_SUPPLY_TASK_H_ + +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <map> +#include <set> +#include <string> + +#include "retriever.h" + +namespace i18n { +namespace addressinput { + +class LookupKey; +class Rule; + +// An OndemandSupplyTask object encapsulates the information necessary to +// retrieve the set of Rule objects corresponding to a LookupKey and call a +// callback when that has been done. Calling the Retrieve() method will load +// required metadata, then call the callback and delete the OndemandSupplyTask +// object itself. +class OndemandSupplyTask { + public: + OndemandSupplyTask(const LookupKey& lookup_key, + std::map<std::string, const Rule*>* rules, + const Supplier::Callback& supplied); + ~OndemandSupplyTask(); + + // Adds lookup key string |key| to the queue of data to be retrieved. + void Queue(const std::string& key); + + // Retrieves and parses data for all queued keys, then calls |supplied_|. + void Retrieve(const Retriever& retriever); + + Supplier::RuleHierarchy hierarchy_; + + private: + void Load(bool success, const std::string& key, const std::string& data); + void Loaded(); + + std::set<std::string> pending_; + const LookupKey& lookup_key_; + std::map<std::string, const Rule*>* const rule_cache_; + const Supplier::Callback& supplied_; + const scoped_ptr<const Retriever::Callback> retrieved_; + bool success_; + + DISALLOW_COPY_AND_ASSIGN(OndemandSupplyTask); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_ONDEMAND_SUPPLY_TASK_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/post_box_matchers.cc b/chromium/third_party/libaddressinput/src/cpp/src/post_box_matchers.cc new file mode 100644 index 00000000000..f1ad6dd6e95 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/post_box_matchers.cc @@ -0,0 +1,132 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "post_box_matchers.h" + +#include <cstddef> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include <re2/re2.h> + +#include "language.h" +#include "rule.h" +#include "util/re2ptr.h" + +namespace i18n { +namespace addressinput { + +namespace { + +std::map<std::string, const RE2ptr*> InitMatchers() { + static const struct { + const char* const language; + const RE2ptr ptr; + } kMatchers[] = { + { "ar", + /* "صندوق بريد|ص[-. ]ب" */ + new RE2("\xD8\xB5\xD9\x86\xD8\xAF\xD9\x88\xD9\x82 " + "\xD8\xA8\xD8\xB1\xD9\x8A\xD8\xAF|\xD8\xB5[-. ]\xD8\xA8") }, + + { "cs", new RE2("(?i)p\\.? ?p\\.? \\d") }, + { "da", new RE2("(?i)Postboks") }, + { "de", new RE2("(?i)Postfach") }, + + { "el", + /* "T\\.? ?Θ\\.? \\d{2}" */ + new RE2("(?i)T\\.? ?\xCE\x98\\.? \\d{2}") }, + + { "en", new RE2("Private Bag|Post(?:al)? Box") }, + { "es", new RE2("(?i)(?:Apartado|Casillas) de correos?") }, + { "fi", new RE2("(?i)Postilokero|P\\.?L\\.? \\d") }, + { "hr", new RE2("(?i)p\\.? ?p\\.? \\d") }, + + { "hu", + /* "Postafi(?:[oó]|ó)k|Pf\\.? \\d" */ + new RE2("(?i)Postafi(?:[o\xC3\xB3]|o\xCC\x81)k|Pf\\.? \\d") }, + + { "fr", + /* "Bo(?:[iî]|î)te Postale|BP \\d|CEDEX \\d" */ + new RE2("(?i)Bo(?:[i\xC3\xAE]|i\xCC\x82)te Postale|BP \\d|CEDEX \\d") }, + + { "ja", + /* "私書箱\\d{1,5}号" */ + new RE2("(?i)\xE7\xA7\x81\xE6\x9B\xB8\xE7\xAE\xB1\\d{1,5}\xE5\x8F\xB7") }, + + { "nl", new RE2("(?i)Postbus") }, + { "no", new RE2("(?i)Postboks") }, + { "pl", new RE2("(?i)Skr(?:\\.?|ytka) poczt(?:\\.?|owa)") }, + { "pt", new RE2("(?i)Apartado") }, + + { "ru", + /* "абонентский ящик|[аa]\\\" */ + new RE2("(?i)\xD0\xB0\xD0\xB1\xD0\xBE\xD0\xBD\xD0\xB5\xD0\xBD\xD1\x82\xD1" + "\x81\xD0\xBA\xD0\xB8\xD0\xB9 \xD1\x8F\xD1\x89\xD0\xB8\xD0\xBA|" + "[\xD0\xB0""a]\\\"\xD1\x8F (?:(?:\xE2\x84\x96|#|N) ?)?\\d") }, + + { "sv", new RE2("(?i)Box \\d") }, + + { "zh", + /* "郵政信箱.{1,5}號|郵局第.{1,10}號信箱" */ + new RE2("(?i)\xE9\x83\xB5\xE6\x94\xBF\xE4\xBF\xA1\xE7\xAE\xB1.{1,5}" + "\xE8\x99\x9F|\xE9\x83\xB5\xE5\xB1\x80\xE7\xAC\xAC.{1,10}" + "\xE8\x99\x9F\xE4\xBF\xA1\xE7\xAE\xB1") }, + + { "und", new RE2("P\\.? ?O\\.? Box") } + }; + + std::map<std::string, const RE2ptr*> matchers; + + for (size_t i = 0; i < sizeof kMatchers / sizeof *kMatchers; ++i) { + matchers.insert(std::make_pair(kMatchers[i].language, &kMatchers[i].ptr)); + } + + return matchers; +} + +} // namespace + +// static +std::vector<const RE2ptr*> PostBoxMatchers::GetMatchers( + const Rule& country_rule) { + static const std::map<std::string, const RE2ptr*> kMatchers(InitMatchers()); + + // Always add any expressions defined for "und" (English-like defaults). + std::vector<std::string> languages(1, "und"); + for (std::vector<std::string>::const_iterator + it = country_rule.GetLanguages().begin(); + it != country_rule.GetLanguages().end(); ++it) { + Language language(*it); + languages.push_back(language.base); + } + + std::vector<const RE2ptr*> result; + + for (std::vector<std::string>::const_iterator + it = languages.begin(); + it != languages.end(); ++it) { + std::map<std::string, const RE2ptr*>::const_iterator + jt = kMatchers.find(*it); + if (jt != kMatchers.end()) { + result.push_back(jt->second); + } + } + + return result; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/post_box_matchers.h b/chromium/third_party/libaddressinput/src/cpp/src/post_box_matchers.h new file mode 100644 index 00000000000..9924a2c5133 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/post_box_matchers.h @@ -0,0 +1,43 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// Post office box regular expressions. + +#ifndef I18N_ADDRESSINPUT_POST_BOX_MATCHERS_H_ +#define I18N_ADDRESSINPUT_POST_BOX_MATCHERS_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <vector> + +namespace i18n { +namespace addressinput { + +class Rule; +struct RE2ptr; + +class PostBoxMatchers { + public: + // Returns pointers to RE2 regular expression objects to test address lines + // for those languages that are relevant for |country_rule|. + static std::vector<const RE2ptr*> GetMatchers(const Rule& country_rule); + + private: + DISALLOW_COPY_AND_ASSIGN(PostBoxMatchers); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_POST_BOX_MATCHERS_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/preload_supplier.cc b/chromium/third_party/libaddressinput/src/cpp/src/preload_supplier.cc new file mode 100644 index 00000000000..79119bdbea1 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/preload_supplier.cc @@ -0,0 +1,373 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/preload_supplier.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/callback.h> +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <map> +#include <set> +#include <stack> +#include <string> +#include <utility> +#include <vector> + +#include "lookup_key.h" +#include "region_data_constants.h" +#include "retriever.h" +#include "rule.h" +#include "util/json.h" +#include "util/string_compare.h" + +namespace i18n { +namespace addressinput { + +namespace { + +// STL predicate less<> that uses StringCompare to match strings that a human +// reader would consider to be "the same". The default implementation just does +// case insensitive string comparison, but StringCompare can be overriden with +// more sophisticated implementations. +class IndexLess : public std::binary_function<std::string, std::string, bool> { + public: + result_type operator()(const first_argument_type& a, + const second_argument_type& b) const { + static const StringCompare kStringCompare; + return kStringCompare.NaturalLess(a, b); + } +}; + +} // namespace + +class IndexMap : public std::map<std::string, const Rule*, IndexLess> {}; + +namespace { + +class Helper { + public: + // Does not take ownership of its parameters. + Helper(const std::string& region_code, + const std::string& key, + const PreloadSupplier::Callback& loaded, + const Retriever& retriever, + std::set<std::string>* pending, + IndexMap* rule_index, + std::vector<const Rule*>* rule_storage, + std::map<std::string, const Rule*>* region_rules) + : region_code_(region_code), + loaded_(loaded), + pending_(pending), + rule_index_(rule_index), + rule_storage_(rule_storage), + region_rules_(region_rules), + retrieved_(BuildCallback(this, &Helper::OnRetrieved)) { + assert(pending_ != NULL); + assert(rule_index_ != NULL); + assert(rule_storage_ != NULL); + assert(region_rules_ != NULL); + assert(retrieved_ != NULL); + pending_->insert(key); + retriever.Retrieve(key, *retrieved_); + } + + private: + ~Helper() {} + + void OnRetrieved(bool success, + const std::string& key, + const std::string& data) { + int rule_count = 0; + + size_t status = pending_->erase(key); + assert(status == 1); // There will always be one item erased from the set. + (void)status; // Prevent unused variable if assert() is optimized away. + + Json json; + std::string id; + std::vector<const Rule*> sub_rules; + + IndexMap::iterator last_index_it = rule_index_->end(); + IndexMap::iterator last_latin_it = rule_index_->end(); + std::map<std::string, const Rule*>::iterator last_region_it = + region_rules_->end(); + + IndexMap::const_iterator hints[arraysize(LookupKey::kHierarchy) - 1]; + std::fill(hints, hints + arraysize(hints), rule_index_->end()); + + if (!success) { + goto callback; + } + + if (!json.ParseObject(data)) { + success = false; + goto callback; + } + + for (std::vector<const Json*>::const_iterator + it = json.GetSubDictionaries().begin(); + it != json.GetSubDictionaries().end(); + ++it) { + const Json* value = *it; + assert(value != NULL); + if (!value->GetStringValueForKey("id", &id)) { + success = false; + goto callback; + } + assert(!id.empty()); + + size_t depth = std::count(id.begin(), id.end(), '/') - 1; + assert(depth < arraysize(LookupKey::kHierarchy)); + AddressField field = LookupKey::kHierarchy[depth]; + + Rule* rule = new Rule; + if (field == COUNTRY) { + // All rules on the COUNTRY level inherit from the default rule. + rule->CopyFrom(Rule::GetDefault()); + } + rule->ParseJsonRule(*value); + assert(id == rule->GetId()); // Sanity check. + + rule_storage_->push_back(rule); + if (depth > 0) { + sub_rules.push_back(rule); + } + + // Add the ID of this Rule object to the rule index with natural string + // comparison for keys. + last_index_it = + rule_index_->insert(last_index_it, std::make_pair(id, rule)); + + // Add the ID of this Rule object to the region-specific rule index with + // exact string comparison for keys. + last_region_it = + region_rules_->insert(last_region_it, std::make_pair(id, rule)); + + ++rule_count; + } + + /* + * Normally the address metadata server takes care of mapping from natural + * language names to metadata IDs (eg. "São Paulo" -> "SP") and from Latin + * script names to local script names (eg. "Tokushima" -> "徳島県"). + * + * As the PreloadSupplier doesn't contact the metadata server upon each + * Supply() request, it instead has an internal lookup table (rule_index_) + * that contains such mappings. + * + * This lookup table is populated by iterating over all sub rules and for + * each of them construct ID strings using human readable names (eg. "São + * Paulo") and using Latin script names (eg. "Tokushima"). + */ + for (std::vector<const Rule*>::const_iterator + it = sub_rules.begin(); it != sub_rules.end(); ++it) { + std::stack<const Rule*> hierarchy; + hierarchy.push(*it); + + // Push pointers to all parent Rule objects onto the hierarchy stack. + for (std::string parent_id((*it)->GetId());;) { + // Strip the last part of parent_id. Break if COUNTRY level is reached. + std::string::size_type pos = parent_id.rfind('/'); + if (pos == sizeof "data/ZZ" - 1) { + break; + } + parent_id.resize(pos); + + IndexMap::const_iterator* const hint = &hints[hierarchy.size() - 1]; + if (*hint == rule_index_->end() || (*hint)->first != parent_id) { + *hint = rule_index_->find(parent_id); + } + assert(*hint != rule_index_->end()); + hierarchy.push((*hint)->second); + } + + std::string human_id((*it)->GetId().substr(0, sizeof "data/ZZ" - 1)); + std::string latin_id(human_id); + + // Append the names from all Rule objects on the hierarchy stack. + for (; !hierarchy.empty(); hierarchy.pop()) { + const Rule* rule = hierarchy.top(); + + human_id.push_back('/'); + if (!rule->GetName().empty()) { + human_id.append(rule->GetName()); + } else { + // If the "name" field is empty, the name is the last part of the ID. + const std::string& id = rule->GetId(); + std::string::size_type pos = id.rfind('/'); + assert(pos != std::string::npos); + human_id.append(id.substr(pos + 1)); + } + + if (!rule->GetLatinName().empty()) { + latin_id.push_back('/'); + latin_id.append(rule->GetLatinName()); + } + } + + // If the ID has a language tag, copy it. + { + const std::string& id = (*it)->GetId(); + std::string::size_type pos = id.rfind("--"); + if (pos != std::string::npos) { + human_id.append(id, pos, id.size() - pos); + } + } + + last_index_it = + rule_index_->insert(last_index_it, std::make_pair(human_id, *it)); + + // Add the Latin script ID, if a Latin script name could be found for + // every part of the ID. + if (std::count(human_id.begin(), human_id.end(), '/') == + std::count(latin_id.begin(), latin_id.end(), '/')) { + last_latin_it = + rule_index_->insert(last_latin_it, std::make_pair(latin_id, *it)); + } + } + + callback: + loaded_(success, region_code_, rule_count); + delete this; + } + + const std::string region_code_; + const PreloadSupplier::Callback& loaded_; + std::set<std::string>* const pending_; + IndexMap* const rule_index_; + std::vector<const Rule*>* const rule_storage_; + std::map<std::string, const Rule*>* const region_rules_; + const scoped_ptr<const Retriever::Callback> retrieved_; + + DISALLOW_COPY_AND_ASSIGN(Helper); +}; + +std::string KeyFromRegionCode(const std::string& region_code) { + AddressData address; + address.region_code = region_code; + LookupKey lookup_key; + lookup_key.FromAddress(address); + return lookup_key.ToKeyString(0); // Zero depth = COUNTRY level. +} + +} // namespace + +PreloadSupplier::PreloadSupplier(const Source* source, Storage* storage) + : retriever_(new Retriever(source, storage)), + pending_(), + rule_index_(new IndexMap), + rule_storage_(), + region_rules_() {} + +PreloadSupplier::~PreloadSupplier() { + for (std::vector<const Rule*>::const_iterator + it = rule_storage_.begin(); it != rule_storage_.end(); ++it) { + delete *it; + } +} + +void PreloadSupplier::Supply(const LookupKey& lookup_key, + const Supplier::Callback& supplied) { + Supplier::RuleHierarchy hierarchy; + bool success = GetRuleHierarchy(lookup_key, &hierarchy); + supplied(success, lookup_key, hierarchy); +} + +const Rule* PreloadSupplier::GetRule(const LookupKey& lookup_key) const { + assert(IsLoaded(lookup_key.GetRegionCode())); + Supplier::RuleHierarchy hierarchy; + if (!GetRuleHierarchy(lookup_key, &hierarchy)) { + return NULL; + } + return hierarchy.rule[lookup_key.GetDepth()]; +} + +void PreloadSupplier::LoadRules(const std::string& region_code, + const Callback& loaded) { + const std::string& key = KeyFromRegionCode(region_code); + + if (IsLoadedKey(key)) { + loaded(true, region_code, 0); + return; + } + + if (IsPendingKey(key)) { + return; + } + + new Helper( + region_code, + key, + loaded, + *retriever_, + &pending_, + rule_index_.get(), + &rule_storage_, + ®ion_rules_[region_code]); +} + +const std::map<std::string, const Rule*>& PreloadSupplier::GetRulesForRegion( + const std::string& region_code) const { + assert(IsLoaded(region_code)); + return region_rules_.find(region_code)->second; +} + +bool PreloadSupplier::IsLoaded(const std::string& region_code) const { + return IsLoadedKey(KeyFromRegionCode(region_code)); +} + +bool PreloadSupplier::IsPending(const std::string& region_code) const { + return IsPendingKey(KeyFromRegionCode(region_code)); +} + +bool PreloadSupplier::GetRuleHierarchy(const LookupKey& lookup_key, + RuleHierarchy* hierarchy) const { + assert(hierarchy != NULL); + + if (RegionDataConstants::IsSupported(lookup_key.GetRegionCode())) { + size_t max_depth = std::min( + lookup_key.GetDepth(), + RegionDataConstants::GetMaxLookupKeyDepth(lookup_key.GetRegionCode())); + + for (size_t depth = 0; depth <= max_depth; ++depth) { + const std::string& key = lookup_key.ToKeyString(depth); + IndexMap::const_iterator it = rule_index_->find(key); + if (it == rule_index_->end()) { + return depth > 0; // No data on COUNTRY level is failure. + } + hierarchy->rule[depth] = it->second; + } + } + + return true; +} + +bool PreloadSupplier::IsLoadedKey(const std::string& key) const { + return rule_index_->find(key) != rule_index_->end(); +} + +bool PreloadSupplier::IsPendingKey(const std::string& key) const { + return pending_.find(key) != pending_.end(); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/region_data.cc b/chromium/third_party/libaddressinput/src/cpp/src/region_data.cc new file mode 100644 index 00000000000..798501edcd9 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/region_data.cc @@ -0,0 +1,50 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/region_data.h> + +#include <cstddef> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +RegionData::RegionData(const std::string& region_code) + : key_(region_code), + name_(region_code), + parent_(NULL), + sub_regions_() {} + +RegionData::~RegionData() { + for (std::vector<const RegionData*>::const_iterator it = sub_regions_.begin(); + it != sub_regions_.end(); ++it) { + delete *it; + } +} + +RegionData* RegionData::AddSubRegion(const std::string& key, + const std::string& name) { + RegionData* sub_region = new RegionData(key, name, this); + sub_regions_.push_back(sub_region); + return sub_region; +} + +RegionData::RegionData(const std::string& key, + const std::string& name, + RegionData* parent) + : key_(key), name_(name), parent_(parent), sub_regions_() {} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/region_data_builder.cc b/chromium/third_party/libaddressinput/src/cpp/src/region_data_builder.cc new file mode 100644 index 00000000000..b600d09ab06 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/region_data_builder.cc @@ -0,0 +1,189 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include <libaddressinput/region_data_builder.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/preload_supplier.h> +#include <libaddressinput/region_data.h> +#include <libaddressinput/util/basictypes.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <utility> +#include <vector> + +#include "language.h" +#include "lookup_key.h" +#include "region_data_constants.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +namespace { + +// The maximum depth of lookup keys. +static const size_t kLookupKeysMaxDepth = arraysize(LookupKey::kHierarchy) - 1; + +// Does not take ownership of |parent_region|, which is not allowed to be NULL. +void BuildRegionTreeRecursively( + const std::map<std::string, const Rule*>& rules, + std::map<std::string, const Rule*>::const_iterator hint, + const LookupKey& parent_key, + RegionData* parent_region, + const std::vector<std::string>& keys, + bool prefer_latin_name, + size_t region_max_depth) { + assert(parent_region != NULL); + + LookupKey lookup_key; + for (std::vector<std::string>::const_iterator key_it = keys.begin(); + key_it != keys.end(); ++key_it) { + lookup_key.FromLookupKey(parent_key, *key_it); + const std::string& lookup_key_string = + lookup_key.ToKeyString(kLookupKeysMaxDepth); + + ++hint; + if (hint == rules.end() || hint->first != lookup_key_string) { + hint = rules.find(lookup_key_string); + if (hint == rules.end()) { + return; + } + } + + const Rule* rule = hint->second; + assert(rule != NULL); + + const std::string& local_name = rule->GetName().empty() + ? *key_it : rule->GetName(); + const std::string& name = + prefer_latin_name && !rule->GetLatinName().empty() + ? rule->GetLatinName() : local_name; + RegionData* region = parent_region->AddSubRegion(*key_it, name); + + if (!rule->GetSubKeys().empty() && + region_max_depth > parent_key.GetDepth()) { + BuildRegionTreeRecursively(rules, + hint, + lookup_key, + region, + rule->GetSubKeys(), + prefer_latin_name, + region_max_depth); + } + } +} + +// The caller owns the result. +RegionData* BuildRegion(const std::map<std::string, const Rule*>& rules, + const std::string& region_code, + const Language& language) { + AddressData address; + address.region_code = region_code; + + LookupKey lookup_key; + lookup_key.FromAddress(address); + + std::map<std::string, const Rule*>::const_iterator hint = + rules.find(lookup_key.ToKeyString(kLookupKeysMaxDepth)); + assert(hint != rules.end()); + + const Rule* rule = hint->second; + assert(rule != NULL); + + RegionData* region = new RegionData(region_code); + + // If there're sub-keys for field X, but field X is not used in this region + // code, then these sub-keys are skipped over. For example, CH has sub-keys + // for field ADMIN_AREA, but CH does not use ADMIN_AREA field. + size_t region_max_depth = + RegionDataConstants::GetMaxLookupKeyDepth(region_code); + if (region_max_depth > 0) { + BuildRegionTreeRecursively(rules, + hint, + lookup_key, + region, + rule->GetSubKeys(), + language.has_latin_script, + region_max_depth); + } + + return region; +} + +} // namespace + +RegionDataBuilder::RegionDataBuilder(PreloadSupplier* supplier) + : supplier_(supplier), + cache_() { + assert(supplier_ != NULL); +} + +RegionDataBuilder::~RegionDataBuilder() { + for (RegionCodeDataMap::const_iterator region_it = cache_.begin(); + region_it != cache_.end(); ++region_it) { + for (LanguageRegionMap::const_iterator + language_it = region_it->second->begin(); + language_it != region_it->second->end(); ++language_it) { + delete language_it->second; + } + delete region_it->second; + } +} + +const RegionData& RegionDataBuilder::Build( + const std::string& region_code, + const std::string& ui_language_tag, + std::string* best_region_tree_language_tag) { + assert(supplier_->IsLoaded(region_code)); + assert(best_region_tree_language_tag != NULL); + + // Look up the region tree in cache first before building it. + RegionCodeDataMap::const_iterator region_it = cache_.find(region_code); + if (region_it == cache_.end()) { + region_it = + cache_.insert(std::make_pair(region_code, new LanguageRegionMap)).first; + } + + // No need to copy from default rule first, because only languages and Latin + // format are going to be used, which do not exist in the default rule. + Rule rule; + rule.ParseSerializedRule(RegionDataConstants::GetRegionData(region_code)); + static const Language kUndefinedLanguage("und"); + const Language& best_language = + rule.GetLanguages().empty() + ? kUndefinedLanguage + : ChooseBestAddressLanguage(rule, Language(ui_language_tag)); + *best_region_tree_language_tag = best_language.tag; + + LanguageRegionMap::const_iterator language_it = + region_it->second->find(best_language.tag); + if (language_it == region_it->second->end()) { + const std::map<std::string, const Rule*>& rules = + supplier_->GetRulesForRegion(region_code); + language_it = + region_it->second->insert(std::make_pair(best_language.tag, + BuildRegion(rules, + region_code, + best_language))) + .first; + } + + return *language_it->second; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/region_data_constants.cc b/chromium/third_party/libaddressinput/src/cpp/src/region_data_constants.cc new file mode 100644 index 00000000000..a44a310eb3b --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/region_data_constants.cc @@ -0,0 +1,1508 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// The data in this file is automatically generated. + +#include "region_data_constants.h" + +#include <libaddressinput/address_field.h> +#include <libaddressinput/util/basictypes.h> + +#include <algorithm> +#include <cstddef> +#include <map> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "address_field_util.h" +#include "format_element.h" +#include "lookup_key.h" + +namespace i18n { +namespace addressinput { + +// ---- BEGIN AUTOGENERATED CODE ---- +namespace { + +std::map<std::string, std::string> InitRegionData() { + std::map<std::string, std::string> region_data; + region_data.insert(std::make_pair("AC", "{" + "\"zipex\":\"ASCN 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("AD", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"AD100,AD501,AD700\"," + "\"posturl\":\"http://www.correos.es/comun/CodigosPostales/1010_s-CodPostal.asp\?Provincia=\"," + "\"languages\":\"ca\"" + "}")); + region_data.insert(std::make_pair("AE", "{" + "\"fmt\":\"%N%n%O%n%A%n%S\"," + "\"lfmt\":\"%N%n%O%n%A%n%S\"," + "\"require\":\"AS\"," + "\"state_name_type\":\"emirate\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("AF", "{" + "\"zipex\":\"1001,2601,3801\"," + "\"posturl\":\"http://afghanpost.gov.af/Postal%20Code/\"," + "\"languages\":\"fa~ps\"" + "}")); + region_data.insert(std::make_pair("AG", "{" + "\"require\":\"A\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("AI", "{" + "\"zipex\":\"2640\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("AL", "{" + "\"zipex\":\"1001,1017,3501\"," + "\"languages\":\"sq\"" + "}")); + region_data.insert(std::make_pair("AM", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z%n%C%n%S\"," + "\"lfmt\":\"%N%n%O%n%A%n%Z%n%C%n%S\"," + "\"zipex\":\"375010,0002,0010\"," + "\"languages\":\"hy\"" + "}")); + region_data.insert(std::make_pair("AO", "{" + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("AQ", "{" + "\"languages\":\"\"" + "}")); + region_data.insert(std::make_pair("AR", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C%n%S\"," + "\"zipex\":\"C1070AAM,C1000WAM,B1000TBU,X5187XAB\"," + "\"posturl\":\"http://www.correoargentino.com.ar/formularios/cpa\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("AS", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96799\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"sm~en\"" + "}")); + region_data.insert(std::make_pair("AT", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"1010,3741\"," + "\"posturl\":\"http://www.post.at/post_subsite_postleitzahlfinder.php\"," + "\"languages\":\"de\"" + "}")); + region_data.insert(std::make_pair("AU", "{" + "\"fmt\":\"%O%n%N%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"2060,3171,6430,4000,4006,3001\"," + "\"posturl\":\"http://www1.auspost.com.au/postcodes/\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("AW", "{" + "\"languages\":\"nl~pap\"" + "}")); + region_data.insert(std::make_pair("AX", "{" + "\"fmt\":\"%O%n%N%n%A%nAX-%Z %C%n\\u00c5LAND\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"22150,22550,22240,22710,22270,22730,22430\"," + "\"posturl\":\"http://www.posten.ax/department.con\?iPage=123\"," + "\"languages\":\"sv\"" + "}")); + region_data.insert(std::make_pair("AZ", "{" + "\"fmt\":\"%N%n%O%n%A%nAZ %Z %C\"," + "\"zipex\":\"1000\"," + "\"languages\":\"az-Latn~az-Cyrl\"" + "}")); + region_data.insert(std::make_pair("BA", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"71000\"," + "\"posturl\":\"http://www.post.ba/postanski_brojevi.php\"," + "\"languages\":\"bs-Cyrl~bs-Latn~hr~sr-Cyrl~sr-Latn\"" + "}")); + region_data.insert(std::make_pair("BB", "{" + "\"state_name_type\":\"parish\"," + "\"zipex\":\"BB23026,BB22025\"," + "\"posturl\":\"http://barbadospostal.com/zipcodes.html\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("BD", "{" + "\"fmt\":\"%N%n%O%n%A%n%C - %Z\"," + "\"zipex\":\"1340,1000\"," + "\"posturl\":\"http://www.bangladeshpost.gov.bd/PostCode.asp\"," + "\"languages\":\"bn\"" + "}")); + region_data.insert(std::make_pair("BE", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"4000,1000\"," + "\"posturl\":\"http://www.post.be/site/nl/residential/customerservice/search/postal_codes.html\"," + "\"languages\":\"nl~fr~de\"" + "}")); + region_data.insert(std::make_pair("BF", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %X\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("BG", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1000,1700\"," + "\"posturl\":\"http://www.bgpost.bg/\?cid=5\"," + "\"languages\":\"bg\"" + "}")); + region_data.insert(std::make_pair("BH", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"317\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("BI", "{" + "\"languages\":\"rn~fr\"" + "}")); + region_data.insert(std::make_pair("BJ", "{" + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("BL", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97100\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("BM", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"FL 07,HM GX,HM 12\"," + "\"posturl\":\"http://www.landvaluation.bm/\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("BN", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"BT2328,KA1131,BA1511\"," + "\"posturl\":\"http://www.post.gov.bn/index.php/extensions/postcode-guide\"," + "\"languages\":\"ms-Latn~ms-Arab\"" + "}")); + region_data.insert(std::make_pair("BO", "{" + "\"languages\":\"es~qu~ay\"" + "}")); + region_data.insert(std::make_pair("BQ", "{" + "\"languages\":\"nl\"" + "}")); + region_data.insert(std::make_pair("BR", "{" + "\"fmt\":\"%O%n%N%n%A%n%D%n%C-%S%n%Z\"," + "\"require\":\"ASCZ\"," + "\"state_name_type\":\"state\"," + "\"sublocality_name_type\":\"neighborhood\"," + "\"zipex\":\"40301-110,70002-900\"," + "\"posturl\":\"http://www.buscacep.correios.com.br/\"," + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("BS", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %S\"," + "\"state_name_type\":\"island\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("BT", "{" + "\"zipex\":\"11001,31101,35003\"," + "\"posturl\":\"http://www.bhutanpost.com.bt/postcode/postcode.php\"," + "\"languages\":\"dz\"" + "}")); + region_data.insert(std::make_pair("BV", "{" + "\"languages\":\"\"" + "}")); + region_data.insert(std::make_pair("BW", "{" + "\"languages\":\"en~tn\"" + "}")); + region_data.insert(std::make_pair("BY", "{" + "\"fmt\":\"%S%n%Z %C %X%n%A%n%O%n%N\"," + "\"zipex\":\"223016,225860,220050\"," + "\"posturl\":\"http://zip.belpost.by\"," + "\"languages\":\"be~ru\"" + "}")); + region_data.insert(std::make_pair("BZ", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("CA", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zipex\":\"H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1\"," + "\"posturl\":\"http://www.canadapost.ca/cpotools/apps/fpc/personal/findByCity\?execution=e2s1\"," + "\"languages\":\"en~fr\"" + "}")); + region_data.insert(std::make_pair("CC", "{" + "\"fmt\":\"%O%n%N%n%A%n%C %S %Z\"," + "\"zipex\":\"6799\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("CD", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %X\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("CF", "{" + "\"languages\":\"fr~sg\"" + "}")); + region_data.insert(std::make_pair("CG", "{" + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("CH", "{" + "\"fmt\":\"%O%n%N%n%A%nCH-%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"2544,1211,1556,3030\"," + "\"posturl\":\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\"," + "\"languages\":\"de~fr~it\"" + "}")); + region_data.insert(std::make_pair("CI", "{" + "\"fmt\":\"%N%n%O%n%X %A %C %X\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("CK", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("CL", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C%n%S\"," + "\"zipex\":\"8340457,8720019,1230000,8329100\"," + "\"posturl\":\"http://www.correos.cl/SitePages/home.aspx\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("CM", "{" + "\"languages\":\"fr~en\"" + "}")); + region_data.insert(std::make_pair("CN", "{" + "\"fmt\":\"%Z%n%S%C%D%n%A%n%O%n%N\"," + "\"lfmt\":\"%N%n%O%n%A%n%D%n%C%n%S, %Z\"," + "\"require\":\"ACSZ\"," + "\"sublocality_name_type\":\"district\"," + "\"zipex\":\"266033,317204,100096,100808\"," + "\"posturl\":\"http://www.cpdc.com.cn/postcdQueryAction.do\?reqCode=gotoQueryPostAddr\"," + "\"languages\":\"zh\"" + "}")); + region_data.insert(std::make_pair("CO", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %S, %Z\"," + "\"zipex\":\"111221,130001,760011\"," + "\"posturl\":\"http://www.codigopostal.gov.co/\"," + "\"state_name_type\":\"department\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("CR", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1000,2010,1001\"," + "\"posturl\":\"https://www.correos.go.cr/nosotros/codigopostal/busqueda.html\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("CV", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C%n%S\"," + "\"state_name_type\":\"island\"," + "\"zipex\":\"7600\"," + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("CW", "{" + "\"languages\":\"pap~nl\"" + "}")); + region_data.insert(std::make_pair("CX", "{" + "\"fmt\":\"%O%n%N%n%A%n%C %S %Z\"," + "\"zipex\":\"6798\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("CY", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"2008,3304,1900\"," + "\"languages\":\"el~tr\"" + "}")); + region_data.insert(std::make_pair("CZ", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"100 00,251 66,530 87,110 00,225 99\"," + "\"posturl\":\"http://psc.ceskaposta.cz/CleanForm.action\"," + "\"languages\":\"cs\"" + "}")); + region_data.insert(std::make_pair("DE", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"26133,53225\"," + "\"posturl\":\"http://www.postdirekt.de/plzserver/\"," + "\"languages\":\"de\"" + "}")); + region_data.insert(std::make_pair("DJ", "{" + "\"languages\":\"ar~fr\"" + "}")); + region_data.insert(std::make_pair("DK", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"8660,1566\"," + "\"posturl\":\"http://www.postdanmark.dk/da/Privat/Kundeservice/postnummerkort/Sider/Find-postnummer.aspx\"," + "\"languages\":\"da\"" + "}")); + region_data.insert(std::make_pair("DM", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("DO", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"11903,10101\"," + "\"posturl\":\"http://inposdom.gob.do/servicios/codigo-postal.html#buscar_codigo\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("DZ", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"40304,16027\"," + "\"languages\":\"ar~fr\"" + "}")); + region_data.insert(std::make_pair("EC", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z%n%C\"," + "\"zipex\":\"090105,EC090112,H0103C,P0133B,P0133A,P0133V\"," + "\"languages\":\"es~qu\"" + "}")); + region_data.insert(std::make_pair("EE", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"69501,11212\"," + "\"posturl\":\"http://www.post.ee/\?op=sihtnumbriotsing\"," + "\"languages\":\"et\"" + "}")); + region_data.insert(std::make_pair("EG", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"lfmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"zipex\":\"12411,11599\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("EH", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"70000,72000\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("ER", "{" + "\"languages\":\"ti~en~ar\"" + "}")); + region_data.insert(std::make_pair("ES", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C %S\"," + "\"require\":\"ACSZ\"," + "\"zipex\":\"28039,28300,28070\"," + "\"posturl\":\"http://www.correos.es/contenido/13-MenuRec2/04-MenuRec24/1010_s-CodPostal.asp\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("ET", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1000\"," + "\"languages\":\"am\"" + "}")); + region_data.insert(std::make_pair("FI", "{" + "\"fmt\":\"%O%n%N%n%A%nFI-%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"00550,00011\"," + "\"posturl\":\"http://www.verkkoposti.com/e3/postinumeroluettelo\"," + "\"languages\":\"fi~sv\"" + "}")); + region_data.insert(std::make_pair("FJ", "{" + "\"languages\":\"en~hif-Deva~fj\"" + "}")); + region_data.insert(std::make_pair("FK", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"FIQQ 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("FM", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96941,96944\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("FO", "{" + "\"fmt\":\"%N%n%O%n%A%nFO%Z %C\"," + "\"zipex\":\"100\"," + "\"posturl\":\"http://www.postur.fo/\"," + "\"languages\":\"fo\"" + "}")); + region_data.insert(std::make_pair("FR", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"33380,34092,33506\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("GA", "{" + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("GB", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"require\":\"ACZ\"," + "\"state_name_type\":\"county\"," + "\"locality_name_type\":\"post_town\"," + "\"zipex\":\"EC1Y 8SY,GIR 0AA,M2 5BQ,M34 4AB,CR0 2YR,DN16 9AA,W1A 4ZZ,EC1A 1HQ,OX14 4PG,BS18 8HF,NR25 7HG,RH6 0NP,BH23 6AA,B6 5BA,SO23 9AP,PO1 3AX,BFPO 61\"," + "\"posturl\":\"http://www.royalmail.com/postcode-finder\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("GD", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("GE", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"0101\"," + "\"posturl\":\"http://www.georgianpost.ge/index.php\?page=10\"," + "\"languages\":\"ka\"" + "}")); + region_data.insert(std::make_pair("GF", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97300\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("GG", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%nGUERNSEY%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"GY1 1AA,GY2 2BT\"," + "\"posturl\":\"http://www.guernseypost.com/postcode_finder/\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("GH", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("GI", "{" + "\"fmt\":\"%N%n%O%n%A%nGIBRALTAR%n%Z\"," + "\"require\":\"A\"," + "\"zipex\":\"GX11 1AA\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("GL", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"3900,3950,3911\"," + "\"languages\":\"kl\"" + "}")); + region_data.insert(std::make_pair("GM", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("GN", "{" + "\"fmt\":\"%N%n%O%n%Z %A %C\"," + "\"zipex\":\"001,200,100\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("GP", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97100\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("GQ", "{" + "\"languages\":\"es~fr\"" + "}")); + region_data.insert(std::make_pair("GR", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"151 24,151 10,101 88\"," + "\"posturl\":\"http://www.elta.gr/findapostcode.aspx\"," + "\"languages\":\"el\"" + "}")); + region_data.insert(std::make_pair("GS", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"SIQQ 1ZZ\"," + "\"languages\":\"\"" + "}")); + region_data.insert(std::make_pair("GT", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z- %C\"," + "\"zipex\":\"09001,01501\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("GU", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96910,96931\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"en~ch\"" + "}")); + region_data.insert(std::make_pair("GW", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1000,1011\"," + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("GY", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("HK", "{" + "\"fmt\":\"%S%n%C%n%A%n%O%n%N\"," + "\"lfmt\":\"%N%n%O%n%A%n%C%n%S\"," + "\"require\":\"AS\"," + "\"state_name_type\":\"area\"," + "\"locality_name_type\":\"district\"," + "\"languages\":\"zh-Hant~en\"" + "}")); + region_data.insert(std::make_pair("HM", "{" + "\"fmt\":\"%O%n%N%n%A%n%C %S %Z\"," + "\"zipex\":\"7050\"," + "\"languages\":\"\"" + "}")); + region_data.insert(std::make_pair("HN", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %S%n%Z\"," + "\"require\":\"ACS\"," + "\"zipex\":\"31301\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("HR", "{" + "\"fmt\":\"%N%n%O%n%A%nHR-%Z %C\"," + "\"zipex\":\"10000,21001,10002\"," + "\"posturl\":\"http://www.posta.hr/default.aspx\?pretpum\"," + "\"languages\":\"hr\"" + "}")); + region_data.insert(std::make_pair("HT", "{" + "\"fmt\":\"%N%n%O%n%A%nHT%Z %C %X\"," + "\"zipex\":\"6120,5310,6110,8510\"," + "\"languages\":\"ht~fr\"" + "}")); + region_data.insert(std::make_pair("HU", "{" + "\"fmt\":\"%N%n%O%n%C%n%A%n%Z\"," + "\"zipex\":\"1037,2380,1540\"," + "\"posturl\":\"http://posta.hu/ugyfelszolgalat/iranyitoszam_kereso\"," + "\"languages\":\"hu\"" + "}")); + region_data.insert(std::make_pair("ID", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S %Z\"," + "\"state_name_type\":\"district\"," + "\"zipex\":\"40115\"," + "\"languages\":\"id\"" + "}")); + region_data.insert(std::make_pair("IE", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S\"," + "\"state_name_type\":\"county\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("IL", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"9614303\"," + "\"posturl\":\"http://www.israelpost.co.il/zipcode.nsf/demozip\?openform\"," + "\"languages\":\"iw~ar\"" + "}")); + region_data.insert(std::make_pair("IM", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"IM2 1AA,IM99 1PS\"," + "\"posturl\":\"http://www.gov.im/post/postal/fr_main.asp\"," + "\"languages\":\"en~gv\"" + "}")); + region_data.insert(std::make_pair("IN", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z%n%S\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"pin\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"110034,110001\"," + "\"posturl\":\"http://www.indiapost.gov.in/pin/pinsearch.aspx\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("IO", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"BBND 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("IQ", "{" + "\"fmt\":\"%O%n%N%n%A%n%C, %S%n%Z\"," + "\"require\":\"ACS\"," + "\"zipex\":\"31001\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("IR", "{" + "\"fmt\":\"%O%n%N%n%S%n%C, %D%n%A%n%Z\"," + "\"sublocality_name_type\":\"neighborhood\"," + "\"zipex\":\"11936-12345\"," + "\"languages\":\"fa\"" + "}")); + region_data.insert(std::make_pair("IS", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"320,121,220,110\"," + "\"posturl\":\"http://www.postur.is/cgi-bin/hsrun.exe/Distributed/vefur/vefur.htx;start=HS_landakort_postnumer\"," + "\"languages\":\"is\"" + "}")); + region_data.insert(std::make_pair("IT", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C %S\"," + "\"require\":\"ACSZ\"," + "\"zipex\":\"00144,47037,39049\"," + "\"posturl\":\"http://www.poste.it/online/cercacap/\"," + "\"languages\":\"it\"" + "}")); + region_data.insert(std::make_pair("JE", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%nJERSEY%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"JE1 1AA,JE2 2BT\"," + "\"posturl\":\"http://www.jerseypost.com/tools/postcode-address-finder/\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("JM", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S %X\"," + "\"require\":\"ACS\"," + "\"state_name_type\":\"parish\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("JO", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"11937,11190\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("JP", "{" + "\"fmt\":\"\\u3012%Z%n%S%C%n%A%n%O%n%N\"," + "\"lfmt\":\"%N%n%O%n%A%n%C, %S%n%Z\"," + "\"require\":\"ACSZ\"," + "\"state_name_type\":\"prefecture\"," + "\"zipex\":\"154-0023,350-1106,951-8073,112-0001,208-0032,231-0012\"," + "\"posturl\":\"http://search.post.japanpost.jp/zipcode/\"," + "\"languages\":\"ja\"" + "}")); + region_data.insert(std::make_pair("KE", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%Z\"," + "\"zipex\":\"20100,00100\"," + "\"languages\":\"en~sw\"" + "}")); + region_data.insert(std::make_pair("KG", "{" + "\"fmt\":\"%Z %C %X%n%A%n%O%n%N\"," + "\"zipex\":\"720001\"," + "\"languages\":\"ky-Cyrl~ru\"" + "}")); + region_data.insert(std::make_pair("KH", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"12203,14206,12000\"," + "\"languages\":\"km\"" + "}")); + region_data.insert(std::make_pair("KI", "{" + "\"fmt\":\"%N%n%O%n%A%n%S%n%C\"," + "\"state_name_type\":\"island\"," + "\"languages\":\"en~gil\"" + "}")); + region_data.insert(std::make_pair("KM", "{" + "\"languages\":\"ar~fr~zdj\"" + "}")); + region_data.insert(std::make_pair("KN", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %S\"," + "\"require\":\"ACS\"," + "\"state_name_type\":\"island\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("KR", "{" + "\"fmt\":\"%S %C%D%n%A%n%O%n%N%n%Z\"," + "\"lfmt\":\"%N%n%O%n%A%n%D%n%C%n%S%n%Z\"," + "\"require\":\"ACSZ\"," + "\"state_name_type\":\"do_si\"," + "\"sublocality_name_type\":\"district\"," + "\"zipex\":\"110-110,699-800\"," + "\"posturl\":\"http://www.epost.go.kr/search/zipcode/search5.jsp\"," + "\"languages\":\"ko\"" + "}")); + region_data.insert(std::make_pair("KW", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"54541,54551,54404,13009\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("KY", "{" + "\"fmt\":\"%N%n%O%n%A%n%S %Z\"," + "\"require\":\"AS\"," + "\"state_name_type\":\"island\"," + "\"zipex\":\"KY1-1100,KY1-1702,KY2-2101\"," + "\"posturl\":\"http://www.caymanpost.gov.ky/portal/page\?_pageid=3561,1&_dad=portal&_schema=PORTAL\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("KZ", "{" + "\"fmt\":\"%Z%n%S%n%C%n%A%n%O%n%N\"," + "\"zipex\":\"040900,050012\"," + "\"languages\":\"ru~kk-Cyrl\"" + "}")); + region_data.insert(std::make_pair("LA", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"01160,01000\"," + "\"languages\":\"lo\"" + "}")); + region_data.insert(std::make_pair("LB", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"2038 3054,1107 2810,1000\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("LC", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("LI", "{" + "\"fmt\":\"%O%n%N%n%A%nFL-%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"9496,9491,9490,9485\"," + "\"posturl\":\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\"," + "\"languages\":\"de~gsw\"" + "}")); + region_data.insert(std::make_pair("LK", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%Z\"," + "\"zipex\":\"20000,00100\"," + "\"posturl\":\"http://www.slpost.gov.lk/\"," + "\"languages\":\"si~ta\"" + "}")); + region_data.insert(std::make_pair("LR", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C %X\"," + "\"zipex\":\"1000\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("LS", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"100\"," + "\"languages\":\"st~en\"" + "}")); + region_data.insert(std::make_pair("LT", "{" + "\"fmt\":\"%O%n%N%n%A%nLT-%Z %C\"," + "\"zipex\":\"04340,03500\"," + "\"posturl\":\"http://www.post.lt/lt/\?id=316\"," + "\"languages\":\"lt\"" + "}")); + region_data.insert(std::make_pair("LU", "{" + "\"fmt\":\"%O%n%N%n%A%nL-%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"4750,2998\"," + "\"posturl\":\"http://www.pt.lu/portal/services_en_ligne/recherche_codes_postaux\"," + "\"languages\":\"fr~lb~de\"" + "}")); + region_data.insert(std::make_pair("LV", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %Z\"," + "\"zipex\":\"LV-1073,LV-1000\"," + "\"posturl\":\"http://www.pasts.lv/lv/uzzinas/nodalas/\"," + "\"languages\":\"lv\"" + "}")); + region_data.insert(std::make_pair("LY", "{" + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("MA", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"53000,10000,20050,16052\"," + "\"languages\":\"ar~fr~tzm-Latn\"" + "}")); + region_data.insert(std::make_pair("MC", "{" + "\"fmt\":\"%N%n%O%n%A%nMC-%Z %C %X\"," + "\"zipex\":\"98000,98020,98011,98001\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("MD", "{" + "\"fmt\":\"%N%n%O%n%A%nMD-%Z %C\"," + "\"zipex\":\"2012,2019\"," + "\"languages\":\"ro\"" + "}")); + region_data.insert(std::make_pair("ME", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"81257,81258,81217,84314,85366\"," + "\"languages\":\"sr-Latn\"" + "}")); + region_data.insert(std::make_pair("MF", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97100\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("MG", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"501,101\"," + "\"languages\":\"mg~fr~en\"" + "}")); + region_data.insert(std::make_pair("MH", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96960,96970\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"en~mh\"" + "}")); + region_data.insert(std::make_pair("MK", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1314,1321,1443,1062\"," + "\"languages\":\"mk\"" + "}")); + region_data.insert(std::make_pair("ML", "{" + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("MM", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %Z\"," + "\"zipex\":\"11181\"," + "\"languages\":\"my\"" + "}")); + region_data.insert(std::make_pair("MN", "{" + "\"fmt\":\"%N%n%O%n%A%n%S %C-%X%n%Z\"," + "\"zipex\":\"65030,65270\"," + "\"posturl\":\"http://www.zipcode.mn/\"," + "\"languages\":\"mn-Cyrl\"" + "}")); + region_data.insert(std::make_pair("MO", "{" + "\"fmt\":\"%A%n%O%n%N\"," + "\"lfmt\":\"%N%n%O%n%A\"," + "\"require\":\"A\"," + "\"languages\":\"zh-Hant~pt\"" + "}")); + region_data.insert(std::make_pair("MP", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96950,96951,96952\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("MQ", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97220\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("MR", "{" + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("MS", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("MT", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"NXR 01,ZTN 05,GPO 01,BZN 1130,SPB 6031,VCT 1753\"," + "\"posturl\":\"http://postcodes.maltapost.com/\"," + "\"languages\":\"mt~en\"" + "}")); + region_data.insert(std::make_pair("MU", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z%n%C\"," + "\"zipex\":\"42602\"," + "\"languages\":\"en~fr\"" + "}")); + region_data.insert(std::make_pair("MV", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"20026\"," + "\"posturl\":\"http://www.maldivespost.com/\?lid=10\"," + "\"languages\":\"dv\"" + "}")); + region_data.insert(std::make_pair("MW", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %X\"," + "\"languages\":\"en~ny\"" + "}")); + region_data.insert(std::make_pair("MX", "{" + "\"fmt\":\"%N%n%O%n%A%n%D%n%Z %C, %S\"," + "\"require\":\"ACZ\"," + "\"state_name_type\":\"state\"," + "\"sublocality_name_type\":\"neighborhood\"," + "\"zipex\":\"02860,77520,06082\"," + "\"posturl\":\"http://www.correosdemexico.gob.mx/ServiciosLinea/Paginas/ccpostales.aspx\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("MY", "{" + "\"fmt\":\"%N%n%O%n%A%n%D%n%Z %C%n%S\"," + "\"require\":\"ACZ\"," + "\"state_name_type\":\"state\"," + "\"sublocality_name_type\":\"village_township\"," + "\"zipex\":\"43000,50754,88990,50670\"," + "\"posturl\":\"http://www.pos.com.my/pos/homepage.aspx\"," + "\"languages\":\"ms\"" + "}")); + region_data.insert(std::make_pair("MZ", "{" + "\"zipex\":\"1102,1119,3212\"," + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("NA", "{" + "\"languages\":\"af~en\"" + "}")); + region_data.insert(std::make_pair("NC", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"98814,98800,98810\"," + "\"posturl\":\"http://poste.opt.nc/index.php\?option=com_content&view=article&id=80&Itemid=131\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("NE", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"8001\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("NF", "{" + "\"fmt\":\"%O%n%N%n%A%n%C %S %Z\"," + "\"zipex\":\"2899\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("NG", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z%n%S\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"930283,300001,931104\"," + "\"posturl\":\"http://www.nigeriapostcodes.com/views/\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("NI", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z%n%C, %S\"," + "\"state_name_type\":\"department\"," + "\"zipex\":\"52000\"," + "\"posturl\":\"http://www.correos.gob.ni/index.php/codigo-postal-2\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("NL", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"1234 AB,2490 AA\"," + "\"posturl\":\"http://www.postnl.nl/voorthuis/\"," + "\"languages\":\"nl\"" + "}")); + region_data.insert(std::make_pair("NO", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"0025,0107,6631\"," + "\"posturl\":\"http://adressesok.posten.no/nb/postal_codes/search\"," + "\"languages\":\"no~nn\"" + "}")); + region_data.insert(std::make_pair("NP", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"44601\"," + "\"posturl\":\"http://www.gpo.gov.np/postalcode.aspx\"," + "\"languages\":\"ne\"" + "}")); + region_data.insert(std::make_pair("NR", "{" + "\"fmt\":\"%N%n%O%n%A%n%S\"," + "\"require\":\"AS\"," + "\"state_name_type\":\"district\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("NU", "{" + "\"languages\":\"en~niu\"" + "}")); + region_data.insert(std::make_pair("NZ", "{" + "\"fmt\":\"%N%n%O%n%A%n%D%n%C %Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"6001,6015,6332,8252,1030\"," + "\"posturl\":\"http://www.nzpost.co.nz/Cultures/en-NZ/OnlineTools/PostCodeFinder/\"," + "\"languages\":\"en~mi\"" + "}")); + region_data.insert(std::make_pair("OM", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z%n%C\"," + "\"zipex\":\"133,112,111\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("PA", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("PE", "{" + "\"zipex\":\"LIMA 23,LIMA 42,CALLAO 2,02001\"," + "\"posturl\":\"http://www.serpost.com.pe/cpostal/codigo\"," + "\"languages\":\"es~qu\"" + "}")); + region_data.insert(std::make_pair("PF", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C %S\"," + "\"require\":\"ACSZ\"," + "\"state_name_type\":\"island\"," + "\"zipex\":\"98709\"," + "\"languages\":\"fr~ty\"" + "}")); + region_data.insert(std::make_pair("PG", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z %S\"," + "\"require\":\"ACS\"," + "\"zipex\":\"111\"," + "\"languages\":\"tpi~en~ho\"" + "}")); + region_data.insert(std::make_pair("PH", "{" + "\"fmt\":\"%N%n%O%n%A%n%D, %C%n%Z %S\"," + "\"zipex\":\"1008,1050,1135,1207,2000,1000\"," + "\"posturl\":\"http://www.philpost.gov.ph/\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("PK", "{" + "\"fmt\":\"%N%n%O%n%A%n%C-%Z\"," + "\"zipex\":\"44000\"," + "\"posturl\":\"http://www.pakpost.gov.pk/postcode/postcode.html\"," + "\"languages\":\"ur~en\"" + "}")); + region_data.insert(std::make_pair("PL", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"00-950,05-470,48-300,32-015,00-940\"," + "\"posturl\":\"http://www.poczta-polska.pl/kody.php\"," + "\"languages\":\"pl\"" + "}")); + region_data.insert(std::make_pair("PM", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97500\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("PN", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"PCRN 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("PR", "{" + "\"fmt\":\"%N%n%O%n%A%n%C PR %Z\"," + "\"require\":\"ACZ\"," + "\"zip_name_type\":\"zip\"," + "\"zipex\":\"00930\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"es~en\"" + "}")); + region_data.insert(std::make_pair("PS", "{" + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("PT", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"2725-079,1250-096,1201-950,2860-571,1208-148\"," + "\"posturl\":\"http://www.ctt.pt/feapl_2/app/open/tools.jspx\?tool=1\"," + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("PW", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96940\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"pau~en\"" + "}")); + region_data.insert(std::make_pair("PY", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1536,1538,1209\"," + "\"languages\":\"gn~es\"" + "}")); + region_data.insert(std::make_pair("QA", "{" + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("RE", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97400\"," + "\"posturl\":\"http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("RO", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"060274,061357,200716\"," + "\"posturl\":\"http://www.posta-romana.ro/zip_codes\"," + "\"languages\":\"ro\"" + "}")); + region_data.insert(std::make_pair("RS", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"106314\"," + "\"posturl\":\"http://www.posta.rs/struktura/lat/aplikacije/pronadji/nadji-postu.asp\"," + "\"languages\":\"sr-Cyrl~sr-Latn\"" + "}")); + region_data.insert(std::make_pair("RU", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"lfmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"require\":\"ACZ\"," + "\"state_name_type\":\"oblast\"," + "\"zipex\":\"247112,103375,188300\"," + "\"posturl\":\"http://info.russianpost.ru/servlet/department\"," + "\"languages\":\"ru\"" + "}")); + region_data.insert(std::make_pair("RW", "{" + "\"languages\":\"rw~fr~en\"" + "}")); + region_data.insert(std::make_pair("SA", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z\"," + "\"zipex\":\"11564,11187,11142\"," + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("SB", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("SC", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S\"," + "\"state_name_type\":\"island\"," + "\"languages\":\"fr~en\"" + "}")); + region_data.insert(std::make_pair("SE", "{" + "\"fmt\":\"%O%n%N%n%A%nSE-%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"11455,12345,10500\"," + "\"posturl\":\"http://www.posten.se/sv/Kundservice/Sidor/Sok-postnummer-resultat.aspx\"," + "\"languages\":\"sv\"" + "}")); + region_data.insert(std::make_pair("SG", "{" + "\"fmt\":\"%N%n%O%n%A%nSINGAPORE %Z\"," + "\"require\":\"AZ\"," + "\"zipex\":\"546080,308125,408600\"," + "\"posturl\":\"http://www.singpost.com.sg/quick_services/index.htm\"," + "\"languages\":\"en~zh-Hans~ms-Latn~ta\"" + "}")); + region_data.insert(std::make_pair("SH", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"STHL 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("SI", "{" + "\"fmt\":\"%N%n%O%n%A%nSI- %Z %C\"," + "\"zipex\":\"4000,1001,2500\"," + "\"languages\":\"sl\"" + "}")); + region_data.insert(std::make_pair("SJ", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"9170\"," + "\"posturl\":\"http://epab.posten.no/\"," + "\"languages\":\"no\"" + "}")); + region_data.insert(std::make_pair("SK", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"010 01,023 14,972 48,921 01,975 99\"," + "\"posturl\":\"http://psc.posta.sk\"," + "\"languages\":\"sk\"" + "}")); + region_data.insert(std::make_pair("SL", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("SM", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"require\":\"AZ\"," + "\"zipex\":\"47890,47891,47895,47899\"," + "\"posturl\":\"http://www.poste.it/online/cercacap/\"," + "\"languages\":\"it\"" + "}")); + region_data.insert(std::make_pair("SN", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"12500,46024,16556,10000\"," + "\"languages\":\"wo~fr\"" + "}")); + region_data.insert(std::make_pair("SO", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %S %Z\"," + "\"require\":\"ACS\"," + "\"zipex\":\"09010,11010\"," + "\"languages\":\"so\"" + "}")); + region_data.insert(std::make_pair("SR", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %X%n%S\"," + "\"languages\":\"nl\"" + "}")); + region_data.insert(std::make_pair("SS", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("ST", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %X\"," + "\"languages\":\"pt\"" + "}")); + region_data.insert(std::make_pair("SV", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z-%C%n%S\"," + "\"require\":\"ACS\"," + "\"zipex\":\"CP 1101\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("SX", "{" + "\"languages\":\"en~nl\"" + "}")); + region_data.insert(std::make_pair("SZ", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%Z\"," + "\"zipex\":\"H100\"," + "\"posturl\":\"http://www.sptc.co.sz/swazipost/codes.php\"," + "\"languages\":\"en~ss\"" + "}")); + region_data.insert(std::make_pair("TA", "{" + "\"zipex\":\"TDCU 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("TC", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"TKCA 1ZZ\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("TD", "{" + "\"languages\":\"fr~ar\"" + "}")); + region_data.insert(std::make_pair("TF", "{" + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("TG", "{" + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("TH", "{" + "\"fmt\":\"%N%n%O%n%A%n%D %C%n%S %Z\"," + "\"lfmt\":\"%N%n%O%n%A%n%D, %C%n%S %Z\"," + "\"zipex\":\"10150,10210\"," + "\"languages\":\"th\"" + "}")); + region_data.insert(std::make_pair("TJ", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"735450,734025\"," + "\"languages\":\"tg-Cyrl\"" + "}")); + region_data.insert(std::make_pair("TK", "{" + "\"languages\":\"en~tkl\"" + "}")); + region_data.insert(std::make_pair("TL", "{" + "\"languages\":\"pt~tet\"" + "}")); + region_data.insert(std::make_pair("TM", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"744000\"," + "\"languages\":\"tk-Latn\"" + "}")); + region_data.insert(std::make_pair("TN", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"1002,8129,3100,1030\"," + "\"posturl\":\"http://www.poste.tn/codes.php\"," + "\"languages\":\"ar~fr\"" + "}")); + region_data.insert(std::make_pair("TO", "{" + "\"languages\":\"to~en\"" + "}")); + region_data.insert(std::make_pair("TR", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C/%S\"," + "\"require\":\"ACZ\"," + "\"locality_name_type\":\"district\"," + "\"zipex\":\"01960,06101\"," + "\"posturl\":\"http://postakodu.ptt.gov.tr/\"," + "\"languages\":\"tr\"" + "}")); + region_data.insert(std::make_pair("TT", "{" + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("TV", "{" + "\"fmt\":\"%N%n%O%n%A%n%X%n%C%n%S\"," + "\"state_name_type\":\"island\"," + "\"languages\":\"tyv\"" + "}")); + region_data.insert(std::make_pair("TW", "{" + "\"fmt\":\"%Z%n%S%C%n%A%n%O%n%N\"," + "\"lfmt\":\"%N%n%O%n%A%n%C, %S %Z\"," + "\"require\":\"ACSZ\"," + "\"state_name_type\":\"county\"," + "\"zipex\":\"104,106,10603,40867\"," + "\"posturl\":\"http://www.post.gov.tw/post/internet/f_searchzone/index.jsp\?ID=190102\"," + "\"languages\":\"zh-Hant\"" + "}")); + region_data.insert(std::make_pair("TZ", "{" + "\"zipex\":\"6090\"," + "\"languages\":\"sw~en\"" + "}")); + region_data.insert(std::make_pair("UA", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"lfmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\"," + "\"require\":\"ACZ\"," + "\"state_name_type\":\"oblast\"," + "\"zipex\":\"15432,01055,01001\"," + "\"posturl\":\"http://services.ukrposhta.com/postindex_new/\"," + "\"languages\":\"uk\"" + "}")); + region_data.insert(std::make_pair("UG", "{" + "\"languages\":\"sw~en\"" + "}")); + region_data.insert(std::make_pair("UM", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACS\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"96898\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("US", "{" + "\"fmt\":\"%N%n%O%n%A%n%C, %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"95014,22162-1010\"," + "\"posturl\":\"https://tools.usps.com/go/ZipLookupAction!input.action\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("UY", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C %S\"," + "\"zipex\":\"11600\"," + "\"posturl\":\"http://www.correo.com.uy/index.asp\?codPag=codPost&switchMapa=codPost\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("UZ", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C%n%S\"," + "\"zipex\":\"702100,700000\"," + "\"posturl\":\"http://www.pochta.uz/index.php/uz/pochta-indekslari/9\"," + "\"languages\":\"uz-Latn~uz-Cyrl\"" + "}")); + region_data.insert(std::make_pair("VA", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"00120\"," + "\"languages\":\"it~la\"" + "}")); + region_data.insert(std::make_pair("VC", "{" + "\"zipex\":\"VC0100,VC0110,VC0400\"," + "\"posturl\":\"http://www.svgpost.gov.vc/\?option=com_content&view=article&id=3&Itemid=16\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("VE", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %Z, %S\"," + "\"require\":\"ACS\"," + "\"zipex\":\"1010,3001,8011,1020\"," + "\"posturl\":\"http://www.ipostel.gob.ve/nlinea/codigo_postal.php\"," + "\"languages\":\"es\"" + "}")); + region_data.insert(std::make_pair("VG", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%Z\"," + "\"require\":\"A\"," + "\"zipex\":\"VG1110,VG1150,VG1160\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("VI", "{" + "\"fmt\":\"%N%n%O%n%A%n%C %S %Z\"," + "\"require\":\"ACSZ\"," + "\"zip_name_type\":\"zip\"," + "\"state_name_type\":\"state\"," + "\"zipex\":\"00802-1222,00850-9802\"," + "\"posturl\":\"http://zip4.usps.com/zip4/welcome.jsp\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("VN", "{" + "\"fmt\":\"%N%n%O%n%A%n%C%n%S %Z\"," + "\"lfmt\":\"%N%n%O%n%A%n%C%n%S %Z\"," + "\"zipex\":\"119415,136065,720344\"," + "\"posturl\":\"http://postcode.vnpost.vn/services/search.aspx\"," + "\"languages\":\"vi\"" + "}")); + region_data.insert(std::make_pair("VU", "{" + "\"languages\":\"bi~en~fr\"" + "}")); + region_data.insert(std::make_pair("WF", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"98600\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("WS", "{" + "\"languages\":\"sm~en\"" + "}")); + region_data.insert(std::make_pair("XK", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"10000\"," + "\"languages\":\"sq~sr-Cyrl~sr-Latn\"" + "}")); + region_data.insert(std::make_pair("YE", "{" + "\"languages\":\"ar\"" + "}")); + region_data.insert(std::make_pair("YT", "{" + "\"fmt\":\"%O%n%N%n%A%n%Z %C %X\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"97600\"," + "\"languages\":\"fr\"" + "}")); + region_data.insert(std::make_pair("ZA", "{" + "\"fmt\":\"%N%n%O%n%A%n%D%n%C%n%Z\"," + "\"require\":\"ACZ\"," + "\"zipex\":\"0083,1451,0001\"," + "\"posturl\":\"http://www.postoffice.co.za/tools/postalcode.html\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("ZM", "{" + "\"fmt\":\"%N%n%O%n%A%n%Z %C\"," + "\"zipex\":\"50100,50101\"," + "\"languages\":\"en\"" + "}")); + region_data.insert(std::make_pair("ZW", "{" + "\"languages\":\"en~sn~nd\"" + "}")); + return region_data; +} + +} // namespace + +// static +const std::string& RegionDataConstants::GetDefaultRegionData() { + static const std::string kDefaultRegionData( + "{" + "\"fmt\":\"%N%n%O%n%A%n%C\"," + "\"require\":\"AC\"," + "\"zip_name_type\":\"postal\"," + "\"state_name_type\":\"province\"," + "\"locality_name_type\":\"city\"," + "\"sublocality_name_type\":\"suburb\"" + "}"); + return kDefaultRegionData; +} +// ---- END AUTOGENERATED CODE ---- + +namespace { + +const std::map<std::string, std::string>& GetAllRegionData() { + static const std::map<std::string, std::string> kRegionData(InitRegionData()); + return kRegionData; +} + +struct SelectFirst { + template <typename Pair> + const typename Pair::first_type& operator()(const Pair& pair) const { + return pair.first; + } +}; + +std::vector<std::string> InitRegionCodes() { + std::vector<std::string> region_codes(GetAllRegionData().size()); + std::transform(GetAllRegionData().begin(), + GetAllRegionData().end(), + region_codes.begin(), + SelectFirst()); + return region_codes; +} + +const std::map<std::string, size_t> InitMaxLookupKeyDepth() { + std::map<std::string, size_t> max_depth; + for (std::map<std::string, std::string>::const_iterator + it = GetAllRegionData().begin(); it != GetAllRegionData().end(); ++it) { + std::vector<FormatElement> fields; + // Here it->second actually contains the entire JSON blob for this region, + // and not only the format field, but it doesn't really matter when just + // checking whether a particular formatting code (eg. "%C") is present, as + // there isn't anything else in the JSON that erroneously could match a + // formatting code. + ParseFormatRule(it->second, &fields); + size_t depth = 1; + for (; depth < arraysize(LookupKey::kHierarchy); ++depth) { + AddressField field = LookupKey::kHierarchy[depth]; + // Check to see if a particular field in the hierarchy is used by + // addresses in this country. If not, the maximum depth has been reached. + if (std::find(fields.begin(), fields.end(), FormatElement(field)) == + fields.end()) { + break; + } + } + max_depth.insert(std::make_pair(it->first, depth - 1)); + } + return max_depth; +} + +} // namespace + +// static +const bool RegionDataConstants::IsSupported(const std::string& region_code) { + static const std::set<std::string> kRegionCodes(GetRegionCodes().begin(), + GetRegionCodes().end()); + return kRegionCodes.find(region_code) != kRegionCodes.end(); +} + +// static +const std::vector<std::string>& RegionDataConstants::GetRegionCodes() { + static const std::vector<std::string> kRegionCodes(InitRegionCodes()); + return kRegionCodes; +} + +// static +const std::string& RegionDataConstants::GetRegionData( + const std::string& region_code) { + static const std::string kEmptyString; + std::map<std::string, std::string>::const_iterator it = + GetAllRegionData().find(region_code); + return it != GetAllRegionData().end() ? it->second : kEmptyString; +} + +// static +size_t RegionDataConstants::GetMaxLookupKeyDepth( + const std::string& region_code) { + static const std::map<std::string, size_t> kMaxDepth(InitMaxLookupKeyDepth()); + std::map<std::string, size_t>::const_iterator it = + kMaxDepth.find(region_code); + return it != kMaxDepth.end() ? it->second : 0; +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/region_data_constants.h b/chromium/third_party/libaddressinput/src/cpp/src/region_data_constants.h new file mode 100644 index 00000000000..4159e722ccb --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/region_data_constants.h @@ -0,0 +1,42 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_REGION_DATA_CONSTANTS_H_ +#define I18N_ADDRESSINPUT_REGION_DATA_CONSTANTS_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <cstddef> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +class RegionDataConstants { + public: + static const bool IsSupported(const std::string& region_code); + static const std::vector<std::string>& GetRegionCodes(); + static const std::string& GetRegionData(const std::string& region_code); + static const std::string& GetDefaultRegionData(); + static size_t GetMaxLookupKeyDepth(const std::string& region_code); + + private: + DISALLOW_COPY_AND_ASSIGN(RegionDataConstants); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_REGION_DATA_CONSTANTS_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/retriever.cc b/chromium/third_party/libaddressinput/src/cpp/src/retriever.cc new file mode 100644 index 00000000000..151b74d65a8 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/retriever.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include "retriever.h" + +#include <libaddressinput/callback.h> +#include <libaddressinput/source.h> +#include <libaddressinput/storage.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <cassert> +#include <cstddef> +#include <string> + +#include "validating_storage.h" + +namespace i18n { +namespace addressinput { + +namespace { + +class Helper { + public: + // Does not take ownership of its parameters. + Helper(const std::string& key, + const Retriever::Callback& retrieved, + const Source& source, + ValidatingStorage* storage) + : retrieved_(retrieved), + source_(source), + storage_(storage), + fresh_data_ready_(BuildCallback(this, &Helper::OnFreshDataReady)), + validated_data_ready_( + BuildCallback(this, &Helper::OnValidatedDataReady)), + stale_data_() { + assert(storage_ != NULL); + storage_->Get(key, *validated_data_ready_); + } + + private: + ~Helper() {} + + void OnValidatedDataReady(bool success, + const std::string& key, + std::string* data) { + if (success) { + assert(data != NULL); + retrieved_(success, key, *data); + delete this; + } else { + // Validating storage returns (false, key, stale-data) for valid but stale + // data. If |data| is empty, however, then it's either missing or invalid. + if (data != NULL && !data->empty()) { + stale_data_ = *data; + } + source_.Get(key, *fresh_data_ready_); + } + delete data; + } + + void OnFreshDataReady(bool success, + const std::string& key, + std::string* data) { + if (success) { + assert(data != NULL); + retrieved_(true, key, *data); + storage_->Put(key, data); + data = NULL; // Deleted by Storage::Put(). + } else if (!stale_data_.empty()) { + // Reuse the stale data if a download fails. It's better to have slightly + // outdated validation rules than to suddenly lose validation ability. + retrieved_(true, key, stale_data_); + } else { + retrieved_(false, key, std::string()); + } + delete data; + delete this; + } + + const Retriever::Callback& retrieved_; + const Source& source_; + ValidatingStorage* storage_; + const scoped_ptr<const Source::Callback> fresh_data_ready_; + const scoped_ptr<const Storage::Callback> validated_data_ready_; + std::string stale_data_; + + DISALLOW_COPY_AND_ASSIGN(Helper); +}; + +} // namespace + +Retriever::Retriever(const Source* source, Storage* storage) + : source_(source), storage_(new ValidatingStorage(storage)) { + assert(source_ != NULL); + assert(storage_ != NULL); +} + +Retriever::~Retriever() {} + +void Retriever::Retrieve(const std::string& key, + const Callback& retrieved) const { + new Helper(key, retrieved, *source_, storage_.get()); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/retriever.h b/chromium/third_party/libaddressinput/src/cpp/src/retriever.h new file mode 100644 index 00000000000..4bf27a5d06c --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/retriever.h @@ -0,0 +1,68 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// An object to retrieve data. + +#ifndef I18N_ADDRESSINPUT_RETRIEVER_H_ +#define I18N_ADDRESSINPUT_RETRIEVER_H_ + +#include <libaddressinput/callback.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +class Source; +class Storage; +class ValidatingStorage; + +// Retrieves data. Sample usage: +// Source* source = ...; +// Storage* storage = ...; +// Retriever retriever(source, storage); +// const scoped_ptr<const Retriever::Callback> retrieved( +// BuildCallback(this, &MyClass::OnDataRetrieved)); +// retriever.Retrieve("data/CA/AB--fr", *retrieved); +class Retriever { + public: + typedef i18n::addressinput::Callback<const std::string&, + const std::string&> Callback; + + // Takes ownership of |source| and |storage|. + Retriever(const Source* source, Storage* storage); + ~Retriever(); + + // Retrieves the data for |key| and invokes the |retrieved| callback. Checks + // for the data in |storage_| first. If storage does not have the data for + // |key|, then gets the data from |source_| and places it in storage. If the + // data in storage is corrupted, then it's discarded and requested anew. If + // the data is stale, then it's requested anew. If the request fails, then + // stale data will be returned this one time. Any subsequent call to + // Retrieve() will attempt to get fresh data again. + void Retrieve(const std::string& key, const Callback& retrieved) const; + + private: + scoped_ptr<const Source> source_; + scoped_ptr<ValidatingStorage> storage_; + + DISALLOW_COPY_AND_ASSIGN(Retriever); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_RETRIEVER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/rule.cc b/chromium/third_party/libaddressinput/src/cpp/src/rule.cc new file mode 100644 index 00000000000..c3d2c22dd88 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/rule.cc @@ -0,0 +1,306 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include "rule.h" + +#include <cassert> +#include <cstddef> +#include <map> +#include <string> +#include <utility> + +#include <re2/re2.h> + +#include "address_field_util.h" +#include "format_element.h" +#include "grit.h" +#include "messages.h" +#include "region_data_constants.h" +#include "util/json.h" +#include "util/re2ptr.h" +#include "util/string_split.h" + +namespace i18n { +namespace addressinput { + +namespace { + +typedef std::map<std::string, int> NameMessageIdMap; + +// Used as a separator in a list of items. For example, the list of supported +// languages can be "de~fr~it". +const char kSeparator = '~'; + +NameMessageIdMap InitAdminAreaMessageIds() { + NameMessageIdMap message_ids; + message_ids.insert(std::make_pair( + "area", IDS_LIBADDRESSINPUT_AREA)); + message_ids.insert(std::make_pair( + "county", IDS_LIBADDRESSINPUT_COUNTY)); + message_ids.insert(std::make_pair( + "department", IDS_LIBADDRESSINPUT_DEPARTMENT)); + message_ids.insert(std::make_pair( + "district", IDS_LIBADDRESSINPUT_DISTRICT)); + message_ids.insert(std::make_pair( + "do_si", IDS_LIBADDRESSINPUT_DO_SI)); + message_ids.insert(std::make_pair( + "emirate", IDS_LIBADDRESSINPUT_EMIRATE)); + message_ids.insert(std::make_pair( + "island", IDS_LIBADDRESSINPUT_ISLAND)); + message_ids.insert(std::make_pair( + "oblast", IDS_LIBADDRESSINPUT_OBLAST)); + message_ids.insert(std::make_pair( + "parish", IDS_LIBADDRESSINPUT_PARISH)); + message_ids.insert(std::make_pair( + "prefecture", IDS_LIBADDRESSINPUT_PREFECTURE)); + message_ids.insert(std::make_pair( + "province", IDS_LIBADDRESSINPUT_PROVINCE)); + message_ids.insert(std::make_pair( + "state", IDS_LIBADDRESSINPUT_STATE)); + return message_ids; +} + +const NameMessageIdMap& GetAdminAreaMessageIds() { + static const NameMessageIdMap kAdminAreaMessageIds(InitAdminAreaMessageIds()); + return kAdminAreaMessageIds; +} + +NameMessageIdMap InitPostalCodeMessageIds() { + NameMessageIdMap message_ids; + message_ids.insert(std::make_pair( + "pin", IDS_LIBADDRESSINPUT_PIN_CODE_LABEL)); + message_ids.insert(std::make_pair( + "postal", IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL)); + message_ids.insert(std::make_pair( + "zip", IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL)); + return message_ids; +} + +const NameMessageIdMap& GetPostalCodeMessageIds() { + static const NameMessageIdMap kPostalCodeMessageIds( + InitPostalCodeMessageIds()); + return kPostalCodeMessageIds; +} + +NameMessageIdMap InitLocalityMessageIds() { + NameMessageIdMap message_ids; + message_ids.insert(std::make_pair( + "city", IDS_LIBADDRESSINPUT_LOCALITY_LABEL)); + message_ids.insert(std::make_pair( + "post_town", IDS_LIBADDRESSINPUT_POST_TOWN)); + message_ids.insert(std::make_pair( + "district", IDS_LIBADDRESSINPUT_DISTRICT)); + return message_ids; +} + +const NameMessageIdMap& GetLocalityMessageIds() { + static const NameMessageIdMap kLocalityMessageIds( + InitLocalityMessageIds()); + return kLocalityMessageIds; +} + +NameMessageIdMap InitSublocalityMessageIds() { + NameMessageIdMap message_ids; + message_ids.insert(std::make_pair( + "suburb", IDS_LIBADDRESSINPUT_SUBURB)); + message_ids.insert(std::make_pair( + "district", IDS_LIBADDRESSINPUT_DISTRICT)); + message_ids.insert(std::make_pair( + "neighborhood", IDS_LIBADDRESSINPUT_NEIGHBORHOOD)); + message_ids.insert(std::make_pair( + "village_township", IDS_LIBADDRESSINPUT_VILLAGE_TOWNSHIP)); + return message_ids; +} + +const NameMessageIdMap& GetSublocalityMessageIds() { + static const NameMessageIdMap kSublocalityMessageIds( + InitSublocalityMessageIds()); + return kSublocalityMessageIds; +} + +int GetMessageIdFromName(const std::string& name, + const NameMessageIdMap& message_ids) { + NameMessageIdMap::const_iterator it = message_ids.find(name); + return it != message_ids.end() ? it->second : INVALID_MESSAGE_ID; +} + +// Determines whether a given string is a reg-exp or a string. We consider a +// string to be anything that doesn't contain characters with special meanings +// in regular expressions - (, [, \, {, ?. These special characters are all the +// ones that appear in the postal code regular expressions. +bool ContainsRegExSpecialCharacters(const std::string& input) { + return input.find_first_of("([\\{?") != std::string::npos; +} + +} // namespace + +Rule::Rule() + : id_(), + format_(), + latin_format_(), + required_(), + sub_keys_(), + languages_(), + postal_code_matcher_(NULL), + sole_postal_code_(), + admin_area_name_message_id_(INVALID_MESSAGE_ID), + postal_code_name_message_id_(INVALID_MESSAGE_ID), + locality_name_message_id_(INVALID_MESSAGE_ID), + sublocality_name_message_id_(INVALID_MESSAGE_ID), + name_(), + latin_name_(), + postal_code_example_(), + post_service_url_() {} + +Rule::~Rule() {} + +// static +const Rule& Rule::GetDefault() { + // Allocated once and leaked on shutdown. + static Rule* default_rule = NULL; + if (default_rule == NULL) { + default_rule = new Rule; + default_rule->ParseSerializedRule( + RegionDataConstants::GetDefaultRegionData()); + } + return *default_rule; +} + +void Rule::CopyFrom(const Rule& rule) { + assert(this != &rule); + id_ = rule.id_; + format_ = rule.format_; + latin_format_ = rule.latin_format_; + required_ = rule.required_; + sub_keys_ = rule.sub_keys_; + languages_ = rule.languages_; + postal_code_matcher_.reset( + rule.postal_code_matcher_ == NULL + ? NULL + : new RE2ptr(new RE2(rule.postal_code_matcher_->ptr->pattern(), + rule.postal_code_matcher_->ptr->options()))); + sole_postal_code_ = rule.sole_postal_code_; + admin_area_name_message_id_ = rule.admin_area_name_message_id_; + postal_code_name_message_id_ = rule.postal_code_name_message_id_; + locality_name_message_id_ = rule.locality_name_message_id_; + sublocality_name_message_id_ = rule.sublocality_name_message_id_; + name_ = rule.name_; + latin_name_ = rule.latin_name_; + postal_code_example_ = rule.postal_code_example_; + post_service_url_ = rule.post_service_url_; +} + +bool Rule::ParseSerializedRule(const std::string& serialized_rule) { + Json json; + if (!json.ParseObject(serialized_rule)) { + return false; + } + ParseJsonRule(json); + return true; +} + +void Rule::ParseJsonRule(const Json& json) { + std::string value; + if (json.GetStringValueForKey("id", &value)) { + id_.swap(value); + } + + if (json.GetStringValueForKey("fmt", &value)) { + ParseFormatRule(value, &format_); + } + + if (json.GetStringValueForKey("lfmt", &value)) { + ParseFormatRule(value, &latin_format_); + } + + if (json.GetStringValueForKey("require", &value)) { + ParseAddressFieldsRequired(value, &required_); + } + + if (json.GetStringValueForKey("sub_keys", &value)) { + SplitString(value, kSeparator, &sub_keys_); + } + + if (json.GetStringValueForKey("languages", &value)) { + SplitString(value, kSeparator, &languages_); + } + + sole_postal_code_.clear(); + if (json.GetStringValueForKey("zip", &value)) { + // The "zip" field in the JSON data is used in two different ways to + // validate the postal code. At the country level, the "zip" field indicates + // a Java compatible regular expression corresponding to all postal codes in + // the country. At other levels, the regular expression indicates the postal + // code prefix expected for addresses in that region. + // + // In order to make the RE2 object created from the "zip" field useable for + // both these purposes, the pattern string is here prefixed with "^" to + // anchor it at the beginning of the string so that it can be used with + // RE2::PartialMatch() to perform prefix matching or else with + // RE2::FullMatch() to perform matching against the entire string. + RE2::Options options; + options.set_never_capture(true); + RE2* matcher = new RE2("^(" + value + ")", options); + if (matcher->ok()) { + postal_code_matcher_.reset(new RE2ptr(matcher)); + } else { + postal_code_matcher_.reset(NULL); + delete matcher; + } + // If the "zip" field is not a regular expression, then it is the sole + // postal code for this rule. + if (!ContainsRegExSpecialCharacters(value)) { + sole_postal_code_.swap(value); + } + } + + if (json.GetStringValueForKey("state_name_type", &value)) { + admin_area_name_message_id_ = + GetMessageIdFromName(value, GetAdminAreaMessageIds()); + } + + if (json.GetStringValueForKey("zip_name_type", &value)) { + postal_code_name_message_id_ = + GetMessageIdFromName(value, GetPostalCodeMessageIds()); + } + + if (json.GetStringValueForKey("locality_name_type", &value)) { + locality_name_message_id_ = + GetMessageIdFromName(value, GetLocalityMessageIds()); + } + + if (json.GetStringValueForKey("sublocality_name_type", &value)) { + sublocality_name_message_id_ = + GetMessageIdFromName(value, GetSublocalityMessageIds()); + } + + if (json.GetStringValueForKey("name", &value)) { + name_.swap(value); + } + + if (json.GetStringValueForKey("lname", &value)) { + latin_name_.swap(value); + } + + if (json.GetStringValueForKey("zipex", &value)) { + postal_code_example_.swap(value); + } + + if (json.GetStringValueForKey("posturl", &value)) { + post_service_url_.swap(value); + } +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/rule.h b/chromium/third_party/libaddressinput/src/cpp/src/rule.h new file mode 100644 index 00000000000..87948df4264 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/rule.h @@ -0,0 +1,165 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// An object to store address metadata, describing the addressing rules for +// regions and sub-regions. The address metadata format is documented here: +// +// https://github.com/googlei18n/libaddressinput/wiki/AddressValidationMetadata + +#ifndef I18N_ADDRESSINPUT_RULE_H_ +#define I18N_ADDRESSINPUT_RULE_H_ + +#include <libaddressinput/address_field.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +class FormatElement; +class Json; +struct RE2ptr; + +// Stores address metadata addressing rules, to be used for determining the +// layout of an address input widget or for address validation. Sample usage: +// Rule rule; +// if (rule.ParseSerializedRule("{\"fmt\": \"%A%n%C%S %Z\"}")) { +// Process(rule.GetFormat()); +// } +class Rule { + public: + Rule(); + ~Rule(); + + // Returns the default rule at a country level. If a country does not specify + // address format, for example, then the format from this rule should be used + // instead. + static const Rule& GetDefault(); + + // Copies all data from |rule|. + void CopyFrom(const Rule& rule); + + // Parses |serialized_rule|. Returns |true| if the |serialized_rule| has valid + // format (JSON dictionary). + bool ParseSerializedRule(const std::string& serialized_rule); + + // Reads data from |json|, which must already have parsed a serialized rule. + void ParseJsonRule(const Json& json); + + // Returns the ID string for this rule. + const std::string& GetId() const { return id_; } + + // Returns the format elements for this rule. The format can include the + // relevant address fields, but also strings used for formatting, or newline + // information. + const std::vector<FormatElement>& GetFormat() const { return format_; } + + // Returns the approximate address format with the Latin order of fields. The + // format can include the relevant address fields, but also strings used for + // formatting, or newline information. + const std::vector<FormatElement>& GetLatinFormat() const { + return latin_format_; + } + + // Returns the required fields for this rule. + const std::vector<AddressField>& GetRequired() const { return required_; } + + // Returns the sub-keys for this rule, which are the administrative areas of a + // country, the localities of an administrative area, or the dependent + // localities of a locality. For example, the rules for "US" have sub-keys of + // "CA", "NY", "TX", etc. + const std::vector<std::string>& GetSubKeys() const { return sub_keys_; } + + // Returns all of the language tags supported by this rule, for example ["de", + // "fr", "it"]. + const std::vector<std::string>& GetLanguages() const { return languages_; } + + // Returns a pointer to a RE2 regular expression object created from the + // postal code format string, if specified, or NULL otherwise. The regular + // expression is anchored to the beginning of the string so that it can be + // used either with RE2::PartialMatch() to perform prefix matching or else + // with RE2::FullMatch() to perform matching against the entire string. + const RE2ptr* GetPostalCodeMatcher() const { + return postal_code_matcher_.get(); + } + + // Returns the sole postal code for this rule, if there is one. + const std::string& GetSolePostalCode() const { return sole_postal_code_; } + + // The message string identifier for admin area name. If not set, then + // INVALID_MESSAGE_ID. + int GetAdminAreaNameMessageId() const { return admin_area_name_message_id_; } + + // The message string identifier for postal code name. If not set, then + // INVALID_MESSAGE_ID. + int GetPostalCodeNameMessageId() const { + return postal_code_name_message_id_; + } + + // The message string identifier for locality name. If not set, then + // INVALID_MESSAGE_ID. + int GetLocalityNameMessageId() const { + return locality_name_message_id_; + } + + // The message string identifier for sublocality name. If not set, then + // INVALID_MESSAGE_ID. + int GetSublocalityNameMessageId() const { + return sublocality_name_message_id_; + } + + // Returns the name for the most specific place described by this rule, if + // there is one. This is typically set when it differs from the key. + const std::string& GetName() const { return name_; } + + // Returns the Latin-script name for the most specific place described by this + // rule, if there is one. + const std::string& GetLatinName() const { return latin_name_; } + + // Returns the postal code example string for this rule. + const std::string& GetPostalCodeExample() const { + return postal_code_example_; + } + + // Returns the post service URL string for this rule. + const std::string& GetPostServiceUrl() const { return post_service_url_; } + + private: + std::string id_; + std::vector<FormatElement> format_; + std::vector<FormatElement> latin_format_; + std::vector<AddressField> required_; + std::vector<std::string> sub_keys_; + std::vector<std::string> languages_; + scoped_ptr<const RE2ptr> postal_code_matcher_; + std::string sole_postal_code_; + int admin_area_name_message_id_; + int postal_code_name_message_id_; + int locality_name_message_id_; + int sublocality_name_message_id_; + std::string name_; + std::string latin_name_; + std::string postal_code_example_; + std::string post_service_url_; + + DISALLOW_COPY_AND_ASSIGN(Rule); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_RULE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/rule_retriever.cc b/chromium/third_party/libaddressinput/src/cpp/src/rule_retriever.cc new file mode 100644 index 00000000000..f0ed848a807 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/rule_retriever.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include "rule_retriever.h" + +#include <libaddressinput/callback.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <cassert> +#include <cstddef> +#include <string> + +#include "retriever.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +namespace { + +class Helper { + public: + Helper(const std::string& key, + const RuleRetriever::Callback& rule_ready, + const Retriever& data_retriever) + : rule_ready_(rule_ready), + data_retrieved_(BuildCallback(this, &Helper::OnDataRetrieved)) { + data_retriever.Retrieve(key, *data_retrieved_); + } + + private: + ~Helper() {} + + void OnDataRetrieved(bool success, + const std::string& key, + const std::string& data) { + Rule rule; + if (!success) { + rule_ready_(false, key, rule); + } else { + success = rule.ParseSerializedRule(data); + rule_ready_(success, key, rule); + } + delete this; + } + + const RuleRetriever::Callback& rule_ready_; + const scoped_ptr<const Retriever::Callback> data_retrieved_; + + DISALLOW_COPY_AND_ASSIGN(Helper); +}; + +} // namespace + +RuleRetriever::RuleRetriever(const Retriever* retriever) + : data_retriever_(retriever) { + assert(data_retriever_ != NULL); +} + +RuleRetriever::~RuleRetriever() {} + +void RuleRetriever::RetrieveRule(const std::string& key, + const Callback& rule_ready) const { + new Helper(key, rule_ready, *data_retriever_); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/rule_retriever.h b/chromium/third_party/libaddressinput/src/cpp/src/rule_retriever.h new file mode 100644 index 00000000000..ae4b5ee97d2 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/rule_retriever.h @@ -0,0 +1,59 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// An object to retrieve validation rules. + +#ifndef I18N_ADDRESSINPUT_RULE_RETRIEVER_H_ +#define I18N_ADDRESSINPUT_RULE_RETRIEVER_H_ + +#include <libaddressinput/callback.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +class Retriever; +class Rule; + +// Retrieves validation rules. Sample usage: +// const Retriever* retriever = ... +// RuleRetriever rules(retriever); +// const scoped_ptr<const RuleRetriever::Callback> rule_ready( +// BuildCallback(this, &MyClass::OnRuleReady)); +// rules.RetrieveRule("data/CA/AB--fr", *rule_ready); +class RuleRetriever { + public: + typedef i18n::addressinput::Callback<const std::string&, + const Rule&> Callback; + + // Takes ownership of |retriever|. + explicit RuleRetriever(const Retriever* retriever); + ~RuleRetriever(); + + // Retrieves the rule for |key| and invokes the |rule_ready| callback. + void RetrieveRule(const std::string& key, const Callback& rule_ready) const; + + private: + scoped_ptr<const Retriever> data_retriever_; + + DISALLOW_COPY_AND_ASSIGN(RuleRetriever); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_RULE_RETRIEVER_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/cctype_tolower_equal.cc b/chromium/third_party/libaddressinput/src/cpp/src/util/cctype_tolower_equal.cc new file mode 100644 index 00000000000..819138f6170 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/cctype_tolower_equal.cc @@ -0,0 +1,44 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "cctype_tolower_equal.h" + +#include <algorithm> +#include <cctype> +#include <functional> +#include <string> + +namespace i18n { +namespace addressinput { + +namespace { + +struct EqualToTolowerChar + : public std::binary_function<std::string::value_type, + std::string::value_type, bool> { + result_type operator()(first_argument_type a, second_argument_type b) const { + return std::tolower(a) == std::tolower(b); + } +}; + +} // namespace + +EqualToTolowerString::result_type EqualToTolowerString::operator()( + const first_argument_type& a, const second_argument_type& b) const { + return a.size() == b.size() && + std::equal(a.begin(), a.end(), b.begin(), EqualToTolowerChar()); +} + +} // addressinput +} // i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/cctype_tolower_equal.h b/chromium/third_party/libaddressinput/src/cpp/src/util/cctype_tolower_equal.h new file mode 100644 index 00000000000..106087e8c44 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/cctype_tolower_equal.h @@ -0,0 +1,35 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_UTIL_CCTYPE_TOLOWER_EQUAL_H_ +#define I18N_ADDRESSINPUT_UTIL_CCTYPE_TOLOWER_EQUAL_H_ + +#include <functional> +#include <string> + +namespace i18n { +namespace addressinput { + +// Performs case insensitive comparison of |a| and |b| by calling std::tolower() +// from <cctype>. +struct EqualToTolowerString + : public std::binary_function<std::string, std::string, bool> { + result_type operator()(const first_argument_type& a, + const second_argument_type& b) const; +}; + +} // addressinput +} // i18n + +#endif // I18N_ADDRESSINPUT_UTIL_CCTYPE_TOLOWER_EQUAL_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/json.cc b/chromium/third_party/libaddressinput/src/cpp/src/util/json.cc new file mode 100644 index 00000000000..9d30b664332 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/json.cc @@ -0,0 +1,133 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#include "json.h" + +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <vector> + +#include <rapidjson/document.h> +#include <rapidjson/reader.h> + +namespace i18n { +namespace addressinput { + +using rapidjson::Document; +using rapidjson::kParseValidateEncodingFlag; +using rapidjson::Value; + +class Json::JsonImpl { + public: + explicit JsonImpl(const std::string& json) + : document_(new Document), + value_(document_.get()), + dictionaries_(), + valid_(false) { + document_->Parse<kParseValidateEncodingFlag>(json.c_str()); + valid_ = !document_->HasParseError() && document_->IsObject(); + } + + ~JsonImpl() { + for (std::vector<const Json*>::const_iterator it = dictionaries_.begin(); + it != dictionaries_.end(); ++it) { + delete *it; + } + } + + bool valid() const { return valid_; } + + const std::vector<const Json*>& GetSubDictionaries() { + if (dictionaries_.empty()) { + for (Value::ConstMemberIterator member = value_->MemberBegin(); + member != value_->MemberEnd(); ++member) { + if (member->value.IsObject()) { + dictionaries_.push_back(new Json(new JsonImpl(&member->value))); + } + } + } + return dictionaries_; + } + + bool GetStringValueForKey(const std::string& key, std::string* value) const { + assert(value != NULL); + + Value::ConstMemberIterator member = value_->FindMember(key.c_str()); + if (member == value_->MemberEnd() || !member->value.IsString()) { + return false; + } + + value->assign(member->value.GetString(), + member->value.GetStringLength()); + return true; + } + + private: + // Does not take ownership of |value|. + explicit JsonImpl(const Value* value) + : document_(), + value_(value), + dictionaries_(), + valid_(true) { + assert(value_ != NULL); + assert(value_->IsObject()); + } + + // An owned JSON document. Can be NULL if the JSON document is not owned. + const scoped_ptr<Document> document_; + + // A JSON document that is not owned. Cannot be NULL. Can point to document_. + const Value* const value_; + + // Owned JSON objects of sub-dictionaries. + std::vector<const Json*> dictionaries_; + + // True if the JSON object was parsed successfully. + bool valid_; + + DISALLOW_COPY_AND_ASSIGN(JsonImpl); +}; + +Json::Json() : impl_() {} + +Json::~Json() {} + +bool Json::ParseObject(const std::string& json) { + assert(impl_ == NULL); + impl_.reset(new JsonImpl(json)); + if (!impl_->valid()) { + impl_.reset(); + } + return impl_ != NULL; +} + +const std::vector<const Json*>& Json::GetSubDictionaries() const { + assert(impl_ != NULL); + return impl_->GetSubDictionaries(); +} + +bool Json::GetStringValueForKey(const std::string& key, + std::string* value) const { + assert(impl_ != NULL); + return impl_->GetStringValueForKey(key, value); +} + +Json::Json(JsonImpl* impl) : impl_(impl) {} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/json.h b/chromium/third_party/libaddressinput/src/cpp/src/util/json.h new file mode 100644 index 00000000000..1aac803c1fd --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/json.h @@ -0,0 +1,68 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_UTIL_JSON_H_ +#define I18N_ADDRESSINPUT_UTIL_JSON_H_ + +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +// Parses a JSON dictionary of strings. Sample usage: +// Json json; +// if (json.ParseObject("{'key1':'value1', 'key2':'value2'}") && +// json.HasStringKey("key1")) { +// Process(json.GetStringValueForKey("key1")); +// } +class Json { + public: + Json(); + ~Json(); + + // Parses the |json| string and returns true if |json| is valid and it is an + // object. + bool ParseObject(const std::string& json); + + // Returns the list of sub dictionaries. The JSON object must be parsed + // successfully in ParseObject() before invoking this method. The caller does + // not own the result. + const std::vector<const Json*>& GetSubDictionaries() const; + + // Returns true if the parsed JSON contains a string value for |key|. Sets + // |value| to the string value of the |key|. The JSON object must be parsed + // successfully in ParseObject() before invoking this method. The |value| + // parameter should not be NULL. + bool GetStringValueForKey(const std::string& key, std::string* value) const; + + private: + class JsonImpl; + friend class JsonImpl; + + // Constructor to be called by JsonImpl. + explicit Json(JsonImpl* impl); + + scoped_ptr<JsonImpl> impl_; + + DISALLOW_COPY_AND_ASSIGN(Json); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_JSON_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/lru_cache_using_std.h b/chromium/third_party/libaddressinput/src/cpp/src/util/lru_cache_using_std.h new file mode 100644 index 00000000000..6062d284e6d --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/lru_cache_using_std.h @@ -0,0 +1,170 @@ +/******************************************************************************/ +/* Copyright (c) 2010-2011, Tim Day <timday@timday.com> */ +/* */ +/* Permission to use, copy, modify, and/or distribute this software for any */ +/* purpose with or without fee is hereby granted, provided that the above */ +/* copyright notice and this permission notice appear in all copies. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES */ +/* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR */ +/* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ +/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN */ +/* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF */ +/* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/******************************************************************************/ + +// The original source code is from: +// https://bitbucket.org/timday/lru_cache/src/497822a492a8/include/lru_cache_using_std.h + +#ifndef I18N_ADDRESSINPUT_UTIL_LRU_CACHE_USING_STD_H_ +#define I18N_ADDRESSINPUT_UTIL_LRU_CACHE_USING_STD_H_ + +#include <cassert> +#include <cstddef> +#include <list> +#include <map> +#include <utility> + +// Class providing fixed-size (by number of records) +// LRU-replacement cache of a function with signature +// V f(K). +// The default comparator/hash/allocator will be used. +template < + typename K, + typename V + > class lru_cache_using_std +{ +public: + + typedef K key_type; + typedef V value_type; + + // Key access history, most recent at back + typedef std::list<key_type> key_tracker_type; + + // Key to value and key history iterator + typedef std::map< + key_type, + std::pair< + value_type, + typename key_tracker_type::iterator + > + > key_to_value_type; + + // Constuctor specifies the cached function and + // the maximum number of records to be stored + lru_cache_using_std( + value_type (*f)(const key_type&), + size_t c + ) + :_fn(f) + ,_capacity(c) + { + assert(_capacity!=0); + } + + // Obtain value of the cached function for k + value_type operator()(const key_type& k) { + + // Attempt to find existing record + const typename key_to_value_type::iterator it + =_key_to_value.find(k); + + if (it==_key_to_value.end()) { + + // We don't have it: + + // Evaluate function and create new record + const value_type v=_fn(k); + insert(k,v); + + // Return the freshly computed value + return v; + + } else { + + // We do have it: + + // Update access record by moving + // accessed key to back of list + _key_tracker.splice( + _key_tracker.end(), + _key_tracker, + (*it).second.second + ); + + // Return the retrieved value + return (*it).second.first; + } + } + + // Obtain the cached keys, most recently used element + // at head, least recently used at tail. + // This method is provided purely to support testing. + template <typename IT> void get_keys(IT dst) const { + typename key_tracker_type::const_reverse_iterator src + =_key_tracker.rbegin(); + while (src!=_key_tracker.rend()) { + *dst++ = *src++; + } + } + +private: + + // Record a fresh key-value pair in the cache + void insert(const key_type& k,const value_type& v) { + + // Method is only called on cache misses + assert(_key_to_value.find(k)==_key_to_value.end()); + + // Make space if necessary + if (_key_to_value.size()==_capacity) + evict(); + + // Record k as most-recently-used key + typename key_tracker_type::iterator it + =_key_tracker.insert(_key_tracker.end(),k); + + // Create the key-value entry, + // linked to the usage record. + _key_to_value.insert( + std::make_pair( + k, + std::make_pair(v,it) + ) + ); + // No need to check return, + // given previous assert. + } + + // Purge the least-recently-used element in the cache + void evict() { + + // Assert method is never called when cache is empty + assert(!_key_tracker.empty()); + + // Identify least recently used key + const typename key_to_value_type::iterator it + =_key_to_value.find(_key_tracker.front()); + assert(it!=_key_to_value.end()); + + // Erase both elements to completely purge record + _key_to_value.erase(it); + _key_tracker.pop_front(); + } + + // The function to be cached + value_type (*_fn)(const key_type&); + + // Maximum number of key-value pairs to be retained + const size_t _capacity; + + // Key access history + key_tracker_type _key_tracker; + + // Key-to-value lookup + key_to_value_type _key_to_value; +}; + +#endif // I18N_ADDRESSINPUT_UTIL_LRU_CACHE_USING_STD_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/md5.cc b/chromium/third_party/libaddressinput/src/cpp/src/util/md5.cc new file mode 100644 index 00000000000..ea7561be606 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/md5.cc @@ -0,0 +1,301 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// http://src.chromium.org/viewvc/chrome/trunk/src/base/md5.cc?revision=94203 + +// The original file was copied from sqlite, and was in the public domain. + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include "md5.h" + +#include <libaddressinput/util/basictypes.h> + +#include <cstddef> +#include <string> +#include <string.h> + +namespace { + +struct Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) { + uint32 t; + do { + t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | + ((unsigned)buf[1]<<8 | buf[0]); + *(uint32 *)buf = t; + buf += 4; + } while (--longs); +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32 buf[4], const uint32 in[16]) { + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +} // namespace + +namespace i18n { +namespace addressinput { + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(MD5Context* context) { + struct Context *ctx = (struct Context *)context; + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(MD5Context* context, const std::string& data) { + const unsigned char* inbuf = (const unsigned char*)data.data(); + size_t len = data.size(); + struct Context *ctx = (struct Context *)context; + const unsigned char* buf = (const unsigned char*)inbuf; + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += static_cast<uint32>(len >> 29); + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *)ctx->in + t; + + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(MD5Digest* digest, MD5Context* context) { + struct Context *ctx = (struct Context *)context; + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; + ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse((unsigned char *)ctx->buf, 4); + memcpy(digest->a, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +std::string MD5DigestToBase16(const MD5Digest& digest) { + static char const zEncode[] = "0123456789abcdef"; + + std::string ret; + ret.resize(32); + + int j = 0; + for (int i = 0; i < 16; i ++) { + int a = digest.a[i]; + ret[j++] = zEncode[(a>>4)&0xf]; + ret[j++] = zEncode[a & 0xf]; + } + return ret; +} + +void MD5Sum(const void* data, size_t length, MD5Digest* digest) { + MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx, + std::string(reinterpret_cast<const char*>(data), length)); + MD5Final(digest, &ctx); +} + +std::string MD5String(const std::string& str) { + MD5Digest digest; + MD5Sum(str.data(), str.length(), &digest); + return MD5DigestToBase16(digest); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/md5.h b/chromium/third_party/libaddressinput/src/cpp/src/util/md5.h new file mode 100644 index 00000000000..98bc3254fbc --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/md5.h @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// http://src.chromium.org/viewvc/chrome/trunk/src/base/md5.h?revision=94203 + +#ifndef I18N_ADDRESSINPUT_UTIL_MD5_H_ +#define I18N_ADDRESSINPUT_UTIL_MD5_H_ + +#include <cstddef> +#include <string> + +namespace i18n { +namespace addressinput { + +// MD5 stands for Message Digest algorithm 5. +// MD5 is a robust hash function, designed for cyptography, but often used +// for file checksums. The code is complex and slow, but has few +// collisions. +// See Also: +// http://en.wikipedia.org/wiki/MD5 + +// These functions perform MD5 operations. The simplest call is MD5Sum() to +// generate the MD5 sum of the given data. +// +// You can also compute the MD5 sum of data incrementally by making multiple +// calls to MD5Update(): +// MD5Context ctx; // intermediate MD5 data: do not use +// MD5Init(&ctx); +// MD5Update(&ctx, data1, length1); +// MD5Update(&ctx, data2, length2); +// ... +// +// MD5Digest digest; // the result of the computation +// MD5Final(&digest, &ctx); +// +// You can call MD5DigestToBase16() to generate a string of the digest. + +// The output of an MD5 operation. +struct MD5Digest { + unsigned char a[16]; +}; + +// Used for storing intermediate data during an MD5 computation. Callers +// should not access the data. +typedef char MD5Context[88]; + +// Computes the MD5 sum of the given data buffer with the given length. +// The given 'digest' structure will be filled with the result data. +void MD5Sum(const void* data, size_t length, MD5Digest* digest); + +// Initializes the given MD5 context structure for subsequent calls to +// MD5Update(). +void MD5Init(MD5Context* context); + +// For the given buffer of |data| as a StringPiece, updates the given MD5 +// context with the sum of the data. You can call this any number of times +// during the computation, except that MD5Init() must have been called first. +void MD5Update(MD5Context* context, const std::string& data); + +// Finalizes the MD5 operation and fills the buffer with the digest. +void MD5Final(MD5Digest* digest, MD5Context* context); + +// Converts a digest into human-readable hexadecimal. +std::string MD5DigestToBase16(const MD5Digest& digest); + +// Returns the MD5 (in hexadecimal) of a string. +std::string MD5String(const std::string& str); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_MD5_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/re2ptr.h b/chromium/third_party/libaddressinput/src/cpp/src/util/re2ptr.h new file mode 100644 index 00000000000..e04bcfd85cf --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/re2ptr.h @@ -0,0 +1,46 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. +// +// Work-around for problems with the RE2 library. Must be the first #include +// statement in the compilation unit. Do not #include in other header files. + +#ifndef I18N_ADDRESSINPUT_UTIL_RE2PTR_H_ +#define I18N_ADDRESSINPUT_UTIL_RE2PTR_H_ + +// RE2 will, in some environments, define class RE2 inside namespace re2 and +// then have a public "using re2::RE2;" statement to bring that definition into +// the root namespace, while in other environments it will define class RE2 +// directly in the root namespace. +// +// Because of that, it's impossible to write a portable forward declaration of +// class RE2. +// +// The work-around in this file works by wrapping pointers to RE2 object in the +// simple struct RE2ptr, which is trivial to forward declare. + +#include <re2/re2.h> + +namespace i18n { +namespace addressinput { + +struct RE2ptr { + RE2ptr(RE2* init_ptr) : ptr(init_ptr) {} + ~RE2ptr() { delete ptr; } + RE2* const ptr; +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_RE2PTR_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/string_compare.cc b/chromium/third_party/libaddressinput/src/cpp/src/util/string_compare.cc new file mode 100644 index 00000000000..31a75346af2 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/string_compare.cc @@ -0,0 +1,102 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "string_compare.h" + +#include <libaddressinput/util/basictypes.h> + +#include <cassert> +#include <string> + +#include <re2/re2.h> + +#include "lru_cache_using_std.h" + +// RE2 uses type string, which is not necessarily the same as type std::string. +// In order to create objects of the correct type, to be able to pass pointers +// to these objects to RE2, the function that does that is defined inside an +// unnamed namespace inside the re2 namespace. Oh, my ... +namespace re2 { +namespace { + +// In order to (mis-)use RE2 to implement UTF-8 capable less<>, this function +// calls RE2::PossibleMatchRange() to calculate the "lessest" string that would +// be a case-insensitive match to the string. This is far too expensive to do +// repeatedly, so the function is only ever called through an LRU cache. +std::string ComputeMinPossibleMatch(const std::string& str) { + string min, max; // N.B.: RE2 type string! + + RE2::Options options; + options.set_literal(true); + options.set_case_sensitive(false); + RE2 matcher(str, options); + + bool success = matcher.PossibleMatchRange(&min, &max, str.size()); + assert(success); + (void)success; // Prevent unused variable if assert() is optimized away. + + return min; +} + +} // namespace +} // namespace re2 + +namespace i18n { +namespace addressinput { + +class StringCompare::Impl { + enum { MAX_CACHE_SIZE = 1 << 15 }; + + public: + Impl() : min_possible_match_(&re2::ComputeMinPossibleMatch, MAX_CACHE_SIZE) { + options_.set_literal(true); + options_.set_case_sensitive(false); + } + + ~Impl() {} + + bool NaturalEquals(const std::string& a, const std::string& b) const { + RE2 matcher(b, options_); + return RE2::FullMatch(a, matcher); + } + + bool NaturalLess(const std::string& a, const std::string& b) const { + const std::string& min_a(min_possible_match_(a)); + const std::string& min_b(min_possible_match_(b)); + return min_a < min_b; + } + + private: + RE2::Options options_; + mutable lru_cache_using_std<std::string, std::string> min_possible_match_; + + DISALLOW_COPY_AND_ASSIGN(Impl); +}; + +StringCompare::StringCompare() : impl_(new Impl) {} + +StringCompare::~StringCompare() {} + +bool StringCompare::NaturalEquals(const std::string& a, + const std::string& b) const { + return impl_->NaturalEquals(a, b); +} + +bool StringCompare::NaturalLess(const std::string& a, + const std::string& b) const { + return impl_->NaturalLess(a, b); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/string_compare.h b/chromium/third_party/libaddressinput/src/cpp/src/util/string_compare.h new file mode 100644 index 00000000000..ae680ddc3b6 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/string_compare.h @@ -0,0 +1,52 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_UTIL_STRING_COMPARE_H_ +#define I18N_ADDRESSINPUT_UTIL_STRING_COMPARE_H_ + +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +class StringCompare { + public: + StringCompare(); + ~StringCompare(); + + // Returns true if a human reader would consider |a| and |b| to be "the same". + // Libaddressinput itself isn't really concerned about how this is done. This + // default implementation just does case insensitive string matching. + bool NaturalEquals(const std::string& a, const std::string& b) const; + + // Comparison function for use with the STL analogous to NaturalEquals(). + // Libaddressinput itself isn't really concerned about how this is done, as + // long as it conforms to the STL requirements on less<> predicates. This + // default implementation is VERY SLOW! Must be replaced if you need speed. + bool NaturalLess(const std::string& a, const std::string& b) const; + + private: + class Impl; + scoped_ptr<Impl> impl_; + + DISALLOW_COPY_AND_ASSIGN(StringCompare); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_STRING_COMPARE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/string_split.cc b/chromium/third_party/libaddressinput/src/cpp/src/util/string_split.cc new file mode 100644 index 00000000000..114cd92f5c6 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/string_split.cc @@ -0,0 +1,37 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// http://src.chromium.org/viewvc/chrome/trunk/src/base/strings/string_split.cc?revision=216633 + +#include "string_split.h" + +#include <cassert> +#include <cstddef> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +void SplitString(const std::string& str, char s, std::vector<std::string>* r) { + assert(r != NULL); + r->clear(); + size_t last = 0; + size_t c = str.size(); + for (size_t i = 0; i <= c; ++i) { + if (i == c || str[i] == s) { + std::string tmp(str, last, i - last); + // Avoid converting an empty or all-whitespace source string into a vector + // of one empty string. + if (i != c || !r->empty() || !tmp.empty()) { + r->push_back(tmp); + } + last = i + 1; + } + } +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/string_split.h b/chromium/third_party/libaddressinput/src/cpp/src/util/string_split.h new file mode 100644 index 00000000000..680929646f4 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/string_split.h @@ -0,0 +1,34 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// http://src.chromium.org/viewvc/chrome/trunk/src/base/strings/string_split.h?revision=236210 +// +// Modifications from original: +// 1) Supports only std::string type. +// 2) Does not trim whitespace. + +#ifndef I18N_ADDRESSINPUT_UTIL_STRING_SPLIT_H_ +#define I18N_ADDRESSINPUT_UTIL_STRING_SPLIT_H_ + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +// Splits |str| into a vector of strings delimited by |c|, placing the results +// in |r|. If several instances of |c| are contiguous, or if |str| begins with +// or ends with |c|, then an empty string is inserted. +// +// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which +// the trailing byte of a multi-byte character can be in the ASCII range. +// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK. +// Note: |c| must be in the ASCII range. +void SplitString(const std::string& str, char c, std::vector<std::string>* r); + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_UTIL_STRING_SPLIT_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/string_util.cc b/chromium/third_party/libaddressinput/src/cpp/src/util/string_util.cc new file mode 100644 index 00000000000..8396d51faac --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/string_util.cc @@ -0,0 +1,68 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// The original source code is from: +// http://src.chromium.org/viewvc/chrome/trunk/src/base/strings/string_util.cc?revision=268754 +// +// Modified to contain only the DoReplaceStringPlaceholders() that works with +// std::string. Replaced DCHECK() with assert() and removed offsets. + +#include "string_util.h" + +#include <cassert> +#include <cstddef> +#include <stdint.h> +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +std::string DoReplaceStringPlaceholders(const std::string& format_string, + const std::vector<std::string>& subst) { + size_t substitutions = subst.size(); + + size_t sub_length = 0; + for (std::vector<std::string>::const_iterator iter = subst.begin(); + iter != subst.end(); ++iter) { + sub_length += iter->length(); + } + + std::string formatted; + formatted.reserve(format_string.length() + sub_length); + + for (std::string::const_iterator i = format_string.begin(); + i != format_string.end(); ++i) { + if ('$' == *i) { + if (i + 1 != format_string.end()) { + ++i; + assert('$' == *i || '1' <= *i); + if ('$' == *i) { + while (i != format_string.end() && '$' == *i) { + formatted.push_back('$'); + ++i; + } + --i; + } else { + uintptr_t index = 0; + while (i != format_string.end() && '0' <= *i && *i <= '9') { + index *= 10; + index += *i - '0'; + ++i; + } + --i; + index -= 1; + if (index < substitutions) + formatted.append(subst.at(index)); + } + } + } else { + formatted.push_back(*i); + } + } + return formatted; +} + +} // addressinput +} // i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/util/string_util.h b/chromium/third_party/libaddressinput/src/cpp/src/util/string_util.h new file mode 100644 index 00000000000..4266347c621 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/util/string_util.h @@ -0,0 +1,28 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file defines utility functions for working with strings. +// +// The original source code is from: +// http://src.chromium.org/viewvc/chrome/trunk/src/base/strings/string_util.h?revision=268754 +// +// Modified to contain only DoReplaceStringPlaceholders() that works only with +// std::string. + +#ifndef I18N_ADDRESSINPUT_UTIL_STRING_UTIL_H_ +#define I18N_ADDRESSINPUT_UTIL_STRING_UTIL_H_ + +#include <string> +#include <vector> + +namespace i18n { +namespace addressinput { + +std::string DoReplaceStringPlaceholders(const std::string& format_string, + const std::vector<std::string>& subst); + +} // addressinput +} // i18n + +#endif // I18N_ADDRESSINPUT_UTIL_STRING_UTIL_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/validating_storage.cc b/chromium/third_party/libaddressinput/src/cpp/src/validating_storage.cc new file mode 100644 index 00000000000..a504db4502b --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/validating_storage.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// ValidatingStorage saves data with checksum and timestamp using +// ValidatingUtil. + +#include "validating_storage.h" + +#include <libaddressinput/callback.h> +#include <libaddressinput/storage.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <cassert> +#include <cstddef> +#include <ctime> +#include <string> + +#include "validating_util.h" + +namespace i18n { +namespace addressinput { + +namespace { + +class Helper { + public: + Helper(const std::string& key, + const ValidatingStorage::Callback& data_ready, + const Storage& wrapped_storage) + : data_ready_(data_ready), + wrapped_data_ready_(BuildCallback(this, &Helper::OnWrappedDataReady)) { + wrapped_storage.Get(key, *wrapped_data_ready_); + } + + private: + ~Helper() {} + + void OnWrappedDataReady(bool success, + const std::string& key, + std::string* data) { + if (success) { + assert(data != NULL); + bool is_stale = !ValidatingUtil::UnwrapTimestamp(data, std::time(NULL)); + bool is_corrupted = !ValidatingUtil::UnwrapChecksum(data); + success = !is_corrupted && !is_stale; + if (is_corrupted) { + delete data; + data = NULL; + } + } else { + delete data; + data = NULL; + } + data_ready_(success, key, data); + delete this; + } + + const Storage::Callback& data_ready_; + const scoped_ptr<const Storage::Callback> wrapped_data_ready_; + + DISALLOW_COPY_AND_ASSIGN(Helper); +}; + +} // namespace + +ValidatingStorage::ValidatingStorage(Storage* storage) + : wrapped_storage_(storage) { + assert(wrapped_storage_ != NULL); +} + +ValidatingStorage::~ValidatingStorage() {} + +void ValidatingStorage::Put(const std::string& key, std::string* data) { + assert(data != NULL); + ValidatingUtil::Wrap(std::time(NULL), data); + wrapped_storage_->Put(key, data); +} + +void ValidatingStorage::Get(const std::string& key, + const Callback& data_ready) const { + new Helper(key, data_ready, *wrapped_storage_); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/validating_storage.h b/chromium/third_party/libaddressinput/src/cpp/src/validating_storage.h new file mode 100644 index 00000000000..1cf3f955e1d --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/validating_storage.h @@ -0,0 +1,64 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// A wrapper object for Storage that stores data with a checksum and a +// timestamp. The existence of checksum and timestamp fields is transparent to +// the user of the object. + +#ifndef I18N_ADDRESSINPUT_VALIDATING_STORAGE_H_ +#define I18N_ADDRESSINPUT_VALIDATING_STORAGE_H_ + +#include <libaddressinput/storage.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +// Wraps Storage to add checksum and timestamp to stored data. Sample usage: +// scoped_ptr<Storage> file_storage = ...; +// ValidatingStorage storage(file_storage)); +// storage.Put("key", new std::string("data")); +// const scoped_ptr<const ValidatingStorage::Callback> data_ready( +// BuildCallback(this, &MyClass::OnDataReady)); +// storage.Get("key", *data_ready); +class ValidatingStorage : public Storage { + public: + // Takes ownership of |storage|. + explicit ValidatingStorage(Storage* storage); + virtual ~ValidatingStorage(); + + // Storage implementation. + virtual void Put(const std::string& key, std::string* data); + + // Storage implementation. + // If the data is invalid, then |data_ready| will be called with (false, key, + // empty-string). If the data is valid, but stale, then |data_ready| will be + // called with (false, key, stale-data). If the data is valid and fresh, then + // |data_ready| will be called with (true, key, fresh-data). + virtual void Get(const std::string& key, const Callback& data_ready) const; + + private: + // The storage being wrapped. + scoped_ptr<Storage> wrapped_storage_; + + DISALLOW_COPY_AND_ASSIGN(ValidatingStorage); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_VALIDATING_STORAGE_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/validating_util.cc b/chromium/third_party/libaddressinput/src/cpp/src/validating_util.cc new file mode 100644 index 00000000000..935668945e4 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/validating_util.cc @@ -0,0 +1,145 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// ValidatingUtil wraps data with checksum and timestamp. Format: +// +// timestamp=<timestamp> +// checksum=<checksum> +// <data> +// +// The timestamp is the time_t that was returned from time() function. The +// timestamp does not need to be portable because it is written and read only by +// ValidatingUtil. The value is somewhat human-readable: it is the number of +// seconds since the epoch. +// +// The checksum is the 32-character hexadecimal MD5 checksum of <data>. It is +// meant to protect from random file changes on disk. + +#include "validating_util.h" + +#include <cassert> +#include <cstddef> +#include <cstdio> +#include <cstdlib> +#include <ctime> +#include <string> + +#include "util/md5.h" + +namespace i18n { +namespace addressinput { + +namespace { + +const char kTimestampPrefix[] = "timestamp="; +const size_t kTimestampPrefixLength = sizeof kTimestampPrefix - 1; + +const char kChecksumPrefix[] = "checksum="; +const size_t kChecksumPrefixLength = sizeof kChecksumPrefix - 1; + +const char kSeparator = '\n'; + +// Places the header value into |header_value| parameter and erases the header +// from |data|. Returns |true| if the header format is valid. +bool UnwrapHeader(const char* header_prefix, + size_t header_prefix_length, + std::string* data, + std::string* header_value) { + assert(header_prefix != NULL); + assert(data != NULL); + assert(header_value != NULL); + + if (data->compare( + 0, header_prefix_length, header_prefix, header_prefix_length) != 0) { + return false; + } + + std::string::size_type separator_position = + data->find(kSeparator, header_prefix_length); + if (separator_position == std::string::npos) { + return false; + } + + header_value->assign( + *data, header_prefix_length, separator_position - header_prefix_length); + data->erase(0, separator_position + 1); + + return true; +} + +} // namespace + +// static +void ValidatingUtil::Wrap(time_t timestamp, std::string* data) { + assert(data != NULL); + char timestamp_string[2 + 3 * sizeof timestamp]; + int size = + std::sprintf(timestamp_string, "%ld", static_cast<long>(timestamp)); + assert(size > 0); + assert(size < sizeof timestamp_string); + (void)size; + + std::string header; + header.append(kTimestampPrefix, kTimestampPrefixLength); + header.append(timestamp_string); + header.push_back(kSeparator); + + header.append(kChecksumPrefix, kChecksumPrefixLength); + header.append(MD5String(*data)); + header.push_back(kSeparator); + + data->reserve(header.size() + data->size()); + data->insert(0, header); +} + +// static +bool ValidatingUtil::UnwrapTimestamp(std::string* data, time_t now) { + assert(data != NULL); + if (now < 0) { + return false; + } + + std::string timestamp_string; + if (!UnwrapHeader( + kTimestampPrefix, kTimestampPrefixLength, data, ×tamp_string)) { + return false; + } + + time_t timestamp = atol(timestamp_string.c_str()); + if (timestamp < 0) { + return false; + } + + // One month contains: + // 30 days * + // 24 hours per day * + // 60 minutes per hour * + // 60 seconds per minute. + static const double kOneMonthInSeconds = 30.0 * 24.0 * 60.0 * 60.0; + double age_in_seconds = difftime(now, timestamp); + return !(age_in_seconds < 0.0) && age_in_seconds < kOneMonthInSeconds; +} + +// static +bool ValidatingUtil::UnwrapChecksum(std::string* data) { + assert(data != NULL); + std::string checksum; + if (!UnwrapHeader(kChecksumPrefix, kChecksumPrefixLength, data, &checksum)) { + return false; + } + return checksum == MD5String(*data); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/validating_util.h b/chromium/third_party/libaddressinput/src/cpp/src/validating_util.h new file mode 100644 index 00000000000..20d541b291a --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/validating_util.h @@ -0,0 +1,60 @@ +// Copyright (C) 2013 Google Inc. +// +// 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. +// +// An object to wrap data with a checksum and a timestamp. These fields are used +// to verify that the data is not stale or corrupted. Staleness threshold is 1 +// month. + +#ifndef I18N_ADDRESSINPUT_VALIDATING_UTIL_H_ +#define I18N_ADDRESSINPUT_VALIDATING_UTIL_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <ctime> +#include <string> + +namespace i18n { +namespace addressinput { + +// Wraps data with a checksum and a timestamp. Sample usage: +// std::string data = ... +// ValidatingUtil::Wrap(time(NULL), &data); +// Process(data); +// +// std::string unwrapped = wrapped; +// if (ValidatingUtil::UnwrapTimestamp(&unwrapped, time(NULL)) && +// ValidatingUtil::UnwrapChecksum(&unwrapped)) { +// Process(unwrapped); +// } +class ValidatingUtil { + public: + // Adds checksum and given |timestamp| to |data|. + static void Wrap(time_t timestamp, std::string* data); + + // Strips out the timestamp from |data|. Returns |true| if the timestamp is + // present, formatted correctly, valid, and recent with respect to |now|. + static bool UnwrapTimestamp(std::string* data, time_t now); + + // Strips out the checksum from |data|. Returns |true| if the checksum is + // present, formatted correctly, and valid for this data. + static bool UnwrapChecksum(std::string* data); + + private: + DISALLOW_COPY_AND_ASSIGN(ValidatingUtil); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_VALIDATING_UTIL_H_ diff --git a/chromium/third_party/libaddressinput/src/cpp/src/validation_task.cc b/chromium/third_party/libaddressinput/src/cpp/src/validation_task.cc new file mode 100644 index 00000000000..1e7911aad18 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/validation_task.cc @@ -0,0 +1,268 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#include "validation_task.h" + +#include <libaddressinput/address_data.h> +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_metadata.h> +#include <libaddressinput/address_problem.h> +#include <libaddressinput/address_validator.h> +#include <libaddressinput/callback.h> +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <string> +#include <utility> +#include <vector> + +#include <re2/re2.h> + +#include "lookup_key.h" +#include "post_box_matchers.h" +#include "rule.h" +#include "util/re2ptr.h" + +namespace i18n { +namespace addressinput { + +ValidationTask::ValidationTask(const AddressData& address, + bool allow_postal, + bool require_name, + const FieldProblemMap* filter, + FieldProblemMap* problems, + const AddressValidator::Callback& validated) + : address_(address), + allow_postal_(allow_postal), + require_name_(require_name), + filter_(filter), + problems_(problems), + validated_(validated), + supplied_(BuildCallback(this, &ValidationTask::Validate)), + lookup_key_(new LookupKey) { + assert(problems_ != NULL); + assert(supplied_ != NULL); + assert(lookup_key_ != NULL); +} + +ValidationTask::~ValidationTask() { +} + +void ValidationTask::Run(Supplier* supplier) const { + assert(supplier != NULL); + problems_->clear(); + lookup_key_->FromAddress(address_); + supplier->Supply(*lookup_key_, *supplied_); +} + +void ValidationTask::Validate(bool success, + const LookupKey& lookup_key, + const Supplier::RuleHierarchy& hierarchy) { + assert(&lookup_key == lookup_key_.get()); // Sanity check. + + if (success) { + if (address_.IsFieldEmpty(COUNTRY)) { + ReportProblemMaybe(COUNTRY, MISSING_REQUIRED_FIELD); + } else if (hierarchy.rule[0] == NULL) { + ReportProblemMaybe(COUNTRY, UNKNOWN_VALUE); + } else { + // Checks which use statically linked metadata. + const std::string& region_code = address_.region_code; + CheckUnexpectedField(region_code); + CheckMissingRequiredField(region_code); + + // Checks which use data from the metadata server. Note that + // CheckPostalCodeFormatAndValue assumes CheckUnexpectedField has already + // been called. + CheckUnknownValue(hierarchy); + CheckPostalCodeFormatAndValue(hierarchy); + CheckUsesPoBox(hierarchy); + } + } + + validated_(success, address_, *problems_); + delete this; +} + +// A field will return an UNEXPECTED_FIELD problem type if the current value of +// that field is not empty and the field should not be used by that region. +void ValidationTask::CheckUnexpectedField( + const std::string& region_code) const { + static const AddressField kFields[] = { + // COUNTRY is never unexpected. + ADMIN_AREA, + LOCALITY, + DEPENDENT_LOCALITY, + SORTING_CODE, + POSTAL_CODE, + STREET_ADDRESS, + ORGANIZATION, + RECIPIENT + }; + + for (size_t i = 0; i < arraysize(kFields); ++i) { + AddressField field = kFields[i]; + if (!address_.IsFieldEmpty(field) && !IsFieldUsed(field, region_code)) { + ReportProblemMaybe(field, UNEXPECTED_FIELD); + } + } +} + +// A field will return an MISSING_REQUIRED_FIELD problem type if the current +// value of that field is empty and the field is required by that region. +void ValidationTask::CheckMissingRequiredField( + const std::string& region_code) const { + static const AddressField kFields[] = { + // COUNTRY is assumed to have already been checked. + ADMIN_AREA, + LOCALITY, + DEPENDENT_LOCALITY, + SORTING_CODE, + POSTAL_CODE, + STREET_ADDRESS + // ORGANIZATION is never required. + // RECIPIENT is handled separately. + }; + + for (size_t i = 0; i < arraysize(kFields); ++i) { + AddressField field = kFields[i]; + if (address_.IsFieldEmpty(field) && IsFieldRequired(field, region_code)) { + ReportProblemMaybe(field, MISSING_REQUIRED_FIELD); + } + } + + if (require_name_ && address_.IsFieldEmpty(RECIPIENT)) { + ReportProblemMaybe(RECIPIENT, MISSING_REQUIRED_FIELD); + } +} + +// A field is UNKNOWN_VALUE if the metadata contains a list of possible values +// for the field and the address data server could not match the current value +// of that field to one of those possible values, therefore returning NULL. +void ValidationTask::CheckUnknownValue( + const Supplier::RuleHierarchy& hierarchy) const { + for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) { + AddressField field = LookupKey::kHierarchy[depth]; + if (!(address_.IsFieldEmpty(field) || + hierarchy.rule[depth - 1] == NULL || + hierarchy.rule[depth - 1]->GetSubKeys().empty() || + hierarchy.rule[depth] != NULL)) { + ReportProblemMaybe(field, UNKNOWN_VALUE); + } + } +} + +// Note that it is assumed that CheckUnexpectedField has already been called. +void ValidationTask::CheckPostalCodeFormatAndValue( + const Supplier::RuleHierarchy& hierarchy) const { + assert(hierarchy.rule[0] != NULL); + const Rule& country_rule = *hierarchy.rule[0]; + + if (!(ShouldReport(POSTAL_CODE, INVALID_FORMAT) || + ShouldReport(POSTAL_CODE, MISMATCHING_VALUE))) { + return; + } + + if (address_.IsFieldEmpty(POSTAL_CODE)) { + return; + } else if (std::find(problems_->begin(), problems_->end(), + FieldProblemMap::value_type(POSTAL_CODE, + UNEXPECTED_FIELD)) + != problems_->end()) { + return; // Problem already reported. + } + + // Validate general postal code format. A country-level rule specifies the + // regular expression for the whole postal code. + const RE2ptr* format_ptr = country_rule.GetPostalCodeMatcher(); + if (format_ptr != NULL && + !RE2::FullMatch(address_.postal_code, *format_ptr->ptr) && + ShouldReport(POSTAL_CODE, INVALID_FORMAT)) { + ReportProblem(POSTAL_CODE, INVALID_FORMAT); + return; + } + + if (!ShouldReport(POSTAL_CODE, MISMATCHING_VALUE)) { + return; + } + + for (size_t depth = arraysize(LookupKey::kHierarchy) - 1; + depth > 0; --depth) { + if (hierarchy.rule[depth] != NULL) { + // Validate sub-region specific postal code format. A sub-region specifies + // the regular expression for a prefix of the postal code. + const RE2ptr* prefix_ptr = hierarchy.rule[depth]->GetPostalCodeMatcher(); + if (prefix_ptr != NULL) { + if (!RE2::PartialMatch(address_.postal_code, *prefix_ptr->ptr)) { + ReportProblem(POSTAL_CODE, MISMATCHING_VALUE); + } + return; + } + } + } +} + +void ValidationTask::CheckUsesPoBox( + const Supplier::RuleHierarchy& hierarchy) const { + assert(hierarchy.rule[0] != NULL); + const Rule& country_rule = *hierarchy.rule[0]; + + if (allow_postal_ || + !ShouldReport(STREET_ADDRESS, USES_P_O_BOX) || + address_.IsFieldEmpty(STREET_ADDRESS)) { + return; + } + + std::vector<const RE2ptr*> matchers = + PostBoxMatchers::GetMatchers(country_rule); + for (std::vector<std::string>::const_iterator + line = address_.address_line.begin(); + line != address_.address_line.end(); ++line) { + for (std::vector<const RE2ptr*>::const_iterator + matcher = matchers.begin(); + matcher != matchers.end(); ++matcher) { + if (RE2::PartialMatch(*line, *(*matcher)->ptr)) { + ReportProblem(STREET_ADDRESS, USES_P_O_BOX); + return; + } + } + } +} + +void ValidationTask::ReportProblem(AddressField field, + AddressProblem problem) const { + problems_->insert(std::make_pair(field, problem)); +} + +void ValidationTask::ReportProblemMaybe(AddressField field, + AddressProblem problem) const { + if (ShouldReport(field, problem)) { + ReportProblem(field, problem); + } +} + +bool ValidationTask::ShouldReport(AddressField field, + AddressProblem problem) const { + return filter_ == NULL || filter_->empty() || + std::find(filter_->begin(), + filter_->end(), + FieldProblemMap::value_type(field, problem)) != + filter_->end(); +} + +} // namespace addressinput +} // namespace i18n diff --git a/chromium/third_party/libaddressinput/src/cpp/src/validation_task.h b/chromium/third_party/libaddressinput/src/cpp/src/validation_task.h new file mode 100644 index 00000000000..165867864fa --- /dev/null +++ b/chromium/third_party/libaddressinput/src/cpp/src/validation_task.h @@ -0,0 +1,101 @@ +// Copyright (C) 2014 Google Inc. +// +// 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. + +#ifndef I18N_ADDRESSINPUT_VALIDATION_TASK_H_ +#define I18N_ADDRESSINPUT_VALIDATION_TASK_H_ + +#include <libaddressinput/address_field.h> +#include <libaddressinput/address_problem.h> +#include <libaddressinput/address_validator.h> +#include <libaddressinput/supplier.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include <string> + +namespace i18n { +namespace addressinput { + +class LookupKey; +struct AddressData; + +// A ValidationTask object encapsulates the information necessary to perform +// validation of one particular address and call a callback when that has been +// done. Calling the Run() method will load required metadata, then perform +// validation, call the callback and delete the ValidationTask object itself. +class ValidationTask { + public: + ValidationTask(const AddressData& address, + bool allow_postal, + bool require_name, + const FieldProblemMap* filter, + FieldProblemMap* problems, + const AddressValidator::Callback& validated); + + ~ValidationTask(); + + // Calls supplier->Load(), with Validate() as callback. + void Run(Supplier* supplier) const; + + private: + friend class ValidationTaskTest; + + // Uses the address metadata of |hierarchy| to validate |address_|, writing + // problems found into |problems_|, then calls the |validated_| callback and + // deletes this ValidationTask object. + void Validate(bool success, + const LookupKey& lookup_key, + const Supplier::RuleHierarchy& hierarchy); + + // Checks all fields for UNEXPECTED_FIELD problems. + void CheckUnexpectedField(const std::string& region_code) const; + + // Checks all fields for MISSING_REQUIRED_FIELD problems. + void CheckMissingRequiredField(const std::string& region_code) const; + + // Checks the hierarchical fields for UNKNOWN_VALUE problems. + void CheckUnknownValue(const Supplier::RuleHierarchy& hierarchy) const; + + // Checks the POSTAL_CODE field for problems. + void CheckPostalCodeFormatAndValue( + const Supplier::RuleHierarchy& hierarchy) const; + + // Checks the STREET_ADDRESS field for USES_P_O_BOX problems. + void CheckUsesPoBox(const Supplier::RuleHierarchy& hierarchy) const; + + // Writes (|field|,|problem|) to |problems_|. + void ReportProblem(AddressField field, AddressProblem problem) const; + + // Writes (|field|,|problem|) to |problems_|, if this pair should be reported. + void ReportProblemMaybe(AddressField field, AddressProblem problem) const; + + // Returns whether (|field|,|problem|) should be reported. + bool ShouldReport(AddressField field, AddressProblem problem) const; + + const AddressData& address_; + const bool allow_postal_; + const bool require_name_; + const FieldProblemMap* filter_; + FieldProblemMap* const problems_; + const AddressValidator::Callback& validated_; + const scoped_ptr<const Supplier::Callback> supplied_; + const scoped_ptr<LookupKey> lookup_key_; + + DISALLOW_COPY_AND_ASSIGN(ValidationTask); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_VALIDATION_TASK_H_ diff --git a/chromium/third_party/libaddressinput/src/settings.gradle b/chromium/third_party/libaddressinput/src/settings.gradle new file mode 100644 index 00000000000..18077ac4d39 --- /dev/null +++ b/chromium/third_party/libaddressinput/src/settings.gradle @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * 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. + */ + +/* + * The Android address input widget is formed from the common (non-UI) classes + * and the Android specific classes. + */ +include 'android', 'common' |