JSON-MultiValueOrdered

 view release on metacpan or  search on metacpan

lib/JSON/Tiny/Subclassable.pm  view on Meta::CPAN

			no strict 'refs';
			*{"$caller\::$func"} = subname "$class\::j" => sub {
				my $d = shift;
				return $class->new->encode($d) if ref $d eq 'ARRAY' || ref $d eq 'HASH';
				return $class->new->decode($d);
			};
			delete $opts->{'j'};
		}
	}
	
	__PACKAGE__->import('j');
	
	# Literal names
	my $FALSE = bless \(my $false = 0), 'JSON::Tiny::_Bool';
	my $TRUE  = bless \(my $true  = 1), 'JSON::Tiny::_Bool';
	
	# Escaped special character map (with u2028 and u2029)
	my %ESCAPE = (
		'"'     => '"',
		'\\'    => '\\',
		'/'     => '/',
		'b'     => "\x07",
		'f'     => "\x0C",
		'n'     => "\x0A",
		'r'     => "\x0D",
		't'     => "\x09",
		'u2028' => "\x{2028}",
		'u2029' => "\x{2029}"
	);
	my %REVERSE = map { $ESCAPE{$_} => "\\$_" } keys %ESCAPE;
	for (0x00 .. 0x1F, 0x7F) {
		my $k = pack 'C', $_;
		$REVERSE{$k} = sprintf '\u%.4X', $_ unless defined $REVERSE{$k};
	}
	
	# Unicode encoding detection
	my $UTF_PATTERNS = {
		'UTF-32BE' => qr/^\0\0\0[^\0]/,
		'UTF-16BE' => qr/^\0[^\0]\0[^\0]/,
		'UTF-32LE' => qr/^[^\0]\0\0\0/,
		'UTF-16LE' => qr/^[^\0]\0[^\0]\0/
	};
	
	my $WHITESPACE_RE = qr/[\x20\x09\x0a\x0d]*/;
	
	sub DOES {
		my ($proto, $role) = @_;
		return 1 if $role eq 'Mojo::JSON';
		return $proto->SUPER::DOES($role);
	}
	
	sub decode {
		my ($self, $bytes) = @_;
		
		# Cleanup
		$self->error(undef);
		
		# Missing input
		$self->error('Missing or empty input') and return undef unless $bytes; ## no critic (undef)
		
		# Remove BOM
		$bytes =~ s/^(?:\357\273\277|\377\376\0\0|\0\0\376\377|\376\377|\377\376)//g;
		
		# Wide characters
		$self->error('Wide character in input') and return undef ## no critic (undef)
			unless utf8::downgrade($bytes, 1);
		
		# Detect and decode Unicode
		my $encoding = 'UTF-8';
		$bytes =~ $UTF_PATTERNS->{$_} and $encoding = $_ for keys %$UTF_PATTERNS;
		
		my $d_res = eval { $bytes = Encode::decode($encoding, $bytes, 1); 1 };
		$bytes = undef unless $d_res;
		
		# Object or array
		my $res = eval {
			local $_ = $bytes;
			
			# Leading whitespace
			m/\G$WHITESPACE_RE/gc;
			
			# Array
			my $ref;
			if (m/\G\[/gc) { $ref = $self->_decode_array() }
			
			# Object
			elsif (m/\G\{/gc) { $ref = $self->_decode_object() }
			
			# Unexpected
			else { $self->_exception('Expected array or object') }
			
			# Leftover data
			unless (m/\G$WHITESPACE_RE\z/gc) {
				my $got = ref $ref eq 'ARRAY' ? 'array' : 'object';
				$self->_exception("Unexpected data after $got");
			}
			
			$ref;
		};
		
		# Exception
		if (!$res && (my $e = $@)) {
			chomp $e;
			$self->error($e);
		}
		
		return $res;
	}
	
	sub encode {
		my ($self, $ref) = @_;
		
		my $eof = '';
		if ($self->pretty) {
			$self->{_indent} = '';
			$eof .= "\n";
		}
		
		return Encode::encode 'UTF-8', $self->_encode_values($ref).$eof;
	}
	



( run in 2.612 seconds using v1.01-cache-2.11-cpan-ceb78f64989 )