All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.crankuptheamps.client.fields.BookmarkRangeField Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2024 60East Technologies Inc., All Rights Reserved.
//
// This computer software is owned by 60East Technologies Inc. and is
// protected by U.S. copyright laws and other laws and by international
// treaties.  This computer software is furnished by 60East Technologies
// Inc. pursuant to a written license agreement and may be used, copied,
// transmitted, and stored only in accordance with the terms of such
// license agreement and with the inclusion of the above copyright notice.
// This computer software or any other copies thereof may not be provided
// or otherwise made available to any other person.
//
// U.S. Government Restricted Rights.  This computer software: (a) was
// developed at private expense and is in all respects the proprietary
// information of 60East Technologies Inc.; (b) was not developed with
// government funds; (c) is a trade secret of 60East Technologies Inc.
// for all purposes of the Freedom of Information Act; and (d) is a
// commercial item and thus, pursuant to Section 12.212 of the Federal
// Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
// Government's use, duplication or disclosure of the computer software
// is subject to the restrictions set forth by 60East Technologies Inc..
//
////////////////////////////////////////////////////////////////////////////

package com.crankuptheamps.client.fields;

import java.lang.System;
import java.util.zip.CRC32;

/**
 * Field data for a {@link com.crankuptheamps.client.Message} consisting of the bookmark.
 * This is the AMPS Bookmark for the Message.
 */
public class BookmarkRangeField extends BookmarkField
{
    private int _capacity = 0;
    private BookmarkField _start = null;
    private BookmarkField _end = null;
    private int _open = -1;

    /**
     * Overrides the base classes' initial default size for the byte and
     * char conversion buffers used by this instance. Defaults to 128
     * which is sufficient for 2 bookmarks and associated chars.
     * 
     * @return Returns a default size of 128.
     */
    @Override
    protected int getConversionBufInitialSize() { return 128; }

    /**
     * Constructs a new BookmarkRangeField with the provided buffer,
     * position, and length.
     * @param buffer    The buffer containing the bookmark range.
     * @param position  The starting position of the bookmark range within the buffer
     * @param length    The length of the bookmark range.
     */
    protected BookmarkRangeField(byte[] buffer, int position, int length)
    {
        super(buffer, position, length);
        _capacity = length;
        parse();
    }

    /**
     * Constructs a new empty BookmarkRangeField.
     */
    public BookmarkRangeField()
    {
    }

    /**
     * Provides a way to make this object a duplicate of f if f
     * represents a valid bookmark range.
     */
    @Override
    public void copyFrom(Field f)
    {
        if (f == null || f.length == 0) {
            length = 0;
            position = 0;
            notValid();
            return;
        }
        if (buffer == null || f.length > _capacity)
        {
            buffer = new byte[f.length];
            _capacity = f.length;
        }
        // Start copy where range starts
        int start = 0;
        while (start < f.length && f.buffer[f.position+start] != (byte)'['
                && f.buffer[f.position+start] != (byte)'(')
        {
            ++start;
        }
        if (start < f.length) {
            length = f.length - start;
            System.arraycopy(f.buffer, f.position + start, buffer, 0, length);
            position = 0;
            parse();
        }
        else {
            length = 0;
            notValid();
        }
    }

    /**
     * Checks if the bookmark range is valid.
     * @return True if the bookmark range is valid, false otherwise.
     */
    public boolean isValid()
    {
        return _open >= 0;
    }

    /**
     * Gets the start bookmark of the range.
     * @return The start bookmark of the range.
     */
    public BookmarkField getStart()
    {
        return _start;
    }

    /**
     * Gets the end bookmark of the range.
     * @return The end bookmark of the range.
     */
    public BookmarkField getEnd()
    {
        return _end;
    }

    /**
     * Checks if the bookmark range starts inclusively (inclusive range).
     * @return True if the range starts inclusively, false otherwise.
     */
    public boolean isStartInclusive()
    {
        if (isValid()) {
            return this.buffer[_open] == (byte)'[';
        }
        return false;
    }

    /**
     * Checks if the bookmark range ends inclusively (inclusive range).
     * @return True if the end of the buffer is inclusive, otherwise false.
     */
    public boolean isEndInclusive()
    {
        if (isValid()) {
            return this.buffer[position+length-1] == (byte)']';
        }
        return false;
    }

    /**
     * Checks if the bookmark range starts exclusively (exclusive range).
     * @return True if the range starts exclusively, false otherwise.
     */
    public boolean isStartExclusive()
    {
        if (isValid()) {
            return this.buffer[_open] == (byte)'(';
        }
        return false;
    }

    /**
     * Checks if the bookmark range ends exclusively (exclusive range).
     * @return True if the range ends exclusively, false otherwise.
     */
    public boolean isEndExclusive()
    {
        if (isValid()) {
            return this.buffer[position+length-1] == (byte)')';
        }
        return false;
    }

    /**
     * Replaces the start bookmark of the range.
     * @param start_  The new start bookmark.
     */
    public void replaceStart(Field start_)
    {
        replaceStart(start_, true);
    }

    /**
     * Replaces the start bookmark of the range.
     * @param start_         The new start bookmark.
     * @param makeExclusive  Indicates whether the new start should be exclusive.
     */
    public void replaceStart(Field start_, boolean makeExclusive)
    {
        if (!isValid()) return;
        // Don't go backwards
        BookmarkField startBm = (BookmarkField)start_;
        if (startBm.getPublisherId() == _start.getPublisherId()
            && unsignedLongLessEqual(startBm.getSequenceNumber(), _start.getSequenceNumber()))
        {
            if (makeExclusive && startBm.getSequenceNumber()
                                 == _start.getSequenceNumber())
            {
                buffer[position+_open] = (byte)'(';
            }
            return;
        }
        int newLen = start_.length + _end.length + 3;
        // Check if new start fits in our buffer
        if (_capacity >= newLen) {
            if (makeExclusive) buffer[position+_open] = (byte)'(';
            if (_open > 0) {
                buffer[position] = buffer[position + _open];
                _open = 0;
            }
            if (_end.position < start_.length + 2) {
                // Move end toward the end to make room
                for (int pos = newLen-1, src = length-1; src > _start.length; --pos, --src) {
                    while (buffer[position+src] == (byte)' ') {
                        --src;
                    }
                    buffer[position+pos] = buffer[position+src];
                    if (buffer[position+src] == (byte)':') {
                        _end.set(buffer, start_.length+2, _end.length);
                        break;
                    }
                }
            }
            else if (_end.position > start_.length + 2) {
                // Move end toward the start
                for (int pos = start_.length+2, src = _end.position; src < length; ++pos, ++src) {
                    while (buffer[position+src] == (byte)' ') {
                        ++src;
                    }
                    buffer[position+pos] = buffer[position+src];
                    if (buffer[position+src] == (byte)']' || buffer[position+src] == (byte)')')
                    {
                        _end.set(buffer, position+start_.length+2, _end.length);
                        buffer[position+start_.length+1] = (byte)':';
                        break;
                    }
                }
            }
            length = newLen;
            System.arraycopy(start_.buffer, start_.position, buffer, position+1, start_.length);
            _start.set(buffer, position+1, start_.length);
        }
        else {
            _capacity = Math.max(4*BookmarkField.MAX_BOOKMARK_LENGTH + 6,
                                 start_.length + _end.length + 3);
            byte[] tmpBuffer = new byte[_capacity];
            if (makeExclusive) tmpBuffer[0] = (byte)'(';
            else tmpBuffer[0] = buffer[_open];
            _open = 0;
            System.arraycopy(start_.buffer, start_.position, tmpBuffer, 1, start_.length);
            _start.set(tmpBuffer, 1, start_.length);
            tmpBuffer[start_.length+1] = (byte)':';
            System.arraycopy(_end.buffer, _end.position, tmpBuffer, start_.length+2, _end.length);
            _end.set(tmpBuffer, start_.length+2, _end.length);
            tmpBuffer[newLen-1] = buffer[length-1];
            set(tmpBuffer, 0, newLen);
        }
    }

    /**
     * Provides a way to duplicate this object and retain its specific type
     * (and hashcode() implementation).
     * @return A new instance of BookmarkRangeField with the same data.
     */
    public BookmarkRangeField clone()
    {
        byte[] copy = null;
        if (buffer != null) {
            copy = new byte[length];
            System.arraycopy(buffer, position, copy, 0, length);
        }
        return new BookmarkRangeField(copy, 0, length);
    }

    /**
     * Override base class's copy() method appropriately, so we don't inadvertently mix
     * BookmarkRangeFields and Fields up -- they have different hashCode implementations.
     */
    @Override
    public BookmarkRangeField copy()
    {
        return clone();
    }

    /**
     * Computes the hash code for this BookmarkRangeField.
     *
     * @return The hash code value for this BookmarkRangeField.
     */
    @Override
    public int hashCode()
    {
        c.reset();
        c.update(buffer, position, length);
        return (int)c.getValue();
    }

    /**
     * Indicates whether some other object is "equal to" this one.
     *
     * @param object_ The object to compare with.
     * @return True if this BookmarkRangeField is the same as the object argument; false otherwise.
     */
    @Override
    public boolean equals(Object object_)
    {
        // Are we comparing to something valid
        if (object_ == null || !(object_ instanceof BookmarkRangeField)) {
            return false;
        }
        BookmarkRangeField rhs = (BookmarkRangeField)object_;
        // Is one an invalid range
        if ((_start == null && rhs._start != null)
            || (_start != null && rhs._start == null)) {
            return false;
        }
        // Compare logically equal
        return isStartInclusive() == rhs.isStartInclusive()
               && isEndInclusive() == rhs.isEndInclusive()
               && _start.equals(rhs._start) && _end.equals(rhs._end);
    }

    private void notValid()
    {
        _start = null;
        _end = null;
        _open = -1;
    }

    private void parse()
    {
        notValid();
        boolean foundClose = false;
        boolean foundSeparator = false;
        int pos = this.position;
        int end = this.position + length;
        while (pos < end) {
            switch (buffer[pos]) {
                // Range start
                case (byte)'(':
                case (byte)'[':
                {
                    // Can't be past the end or already started
                    if (foundClose || _open > -1) {
                        notValid();
                        return;
                    }
                    _open = pos;
                }
                break;
                // Valid characters for start or end portions of the range
                case (byte)'0':
                case (byte)'1':
                case (byte)'2':
                case (byte)'3':
                case (byte)'4':
                case (byte)'5':
                case (byte)'6':
                case (byte)'7':
                case (byte)'8':
                case (byte)'9':
                case (byte)'|':
                case (byte)',':
                case (byte)'T':
                case (byte)'Z':
                case (byte)'.':
                {
                    // Have to be between start and end
                    if (foundClose || _open < 0) {
                        notValid();
                        return;
                    }
                    else if (foundSeparator) {
                        if (_end == null) {
                            // Create the _end field, length will change
                            _end = new BookmarkField();
                            _end.set(this.buffer, pos, end - pos);
                        }
                    }
                    else if (_start == null) {
                        // Create the _start field, length will change
                        _start = new BookmarkField();
                        _start.set(this.buffer, pos, end - pos);
                    }
                }
                break;
                // Range separator
                case (byte)':':
                {
                    // Have to be between start and end and have started
                    // the _start bookmark, and not yet found separator.
                    if (foundClose || _open < 0 || _start == null || foundSeparator) {
                        notValid();
                        return;
                    }
                    foundSeparator = true;
                    // Check for setting the _start length
                    if (pos - _start.position < _start.length) {
                        _start.length = pos - _start.position;
                    }
                }
                break;
                // Close of range
                case (byte)')':
                case (byte)']':
                {
                    // Have have started _end
                    if (foundClose || _open < 0 || _end == null) {
                        notValid();
                        return;
                    }
                    foundClose = true;
                    length = pos - this.position + 1;
                    // Check for setting end length
                    if (pos - _end.position < _end.length) {
                        _end.length = pos - _end.position;
                    }
                }
                break;
                // Spaces are allowed, but skipped
                case (byte)' ':
                {
                    // Is this space at the end of _end?
                    if (_end != null && pos - _end.position < _end.length) {
                        _end.length = pos - _end.position;
                    }
                    // Is this the end of _start?
                    else if (_start != null && pos - _start.position < _start.length) {
                        _start.length = pos - _start.position;
                    }
                }
                break;
                default:
                {
                    notValid();
                    return;
                }
            } // end switch
            ++pos;
        } // end while
        if (_end == null || _start == null || !foundSeparator || !foundClose || _open < 0) {
            notValid();
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy